Login   Register  
PHP Classes
elePHPant
Icontem

File: x64Template.php

Recommend this page to a friend!
Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  Classes of Full name  >  x64Template Engine  >  x64Template.php  >  Download  
File: x64Template.php
Role: Class source
Content type: text/plain
Description: Main class
Class: x64Template Engine
Template engine extensible with plug-in classes
Author: By
Last change: updated licence/copyright information. Big changes will come soon.
Date: 7 years ago
Size: 16,369 bytes
 

Contents

Class file image Download
<?php

/**
 * x64Template
 * @author Atomo64 (www.atomo64.tk)
 * @package x64Template
 * @version 0.1.6
 * @copyright Raphael Geissert 2006-2007
 *
 * Based on code by Brian Lozier (bTemplate: Copyright 2002 Brian Lozier)
 *
 */
class x64Template
{
	/**
	 * When is set to true it makes the class clean the loops and cloops data
	 * The value of this variable can be set while creating the object
	 *
	 * @var bool
	 * @access public
	 */
	var $reset = TRUE;

	/**
	 * The beginning of the normal tags
	 *
	 * @var string
	 * @access public
	 */
	var $ldelim = '{';
	/**
	 * The end of the normal tags
	 *
	 * @var string
	 * @access public
	 */
	var $rdelim = '}';

	/**
	 * The beginning of the opening tag for blocks
	 *
	 * @var string
	 * @access public
	 */
	var $BAldelim = '{';
	/**
	 * The end of the opening tag for blocks
	 *
	 * @var string
	 * @access public
	 */
	var $BArdelim = '}';
	/**
	 * The beginning of the closing tag for blocks
	 *
	 * @var string
	 * @access public
	 */
	var $EAldelim = '{/';
	/**
	 * The end of the closing tag for blocks
	 *
	 * @var string
	 * @access public
	 */
	var $EArdelim = '}';

	/**
	 * Array containing the data for the tag: tags
	 *
	 * @var array
	 * @access private
	 */
	var $_scalars = array();
	/**
	 * Array containing the data for the loop: tags
	 *
	 * @var array
	 * @access private
	 */
	var $_arrays = array();
	/**
	 * Array containing the information about which array tags
	 *  should be enabled for if: tags and which elements should be used
	 *  since trying to find ifs for each array element and
	 *  for each array entry would take a lot of time.
	 *
	 * @var array
	 * @access private
	 */
	var $_arrays_ifs = array();
	/**
	 * Array containing the data for the cloop: tags
	 *
	 * @var array
	 * @access private
	 */
	var $_carrays = array();
	/**
	 * Array containing the data for the if: tags
	 *
	 * @var array
	 * @access private
	 */
	var $_ifs = array();
	/**
	 * Array containing the information of the plugins to be loaded
	 *
	 * @var array
	 * @access private
	 * @see $this->add_plugin
	 */
	var $_plugins = array();

	/**
	 * Object constructor, set $reset to reset the arrays after processing
	 *
	 * @access public
	 * @param bool $reset
	 * @return x64Template
	 */
	function x64Template($reset = TRUE)
	{
		$this->reset = $reset;
	}

	/**
	 * Set a tag with a value, $var can be a string or an array
	 * Set $if to true if you want to be able to use that tag with if: conditions
	 *
	 * @param string $tag
	 * @param mixed $var
	 * @param bool $if
	 */
	function set($tag, $var, $if = NULL)
	{
		if(is_array($var))
		{
			$this->_arrays[$tag] = $var;
			if($if!==null)
			{
				if(!is_array($if))
				{
					$result = $var ? TRUE : FALSE;
					$this->_ifs[] = $tag;
					$this->_scalars[$tag] = $result;
				}
				else
				{
					$result = $var ? TRUE : FALSE;
					$this->_ifs[] = $tag;
					$this->_scalars[$tag] = $result;
					$this->_arrays_ifs[$tag]=$if;
				}
			}
		}
		else
		{
			$this->_scalars[$tag] = $var;
			if($if) $this->_ifs[] = $tag;
		}
	}

	/**
	 * Sets a case loop
	 *
	 * @access public
	 * @param string $tag The tag name
	 * @param array $array The array containing the data
	 * @param array $cases The array telling about the cases that it should check for
	 */
	function set_cloop($tag, $array, $cases)
	{
		$this->_carrays[$tag] = array(
		'array' => $array,
		'cases' => $cases);
	}

	/**
	 * Reset the template variables
	 *
	 * @access public
	 * @param bool $scalars If the scalars data should be cleaned
	 * @param bool $arrays If the arrays data should be cleaned
	 * @param bool $arrays_ifs If the arrays_ifs data should be cleaned
	 * @param bool $carrays If the case arrays data should be cleaned
	 * @param bool $ifs If the ifs data should be cleaned
	 * @param bool $plugins If the plugins data should be cleaned
	 */
	function reset($scalars=false, $arrays=false, $arrays_ifs=false, $carrays=false, $ifs=false,$plugins=false)
	{
		if($scalars)    $this->_scalars    = array();
		if($arrays)     $this->_arrays     = array();
		if($arrays_ifs) $this->_arrays_ifs = array();
		if($carrays)    $this->_carrays    = array();
		if($ifs)        $this->_ifs        = array();
		if($plugins)    $this->_plugins    = array();
	}

	/**
	 * Formats the tags & returns a two-element array,
	 * the opening and closing tags
	 *
	 * @access public
	 * @param string $tag The tag name
	 * @param string $directive The directive name
	 * @return array
	 */
	function get_tags($tag, $directive)
	{
		$tags['b'] = $this->BAldelim . $directive . ':' . $tag . $this->BArdelim;
		$tags['e'] = $this->EAldelim . $directive . ':' . $tag . $this->EArdelim;
		return $tags;
	}

	/**
	 * Formats a simple tag
	 *
	 * @access public
	 * @param string $tag The tag name
	 * @param string $directive The tag directive
	 * @return string The formated tag
	 */
	function get_tag($tag,$directive='tag')
	{
		return $this->ldelim . $directive . ':' . $tag . $this->rdelim;
	}

	/**
	 * Extracts a portion of a template( or a string) according to the
	 *  opening ($tags['b']) and closing ($tags['e']) tags
	 *
	 * @param array $tags The opening and closing tags/delimeters
	 * @param string $contents The content from where it is going to extract
	 * @return string The extracted content
	 */
	function get_statement($tags, $contents)
	{
		// Locate the statement
		$tag_length = strlen($tags['b']);
		$fpos = $tags['b']===null? 0 : strpos($contents, $tags['b']);
		$lpos = $tags['e']===null? strlen($contents) : strpos($contents, $tags['e']);

		if($fpos===false||$lpos===false)
		return false;

		$fpos += $tag_length;
		$length = $lpos - $fpos;

		// Extract & return the statement
		return substr($contents, $fpos, $length);
	}

	/**
	 * Parse the template with the variables
	 *
	 * @access public
	 * @param string $contents The template
	 * @return string The parsed template
	 */
	function parse($contents)
	{
		/**
		 * Process the ifs (if any)
		 */
		foreach($this->_ifs as $value)
		{
			$contents = $this->_parse_if($value, $contents);
		}

		/**
		 * Process the scalars (if any)
		*/
		foreach($this->_scalars as $key => $value)
		{
			$contents = str_replace($this->get_tag($key), $value, $contents);
		}

		/**
		 * Process the arrays (if any)
		 */
		foreach($this->_arrays as $key => $array)
		{
			$contents = $this->_parse_loop($key, $array, $contents);
		}

		/**
		 * Process the case arrays (if any)
		 */
		foreach($this->_carrays as $key => $array)
		{
			$contents = $this->_parse_cloop($key, $array, $contents);
		}

		$plugins_count=count($this->_plugins);
		/**
		 * Process the plugins (if any)
		 */
		for ($n=0;$n<$plugins_count;$n++)
		{
			if($this->_plugins[$n]['object']===null)
			$obj=new $this->_plugins[$n]['function']();
			else
			$obj=&$this->_plugins[$n]['object'];

			//
			//Now we check what protocol version the plugin was designed for
			//
			switch ($obj->version('protocol'))
			{
				case "1.0":
					{
						//
						//Now we give the object itself to the function, so it can access the current settings
						//
						$contents=$obj->parse($contents,$this);
					}break;
			}
		}

		/**
		 * Reset the data according to the settings
		 */
		if($this->reset) $this->reset(FALSE, TRUE, TRUE, TRUE);

		return $contents;
	}

	/**
	 * Parses an if statement
	 *
	 * @access private
	 * @param string $tag The tag name
	 * @param string $contents The current as-processed template
	 * @param string $replace If the function should consider as $replace without checking the real value
	 * @return string The parsed template
	 */
	function _parse_if($tag, $contents, $replace=null)
	{
		//
		// Get the tags
		//
		$t = $this->get_tags($tag, 'if');

		//
		//We loop this so we can process all the ifs for this tag
		//
		while (($entire_statement = $this->get_statement($t, $contents))!==false)
		{

			// Get the else tag
			$tags['b'] = NULL;
			$tags['e'] = $this->get_tag($tag, 'else');

			// See if there's an else statement
			if(($else = strpos($entire_statement, $tags['e'])))
			{
				// Get the if statement
				$if = $this->get_statement($tags, $entire_statement);

				// Get the else statement
				$else = substr($entire_statement, $else + strlen($tags['e']));
			}
			else
			{
				$else = NULL;
				$if = $entire_statement;
			}

			//
			//If the function wasn't called with a value for $replace we check the _scalars array
			//
			if($replace===null||!is_bool($replace))
			$replace=!empty($this->_scalars[$tag])?true:false;

			//
			//If the condition is valid then we use the 'if' (first) part, if not, then we use 'else'
			//
			$replace=($replace) ? $if :  $else;

			//
			// Parse the template
			//
			$contents = str_replace($t['b'] . $entire_statement . $t['e'], $replace, $contents);
		}

		//
		//Return the template
		//
		return $contents;
	}

	/**
	 * Parses a loop
	 *
	 * @access private
	 * @param string $tag Tag name
	 * @param array $array The array containing the loop data
	 * @param string $contents The current as-processed template
	 * @return string The parsed template
	 */
	function _parse_loop($tag, $array, $contents)
	{
		// Get the tags & loop
		$t = $this->get_tags($tag, 'loop');

		while (($loop = $this->get_statement($t, $contents))!==false)
		{
			$parsed = NULL;
			$if_key_exists=isset($this->_arrays_ifs[$tag]);

			// Process the loop
			foreach($array as $key => $value)
			{
				/**
				 * We create a copy of the loop so we can keep the original loop
				 *  but work on this one
				 */
				$i = $loop;

				if($if_key_exists&&isset($this->_arrays_ifs[$tag][$key]))
				$i=$this->_parse_if($tag . '.' . $key,$i,!empty($value)?true:false);
				/**
				 * array(1=>array('key_name'=>'value','some_key'=>'value'))
				 * {tag:tag_name[].key_name},{tag:tag_name[].some_key}
				 * {tag:tag_name[].key_name[]},{tag:tag_name[].some_key[].some_subkey}
				 */
				if(is_numeric($key) && is_array($value))
				{
					foreach($value as $key2 => $value2)
					{
						if($if_key_exists&&isset($this->_arrays_ifs[$tag][$key2]))
						$i=$this->_parse_if($tag . '[].' . $key2,$i,!empty($value2)?true:false);
						if(!is_array($value2))
						{
							// Replace associative array tags
							$i = str_replace($this->get_tag($tag . '[].' . $key2), $value2, $i);
						}
						else
						{
							// Check to see if it's a nested loop
							$i = $this->_parse_loop($tag . '[].' . $key2, $value2, $i);
						}
					}
				}
				/**
				 * array('tsgsgs'=>'sgsgdgg')
				 * {tag:tag_name.key_name}
				 */
				elseif(is_string($key) && !is_array($value))
				{
					$i = str_replace($this->get_tag($tag . '.' . $key), $value, $i);
				}
				/**
				 * array(1=>'fff')
				 * {tag:tag_name[]}
				 */
				elseif(!is_array($value))
				{
					$i = str_replace($this->get_tag($tag . '[]'), $value, $i);
				}

				// Add the parsed iteration
				if(isset($i)) $parsed .= rtrim($i);
			}

			//
			// Parse the template
			//
			$contents=str_replace($t['b'] . $loop . $t['e'], $parsed, $contents);
		}

		//
		//Return the template
		//
		return $contents;
	}

	/**
	 * Parse a case loop
	 *
	 * @access private
	 * @param string $tag The tag name that is going to be parsed
	 * @param array $array Array with the loop elements
	 * @param string $contents The current as-processed template
	 * @return string The parsed template
	 */
	function _parse_cloop($tag, $array, $contents)
	{
		// Get the tags & loop
		$t = $this->get_tags($tag, 'cloop');
		while (($loop = $this->get_statement($t, $contents))!==false)
		{
			// Set up the cases
			$array['cases'][] = 'default';
			$case_content = array();
			$parsed = NULL;

			// Get the case strings
			foreach($array['cases'] as $case)
			{
				$ctags[$case] = $this->get_tags($case, 'case');
				$case_content[$case] = $this->get_statement($ctags[$case], $loop);
			}

			// Process the loop
			foreach($array['array'] as $key => $value)
			{
				if(is_numeric($key) && is_array($value))
				{
					// Set up the cases
					if(isset($value['case'])) $current_case = $value['case'];
					else $current_case = 'default';
					unset($value['case']);
					$i = $case_content[$current_case];

					// Loop through each value
					foreach($value as $key2 => $value2) {
						$i = str_replace($this->get_tag($tag . '[].' . $key2), $value2, $i);
					}
				}

				// Add the parsed iteration
				$parsed .= rtrim($i);
			}

			// Parse & return the final loop
			$contents=str_replace($t['b'] . $loop . $t['e'], $parsed, $contents);
		}
		return $contents;
	}

	/**
	 * Parses the file $file_name as a template
	 *
	 * @access public
	 * @param string $file The template file name
	 * @return string The processed template
	 */
	function fetch($file)
	{
		// Open the file
		$fp = fopen($file, 'rb');
		if(!$fp) return FALSE;

		// Read the file
		$contents = fread($fp, filesize($file));

		// Close the file
		fclose($fp);

		// Parse and return the contents
		return $this->parse($contents);
	}

	/**
	 * Works the same way as set() excepting that if the tag already exists
	 *  it doesn't replaces it, it appends the new value (if it is an string)
	 *  or it merges the content (if it is an array).
	 * Please note that this function will not make any change
	 *  to the array_ifs data, to update that information,
	 *  set() has to be used instead
	 *
	 * @param string $tag
	 * @param mixed $var
	 * @param bool $if
	 */
	function append($tag, $var, $if = NULL)
	{
		if(is_array($var))
		{
			if(!isset($this->_arrays[$tag]))
			$this->_arrays[$tag]= $var;
			else
			$this->_arrays[$tag]=array_merge($this->_arrays[$tag],$var);
			if($if)
			{
				$result = $var ? TRUE : FALSE;
				$this->_ifs[] = $tag;
				$this->_scalars[$tag] = $result;
			}
		}
		else
		{
			if(!isset($this->_scalars[$tag]))
			$this->_scalars[$tag] = $var;
			else
			$this->_scalars[$tag] .= $var;
			if($if) $this->_ifs[] = $tag;
		}
	}

	/**
	 * Adds a plugin to be called when a template is being parsed
	 * The $plugin_name is the name of the class which is the plugin
	 *
	 * The $setup var may contain any type of data, because it is pased directly to the $plugin_name::setup() function of the plugin class
	 * The arguments passed to the $plugin_name::parse() function will be $contents and the object itself ($this), in that order, and the function will only return the parsed template.
	 *
	 * The $plugin_name::setup() function may return an array with some settings
	 *
	 * Notes:
	 * 	The plugin class must have the next functions, which are going to be called by the template engine:
	 * 		-$plugin_name::setup() This function can be used to setup either the template engine when calling the plugin or to setup the plugin itself, in the last case, the $setup param can be used to give some settings to the plugin
	 * 		-$plugin_name::parse() This function is called when the class 'executes' the plugin
	 * 		-$plugin_name::version() This function must have one argument, which specifies the version of what is being requested: 'protocol' is the current plugins protocol, for the current version is 1.0; 'plugin' is the plugin version, it can be useful to debug
	 *
	 * @access public
	 * @param string $plugin_name The name of the function or class to be called
	 * @param mixed $setup Special settings that can be given to the plugin
	 */
	function add_plugin($plugin_name,$setup=null)
	{
		$n=count($this->_plugins);
		$this->_plugins[$n]['function']=$plugin_name;
		$this->_plugins[$n]['setup']=$setup;

		$obj=new $plugin_name();
		$this->_plugins[$n]=array_merge($this->_plugins[$n],$obj->setup($setup));

		if (!isset($this->_plugins[$n]['refresh_object'])||$this->_plugins[$n]['refresh_object']===false)
		$this->_plugins[$n]['object']=&$obj;
		else
		$this->_plugins[$n]['object']=null;
	}
}
?>