<?php
if(!class_exists('XSLTProcessor')) die(__FILE__.': Please enable XSLTProcessor in your php.ini');
/**
* Copyright (C) 2010 Kai Dorschner
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @author Kai Dorschner <the-hide@address.com>
* @copyright Copyright 2010, Kai Dorschner
* @license http://www.gnu.org/licenses/gpl.html GPLv3
* @package mocovi
*/
/**
* Require Singleton.
*/
class_exists('Singleton') or require $GLOBALS['library'].'autoload/Singleton.php';
class_exists('MvcException') or require $GLOBALS['library'].'autoload/MvcException.php';
/**
* View is appropriated for the appearance at the user's browser
*
* Last but not least here we have the "third main pillar" of this project,
* although it's not less valuable than the others.
* This little mighty class has the ability to offer the user a broad spectrum
* from simple templates to complex export interfaces, transcripting or
* undreamed-of possibilities supported by the new forward-looking
* XSLT technology.
*
* @package mocovi
*/
class View extends Singleton
{
/**
* Contains the path to the XSL file
*
* @access protected
*/
protected $xslpath;
/**
* Contains the XSLTProcessor object
*
* @access protected
*/
protected $xsl;
protected $defaultRenderer = 'xmlRenderer';
/**
* Tells the class which output format should be mimed.
*
* Media Mapping only takes place if the URL filename differs from the xslt templates.
*
* Usage:
* 'possible file name in the URL' => 'file name of the xslt-supported media output'
*
*/
protected static $mediaMapping = array
( 'xhtml' => 'html'
, 'htm' => 'html'
, 'php' => 'html'
, 'php3' => 'html'
, 'php4' => 'html'
, 'php5' => 'html'
, 'asp' => 'html'
, 'aspx' => 'html'
, 'jsp' => 'html'
, 'text' => 'txt'
, 'plain' => 'txt'
, 'raw' => 'xml'
);
/**
* Constructor sets the path to the XSL file or throws an error on fault. (Singleton!)
*
* @access public
* @param string $xslpath Contains the path to the XSL file
* @return void;
*/
protected function __construct($xslpath)
{
if(!is_file($xslpath))
throw new MvcException('Path to the xsl file could not be found.'); // better use / create a 404 Exception?
$this->xslpath = $xslpath;
}
public static function mediaMapping(&$key)
{
if(array_key_exists($key, self::$mediaMapping))
$key = self::$mediaMapping[$key];
return $key;
}
/**
* Renders the source XML against the XSL file
*
* This method renders the XSL against the source XML.
*
* @access public
* @param object $xml Contains a reference of the source XML
* @return string XML Document
* @see $xsl
* @todo Caching doesn't work properly
*/
public function transform(DomDocument $xml)
{
$lastModifiedTime = date("r", strtotime($GLOBALS['filesystem']->getLastModified($GLOBALS['page'])));
$etag = md5($GLOBALS['page'].$GLOBALS['language'].$GLOBALS['theme']);
if($this->isCached())
{
$GLOBALS['header']->status(304);
$GLOBALS['header']->sendHeader();
exit(0); // exit without errors.
}
//$GLOBALS['header']->lastModified($lastModifiedTime);
//$GLOBALS['header']->etag($etag);
$this->createXSLTProcessor($this->xslpath);
return $this->render($this->xsl->transformToXML($xml));
}
protected function isCached()
{
return ($GLOBALS['caching'] && isset($_SERVER['HTTP_IF_MODIFIED_SINCE'], $_SERVER['HTTP_IF_NONE_MATCH']) && trim($_SERVER['HTTP_IF_NONE_MATCH']) == $etag && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $lastModifiedTime);
}
protected function render($string)
{
$class = $GLOBALS['media'].'Renderer';
if(!is_file($GLOBALS['renderers'].$class.'.php'))
$class = $this->defaultRenderer;
class_exists($class) or require $GLOBALS['renderers'].$class.'.php';
$renderer = new $class();
return $renderer->render($string);
}
protected function createXSLTProcessor($xslpath)
{
if(!is_object($this->xsl))
{
$xsl_dom = new DOMDocument();
$xsl_dom->preserveWhiteSpace = false;
$xsl_dom->formatOutput = false;
$xsl_dom->load($xslpath);
$this->xsl = new XSLTProcessor();
$this->xsl->registerPHPFunctions(); // Allows the XSL to access custom PHP functions.
$this->xsl->importStyleSheet($xsl_dom);
}
}
}