%PDF- %PDF-
Direktori : /home1/lightco1/public_html/lightingrepublic.com.au/libraries/koowa/template/ |
Current File : //home1/lightco1/public_html/lightingrepublic.com.au/libraries/koowa/template/abstract.php |
<?php /** * @version $Id$ * @package Koowa_Template * @copyright Copyright (C) 2007 - 2012 Johan Janssens. All rights reserved. * @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> * @link http://www.nooku.org */ /** * Abstract Template class * * @author Johan Janssens <johan@nooku.org> * @package Koowa_Template */ abstract class KTemplateAbstract extends KObject implements KTemplateInterface { /** * The template path * * @var string */ protected $_path; /** * The template data * * @var array */ protected $_data; /** * The template contents * * @var string */ protected $_content; /** * The set of template filters for templates * * @var array */ protected $_filters; /** * View object or identifier * * @var string|object */ protected $_view; /** * Counter * * Used to track recursive calls during template evaluation * * @var int * @see _evaluate() */ private $__counter; /** * Constructor * * Prevent creating instances of this class by making the constructor private * * @param KConfig $config An optional KConfig object with configuration options */ public function __construct(KConfig $config) { parent::__construct($config); // Set the view identifier $this->_view = $config->view; // Set the template data $this->_data = $config->data; // Mixin a command chain $this->mixin(new KMixinCommandchain($config->append(array('mixer' => $this)))); //Attach the filters $this->addFilter($config->filters); //Reset the counter $this->__counter = 0; } /** * Initializes the options for the object * * Called from {@link __construct()} as a first step of object instantiation. * * @param KConfig $config An optional KConfig object with configuration options. * @return void */ protected function _initialize(KConfig $config) { $config->append(array( 'data' => array(), 'filters' => array(), 'view' => null, 'command_chain' => new KCommandChain(), 'dispatch_events' => false, 'enable_callbacks' => false, )); parent::_initialize($config); } /** * Get the template path * * @return string */ public function getPath() { return $this->_path; } /** * Get the template data * * @return mixed */ public function getData() { return $this->_data; } /** * Get the template content * * @return string */ public function getContent() { return $this->_content; } /** * Get the view object attached to the template * * @throws \UnexpectedValueException If the views doesn't implement the KViewInterface * @return KViewInterface */ public function getView() { if(!$this->_view instanceof KViewAbstract) { //Make sure we have a view identifier if(!($this->_view instanceof KServiceIdentifier)) { $this->setView($this->_view); } $this->_view = $this->getService($this->_view); //Make sure the view implements KViewAbstract if(!$this->_view instanceof KViewAbstract) { throw new UnexpectedValueException( 'View: '.get_class($this->_view).' does not implement KViewInterface' ); } } return $this->_view; } /** * Method to set a view object attached to the controller * * @param mixed $view An object that implements KObjectServiceable, KServiceIdentifier object * or valid identifier string * @throws KTemplateException If the identifier is not a view identifier * @return KTemplateAbstract */ public function setView($view) { if(!($view instanceof KViewAbstract)) { if(empty($view) || (is_string($view) && strpos($view, '.') === false)) { $identifier = clone $this->getIdentifier(); $identifier->path = array('view'); if ($view) { $identifier->path[] = $view; } $identifier->name = KRequest::format() ? KRequest::format() : 'html'; } else $identifier = $this->getIdentifier($view); if($identifier->path[0] != 'view') { throw new KTemplateException('Identifier: '.$identifier.' is not a view identifier'); } $view = $identifier; } $this->_view = $view; return $this; } /** * Load a template by identifier * * This functions only accepts full identifiers of the format * - com:[//application/]component.view.[.path].name * * @param string The template identifier * @param array An associative array of data to be extracted in local template scope * @throws \InvalidArgumentException If the template could not be found * @return KTemplateAbstract */ public function loadIdentifier($template, $data = array()) { //Identify the template $identifier = $this->getIdentifier($template); // Find the template $file = $this->findFile(dirname($identifier->filepath).'/'.$identifier->name.'.php'); if ($file === false) { throw new InvalidArgumentException('Template "' . $identifier->name . '" not found'); } // Load the file $this->loadFile($file, $data); return $this; } /** * Load a template by path * * @param string $file The template path * @param array $data An associative array of data to be extracted in local template scope * @return KTemplateAbstract */ public function loadFile($path, $data = array()) { //Store the original path $this->_path = $path; //Get the file contents $contents = file_get_contents($path); //Load the contents $this->loadString($contents, $data); return $this; } /** * Load a template from a string * * @param string $string The template contents * @param array $data An associative array of data to be extracted in local template scope * @return KTemplateAbstract */ public function loadString($string, $data = array()) { $this->_content = $string; // Merge the data $this->_data = array_merge((array) $this->_data, $data); // Process inline templates if($this->__counter > 0) { $this->render(); } return $this; } /** * Render the template * * @return string The rendered data */ public function render() { //Parse the template $this->_parse($this->_content); //Evaluate the template $this->_evaluate($this->_content); //Process the template only at the end of the render cycle. if($this->__counter == 0) { $this->_process($this->_content); } return $this->_content; } /** * Check if the template is in a render cycle * * @return boolean Return TRUE if the template is being rendered */ public function isRendering() { return (bool) $this->_counter; } /** * Check if a filter exists * * @param string The name of the filter * @return boolean TRUE if the filter exists, FALSE otherwise */ public function hasFilter($filter) { return isset($this->_filters[$filter]); } /** * Adds one or more filters for template transformation * * @param array Array of one or more behaviors to add. * @return KTemplate */ public function addFilter($filters) { $filters = (array) KConfig::unbox($filters); foreach($filters as $filter) { if(!($filter instanceof KTemplateFilterInterface)) { $filter = $this->getFilter($filter); } //Enqueue the filter in the command chain $this->getCommandChain()->enqueue($filter); //Store the filter $this->_filters[$filter->getIdentifier()->name] = $filter; } return $this; } /** * Get a filter by identifier * * @return KTemplateFilterInterface */ public function getFilter($filter) { //Create the complete identifier if a partial identifier was passed if(is_string($filter) && strpos($filter, '.') === false ) { $identifier = clone $this->getIdentifier(); $identifier->path = array('template', 'filter'); $identifier->name = $filter; } else $identifier = KService::getIdentifier($filter); if (!isset($this->_filters[$identifier->name])) { $filter = KService::get($identifier); if(!($filter instanceof KTemplateFilterInterface)) { throw new KTemplateException("Template filter $identifier does not implement KTemplateFilterInterface"); } } else $filter = $this->_filters[$identifier->name]; return $filter; } /** * Get a template helper * * @param mixed KServiceIdentifierInterface * @return KTemplateHelperInterface */ public function getHelper($helper) { //Create the complete identifier if a partial identifier was passed if(is_string($helper) && strpos($helper, '.') === false ) { $identifier = clone $this->getIdentifier(); $identifier->path = array('template','helper'); $identifier->name = $helper; } else $identifier = $this->getIdentifier($helper); //Create the template helper $helper = $this->getService($identifier, array('template' => $this)); //Check the helper interface if(!($helper instanceof KTemplateHelperInterface)) { throw new KTemplateHelperException("Template helper $identifier does not implement KTemplateHelperInterface"); } return $helper; } /** * Load a template helper * * This functions accepts a partial identifier, in the form of helper.function. If a partial * identifier is passed a full identifier will be created using the template identifier. * * @param string Name of the helper, dot separated including the helper function to call * @param mixed Parameters to be passed to the helper * @return string Helper output */ public function renderHelper($identifier, $params = array()) { //Get the function to call based on the $identifier $parts = explode('.', $identifier); $function = array_pop($parts); $helper = $this->getHelper(implode('.', $parts)); //Call the helper function if (!is_callable( array( $helper, $function ) )) { throw new KTemplateHelperException( get_class($helper).'::'.$function.' not supported.' ); } return $helper->$function($params); } /** * Searches for the file * * @param string The file path to look for. * @return mixed The full path and file name for the target file, or FALSE * if the file is not found */ public function findFile($file) { $result = false; $path = dirname($file); // is the path based on a stream? if (strpos($path, '://') === false) { // not a stream, so do a realpath() to avoid directory // traversal attempts on the local file system. $path = realpath($path); // needed for substr() later $file = realpath($file); } // The substr() check added to make sure that the realpath() // results in a directory registered so that non-registered directores // are not accessible via directory traversal attempts. if (file_exists($file) && substr($file, 0, strlen($path)) == $path) { $result = $file; } // could not find the file in the set of paths return $result; } /** * Returns a directory path for temporary files * * @return string Folder path */ protected function _getTemporaryDirectory() { return sys_get_temp_dir(); } /** * Creates a file with a unique file name * * @param string|null $directory Uses the result of _getTemporaryDirectory() by default * @return string File path */ protected function _getTemporaryFile($directory = null) { if ($directory === null) { $directory = $this->_getTemporaryDirectory(); } $name = str_replace('.', '', uniqid('tmpl', true)); $path = $directory.'/'.$name; touch($path); return $path; } /** * Parse and compile the template to PHP code * * This function passes the template through read filter chain and returns the result. * * @return string The parsed data */ protected function _parse(&$content) { $context = $this->getCommandContext(); $context->data = $content; $this->getCommandChain()->run(KTemplateFilter::MODE_READ, $context); $content = $context->data; } /** * Evaluate the template using a simple sandbox * * This function writes the template to a temporary file and then includes it. * * @return string The evaluated data * @see tempnam() */ protected function _evaluate(&$content) { //Increase counter $this->__counter++; //Create temporary file $tempfile = $this->_getTemporaryFile(); //Write the template to the file $handle = fopen($tempfile, "w+"); fwrite($handle, $content); fclose($handle); //Include the file extract($this->_data, EXTR_SKIP); ob_start(); include $tempfile; $content = ob_get_clean(); unlink($tempfile); //Reduce counter $this->__counter--;; } /** * Process the template * * This function passes the template through write filter chain and returns the result. * * @return string The rendered data */ protected function _process(&$content) { $context = $this->getCommandContext(); $context->data = $content; $this->getCommandChain()->run(KTemplateFilter::MODE_WRITE, $context); $content = $context->data; } /** * Returns the template contents * * @return string * @see getContents() */ public function __toString() { return $this->getContent(); } }