Location: PHPKode > scripts > ubtemplate > ubtemplate/template.php
<?php
/**
 * Representa un bloque a parsear
 *
 */
class ubTemplateBlock
{
	const EXP_VAR_INI = "{{";
	const EXP_VAR_END = "}}";
	const EXP_DEPEND_INI = "{<{";
	const EXP_DEPEND_END = "}>}";
	const EXP_MUL_DEPEND_INI = "{<<{";
	const EXP_MUL_DEPEND_END = "}>>}";
	
	
	private $content;
	
	private $name;
	
	private $blocks;
	
	private $mul_blocks;
	
	private $ignore = array();
	
	public function __construct($name,$content)
	{
		$this->content = $content;
		$this->name = $name;
		$this->load();
	}
	
	private function load()
	{
		preg_match_all('~'.self::EXP_DEPEND_INI.'(\w+)'.self::EXP_DEPEND_END.'~mi',$this->content,$blocks);
		$this->blocks = $blocks[1];
		preg_match_all('~'.self::EXP_MUL_DEPEND_INI.'(\w+)'.self::EXP_MUL_DEPEND_END.'~mi',$this->content,$mul_blocks);
		$this->mul_blocks = $mul_blocks[1];
	}
	
	public function add_ignore($block)
	{
		if(is_array($block))
		{
			foreach ($block as $value) {
				$this->ignore[$value] = true;
			}
		}
		else
			$this->ignore[$block] = true;
	}
	
	public function del_ignore($block)
	{
		if(is_array($block))
		{
			foreach ($block as $value) {
				unset($this->ignore[$value]);
			}
		}
		else
			unset($this->ignore[$block]);
	}
	
	public function get_mul_blocks()
	{
		return $this->mul_blocks;
	}
	
	public function set_mul_blocks($value)
	{
		$this->mul_blocks = $value;
	}
	
	public function get_blocks()
	{
		return $this->blocks;
	}
	
	public function blocks_to_include()
	{
		return array_diff($this->blocks,$this->ignore);
	}
	
	public function set_blocks($value)
	{
		$this->blocks = $value;
	}
	
	public function get_name()
	{
		return $this->name;
	}
	
	public function set_name($value)
	{
		$this->name = $value;
	}
	
	public function get_content()
	{
		return $this->content;
	}
	
	public function set_content($value)
	{
		$this->content = $value;
	}
	
	public function parser($vars=array(),$vars_block=array(),$vars_mul_block=array())
	{
		$vars = (is_array($vars))?$vars:array($vars);
		$vars_block = (is_array($vars_block))?$vars_block:array($vars_block);
		$vars_mul_block = (is_array($vars_mul_block))?$vars_mul_block:array($vars_mul_block);

		$content = $this->content;
		
//-- parseo los bloques dependientes
		foreach ($this->blocks as $value)
		{
			if(!in_array($value,$this->ignore))
				$content = str_replace(self::EXP_DEPEND_INI.$value.self::EXP_DEPEND_END,$vars_block[$value],$content);
			else
				$content = str_replace(self::EXP_DEPEND_INI.$value.self::EXP_DEPEND_END,"",$content);
		}
			
//-- parseo los bloques dependientes multiples
		foreach ($this->mul_blocks as $value)
			$content = str_replace(self::EXP_MUL_DEPEND_INI.$value.self::EXP_MUL_DEPEND_END,$vars_mul_block[$value],$content);
		
//-- parseo de las variables
		preg_match_all('~{(\w+)}~mi',$this->content,$outs);
		$vars_aux = $outs[1];
		
		foreach ($vars_aux as $value)
			$content = str_replace(self::EXP_VAR_INI .$value.self::EXP_VAR_END ,$vars[$value],$content);
			
		return $content;
	}
}


/**
 * Permite leer fichero tpl, permitiendo varias funcionalidades como son 
 * el poder poner variables dentro de dichas plantillas,
 * crear dependencias entre plantillas
 *
 */
class ubTemplate
{
	const EXP_BLOCK_INI = "\[<";
	const EXP_BLOCK_END = ">\]";
    /**
	 * Establece el prefijo de los métodos a tener en cuenta para obtener
	 */
	static public $get = "get__";
	
	/**
	 * Establece el prefijo de los métodos a tener en cuenta para cambiar
	 */
	static public $set = "set__";	
	/**
	 * guarda la direccion donde se encuentran las plantillas
	 *
	 * @var string
	 */
	static public $path = 'tpl';
	/**
	 * especifica el prefijo que se le antepone a la variable que se utilizara para 
	 * llenar los bloques dependientes
	 *
	 * @var string
	 */
	static public $prefix_mul = '';
	/**
	 * contiene el ultimo bloque cargado
	 *
	 * @var ubTemplateBlock
	 */
	public $last_block;
	/**
	 * Contiene todos los bloques
	 *
	 * @var array
	 */
	public $blocks = array();
	/**
	 * contiene las variables para la plantilla
	 *
	 * @var array
	 */
	private $vars = array();
	/**
	 * contiene los bloques ficheros incluidos
	 *
	 * @var array
	 */
	private $includes = array();
		
	/**
	 * Contruye una instancia de la clase, ya sea con el o los ficheros
	 * a mapear o el contenido
	 *
	 * @param string o array $file
	 * @param string $content
	 * @return ubTemplate
	 */
	public function __construct($file = '',$content = '')
	{
		if($file)
			$this->load_file($file);
		elseif ($content)
			$this->load_content($content);
		else
			throw new Exception("Se debe introducir un fichero o el contenido");
	}
	
	/**
	 * Carga los bloques de un fichero
	 *
	 * @param string o array $file
	 */
	public function load_file($file)
	{
		$this->load_content($this->read($file));
	}
	
	/**
	 * Carga los bloques de un contenido
	 *
	 * @param string $content
	 */
	public function load_content($content)
	{
		preg_match_all('~(?:@include\s)+(\w+)~mi', $content, $includes);
				
		if(count($includes[1]) > 0)
		{
			$to_includes = array_diff($includes[1],$this->includes);
			$content .= $this->read($to_includes);
			$this->includes = array_merge($to_includes,$this->includes);
		}
		
		preg_match_all('~'.self::EXP_BLOCK_INI.'(\w+)'.self::EXP_BLOCK_END.'~mi',$content,$blocks);
		
		$default = null;
		foreach ($blocks[1] as $block_name) {
			if($default == null)
				$default = $block_name;
			
			if(!preg_match_all("~".self::EXP_BLOCK_INI."$block_name".self::EXP_BLOCK_END."(.+)".self::EXP_BLOCK_INI."/$block_name".self::EXP_BLOCK_END."~smi",$content,$outs))
				throw new Exception("Error parseando el fichero tpl. El bloque \"$block_name\" no se encuentra cerrado correctamente");
			
			$this->blocks[$block_name] = new ubTemplateBlock($block_name,$outs[1][0]);
		}
		
		if($this->blocks['default'])
			$this->last_block = $this->blocks['default'];
		elseif(count($this->blocks))
			$this->last_block = $this->blocks[$default];
		else
			$this->blocks = null;
	}
	
	public function get_vars()
	{
		return $this->vars;
	}
	
	public function set_vars($value = array())
	{
		$this->vars = $this->validate_vars($value);
	}
	
	/**
	 * @return ubTemplateBlock
	 */
	public function get_last_block()
	{
		return $this->last_block;
	}
	
	/**
	 * @return ubTemplateBlock
	 */
	public function get_block($block)
	{
		if($this->blocks[$block])
			return $this->blocks[$block];
		else
			throw new Exception("El bloque \"$block\" no se encuentra registrado");
	}
	
	/**
	 * Adiciona un bloque que para ignorar dentro de otro
	 *
	 * @param string $block
	 * @param string $block_to_ignore
	 */
	public function add_ignore($block,$block_to_ignore)
	{
		$this->get_block($block)->add_ignore($block_to_ignore);
	}
	
	/**
	 * Elimina un bloque que para ignorar dentro de otro
	 *
	 * @param string $block
	 * @param string $block_to_ignore
	 */
	public function del_ignore($block,$block_to_ignore)
	{
		$this->get_block($block)->del_ignore($block_to_ignore);
	}
	
	/**
	 * Devuelve la información del objecto en forma de array
	 * en caso de que no sea un array se devuelve el propio parámetro
	 *
	 * @param object $object
	 * @return array
	 */
	public function validate_vars($value)
	{
		if(is_array($value))
			$vars = $value;
		elseif (is_object($value))
		{
			$vars = array();
			$arr_get = preg_grep('/^'.self::$get.'/',get_class_methods(get_class($value)));
			$arr = array();
			foreach ($arr_get as $get) 
			{
				$key = preg_replace("/".self::$get."/","",$get);
				$vars[$key] = $value->$get();
			}
		}else
			$vars = array($value);
		
		return $vars;
	}
	
	/**
	 * Devuelve la dirección correspondiente 
	 * a un fichero tenuiendo en cuenta la variable $path 
	 * que tiene que haber sido inicializada con anterioridad
	 *
	 * @param string $file
	 * @return string
	 */
	public function dir_tpl($file)
	{
		if (file_exists($file))
			return $file;

		$dir = "";
		$dir = (self::$path)?self::$path.DIRECTORY_SEPARATOR:"";
		
		if(preg_match("/.tpl$/",$file))
			return "$dir$file";
			
		return "$dir$file.tpl";
	}
	
	/**
	 * Permite leer uno o mas fichero y lo deja guardado en memoria
	 *
	 * @param string $file
	 */
	public function read($file)
	{
		$data = "";
		if(is_array($file))
		{
			foreach ($file as $value) {
				$data .= $this->read_file($value);
			}			
		}else
			$data = $this->read_file($file);
		
		return $data;
	}
	
	/**
	 * Lee un fichero que se le pase por parámetro
	 *
	 * @param string $file
	 * @return string
	 */
	private function read_file($file){
		$tpl_file = $this->dir_tpl($file);
		
		$data = '';
		if (($fd = @fopen($tpl_file, 'r')))
		{
			$tam = filesize($tpl_file);
			if($tam)
				$data = fread($fd, $tam);
				
			fclose($fd);
		}
		return $data;
	}
	
	/**
	 * Escoge y Devuelve solo el bloque deseado dentro del contenido en memoria
	 * en caso de que no exista dicho bloque se devuelve ""
	 *
	 * @param string $block
	 * @return string
	 */
	public function set_block( $block)
	{
		if($this->blocks[$block])
			$this->last_block = $this->blocks[$block];
		else
			throw new Exception("El bloque \"$block\" no se encuentra registrado");
	}

	/**
	 * Permite parsear la información de un bloque determinado
	 *
	 * @param string $block
	 * @return string
	 */
	public function parser($block = null,$vars = array())
	{
		$vars = $this->validate_vars($vars);
		
//-- primero convierto en caso de que sea un objeto la variable $vars a un arreglo
		$vars = array_merge($this->vars,$vars);
		$vars_simple = $this->vars_simples($vars);
		
//-- busco el bloque a parsear		
		if($block == null)
			$block = $this->last_block;
		elseif($this->blocks[$block])
			$block = $this->blocks[$block];
		else
			throw new Exception("El bloque \"$block\" no se encuentra registrado");
				
		$vars_block = array();
		$vars_mul_block = array();

//-- busco las dependencias del bloque y pongo su contenido como variables dentro de otro arreglo
		$blocks = $block->blocks_to_include();
			
		foreach ($blocks as $value) {
			if(!$vars_simple[$value."_ign"])
			{
				$vars_ = $this->validate_vars($vars[$value]);
				$vars_dep = ($vars[$value] && is_array($vars[$value]))?array_merge($vars_simple,$vars_):$vars_simple;	
				$vars_block[$value] = $this->parser($value,$vars_dep);
			}
		}
		
//-- busco las dependencias multiples del bloque y pongo su contenido como variables dentro de otro arreglo
		$mul_blocks = $block->get_mul_blocks();	
		foreach ($mul_blocks as $value) 
		{
			if(!$vars_simple[$value."_ign"])
			{
				$data = "";
				if($vars[$value])
				{
					if(!is_array($vars[$value]))
						$vars[$value] = array($vars[$value]);
					
					foreach ($vars[$value] as $vars_mul)
					{
						$vars_mul = $this->validate_vars($vars_mul);
						$vars_mul = ($vars_mul && is_array($vars_mul))?array_merge($vars_simple,$vars_mul):$vars_simple;
						$data .= $this->parser($value,$vars_mul);
					}
				}
				$vars_mul_block[$value] = $data;
			}
		}

		return $block->parser($vars_simple,$vars_block,$vars_mul_block);
	}
	
	/**
	 * Devuelve solo las variables simples
	 *
	 * @return unknown
	 */
	public function vars_simples($vars)
	{
		$return  = array();
		$vars = $this->validate_vars($vars);
		
		foreach ($vars as $key => $value) {
			if(!is_array($value) && !is_object($value))
				$return[$key] = $value;
		}
		return $return;
	}
	
//Métodos estáticos

	/**
	 * Devuelve un bloque ya parseado,
	 * se le pasa  un fichero
	 *
	 * @param string $file
	 * @param string $block
	 * @param array $vars
	 * @return string
	 */
	static public function parser_block_file($file,$block='',$vars = array())
	{
		$template = new ubTemplate($file,null);
		$template->set_vars($vars);
		$template->set_block($block);
		return $template->parser();
	}

	/**
	 * Devuelve un bloque ya parseado,
	 * en caso de que no se le pase el fichero se le debe pasar el contenido de este
	 *
	 * @param string $context
	 * @param string $block
	 * @param array $vars
	 * @return string
	 */
	static public function parser_block_context($context,$block='',$vars = array())
	{			
		$template = new ubTemplate(null,$context);
		$template->set_vars($vars);
		$template->set_block($block);
		return $template->parser();
	}
}
?>
Return current item: ubtemplate