View file sys/inc/SomeTemplate.class.php

File size: 16.74Kb
<?php

/**
 * @author Morgan
 * @copyright 2010
 */

#error_reporting(E_ALL);

if(!defined('SOMETEMPLATE_DEFAULT_DIR'))define('SOMETEMPLATE_DEFAULT_DIR', './');
if(!defined('SOMETEMPLATE_DEFAULT_COMPILED_DIR'))define('SOMETEMPLATE_DEFAULT_COMPILED_DIR', './compile/');
if(!defined('SOMETEMPLATE_DEFAULT_EXT'))define('SOMETEMPLATE_DEFAULT_EXT', 'tpl');
if(!defined('EOL'))define('EOL', "\r\n");


# Простенький класс для организации MVC-модели
		class SomeTemplate
	{
	// режим отладки компилятора
	public $debug_compiler = false;
	// папка шаблонов
	private $templates_dir = SOMETEMPLATE_DEFAULT_DIR;
	// папка сгенерированных файлов
	private $compiled_template_dir = SOMETEMPLATE_DEFAULT_COMPILED_DIR;
	// расширение шаблонов
	private $templates_ext = SOMETEMPLATE_DEFAULT_EXT;
	// переменные, доступные в шаблонах
	private $vars = array();
	// некоторые настройки шаблона
	private $cfgs = array();


		/**
		* __construct
		*
		* Установка параметров работы
		*
		* @param string $templates_dir            папка с шаблонами
		* @param string $compiled_templates_dir   папка, куда сохраняются скомпилированые шаблоны
		* @param string $templatess_ext           расширение файлов шаблонов
		**/
			public function __construct($templates_dir = SOMETEMPLATE_DEFAULT_DIR, $compiled_templates_dir = SOMETEMPLATE_DEFAULT_COMPILED_DIR, $templates_ext = SOMETEMPLATE_DEFAULT_EXT)
		{
		if(is_dir($templates_dir))$this -> templates_dir = (substr($templates_dir, -1) != '/' ? $templates_dir.'/' : $templates_dir);

		if(is_dir($compiled_templates_dir))$this -> compiled_templates_dir = (substr($compiled_templates_dir, -1) != '/' ? $compiled_templates_dir.'/' : $compiled_templates_dir);

		$this -> templates_ext = $templates_ext;

		}


		/**
		* __set
		*
		* Установка переменных, доступных в шаблоне
		*
		* @param string $var_name  имя переменной
		* @param string $var_value значение переменной
		**/
			public function __set($var_name, $var_value)
		{
		$this -> vars[$var_name] = $var_value;
		}

		/**
		* __get
		*
		* Получения значения переменной
		*
		* @param string $var_name имя переменной
		* @return mixed           значение переменной
		**/
			public function __get($var_name)
		{
		if(isset($this -> vars[$var_name]))return $this -> vars[$var_name];
		return false;
		}


		/**
		* __set
		*
		* Установка переменных, доступных в шаблоне
		*
		* @param string $var_name  имя переменной
		* @param string $var_value значение переменной
		**/
			public function assign($var_name, $var_value = false)
		{
		if(is_array($var_name) && $var_value == false)
			{
					foreach($var_name as $name => $value)
				{
				$this -> assign($name, $value);
				}
			}
		else
			{
			$this -> vars[$var_name] = $var_value;
			}

		return true;
		}


		/**
		* debug
		*
		* Просмотр значений всех переменных
		*
		* @param bool $exit требуется ли завершение работы скрипта
		**/
			public function debug($exit = true)
		{

		echo '<b>templates_dir</b> = <b>'.$this -> templates_dir.'</b><br />';
		echo '<b>templates_ext</b> = <b>'.$this -> templates_ext.'</b><br />';

		print_r($this -> vars);

		if($exit)exit;

		return true;
		}


		/**
		* display
		*
		* Обработка шаблона, и вывод на экран
		*
		* @param string $template_name имя файла-шаблона
		* @return bool                 возникли ли ошибки
		**/
			public function display($template_name)
		{

		if(!file_exists($this -> templates_dir.$template_name.'.'.$this -> templates_ext))return false;

		if($this -> debug_compiler || (!file_exists($this -> compiled_templates_dir.$template_name.'.'.$this -> templates_ext.'.php') || filemtime($this -> compiled_templates_dir.$template_name.'.'.$this -> templates_ext.'.php') < filemtime($this -> templates_dir.$template_name.'.'.$this -> templates_ext)))
			{

			if(!isset($this -> cfgs[$template_name]))$this -> cfgs[$template_name] = array();

			// генерируем php файл из шаблона
			$content = $this -> prepare_tpl($template_name);

			// вставляем комментарий
			$content = '<?php /* Сгенерировано '.date('G:i:s d.m.Y').' из файла '.$this -> compiled_templates_dir.$template_name.'.'.$this -> templates_ext.' */ ?>'.EOL.$content;

			if(!file_put_contents($this -> compiled_templates_dir.$template_name.'.'.$this -> templates_ext.'.php', $content))return false;

			}


		#if(!isset($content))$content = file_get_contents($this -> compiled_templates_dir.$template_name.'.'.$this -> templates_ext.'.php');


		require $this -> compiled_templates_dir.$template_name.'.'.$this -> templates_ext.'.php';

		#if($this -> debug_compiler)unlink($this -> compiled_templates_dir.$template_name.'.'.$this -> templates_ext.'.php');


		return true;
		}


		/**
		* prepare_tpl
		*
		* Обработка шаблона
		*
		* @param string $filename имя файла-шаблона
		* @return string          PHP-код шаблона
		**/
			private function prepare_tpl($filename)
		{

		$code = file_get_contents($this -> templates_dir.$filename.'.'.$this -> templates_ext);

		// вставка других файлов
		$code = $this -> process_tpls($code);

		// блоки
		$code = $this -> process_blocks($code, $filename);

		// циклы
		$code = $this -> process_cycles($code, $filename);

		// условия
		$code = $this -> process_ifs($code);

		// переменные
		$code = $this -> process_vars($code);

		#d($code);

		return $code;

		}


		/**
		* process_blocks
		*
		* обработка блоков в шаблоне типа
		*				{block index}
		*				...
		*				{/block index}
		* в  switch ... case ... break ... endswtich;
		*
		*
		* @param string $code     код шаблона
		* @param string $template имя файла-шаблона
		* @return string          обработанный код
		**/
			private function process_blocks($code, $template)
		{
		$old_code = $code;
		$old_strlen = strlen($old_code);

		// циклы
		preg_match_all('~\{block ((\!)?([^!]*))\}(.*)\{\/block \\1\}~uUs', $code, $blocks, PREG_SET_ORDER ^ PREG_OFFSET_CAPTURE);
		#d($blocks,0);


		$use_blocks = false;

		// код до/после/между блоками
		$after_code = $before_code = $rest = null;

		if($template == 'topic.page')
			{
			#echo '<div class="code">'.nl2br(set_eol(htmlspecialchars($code))).'</div>';
			}

		$count_blocks = count($blocks);


		if($count_blocks > 0)
			{

			$use_blocks = true;
			$lenght_shift = 0;

					for($i = 0;$i < $count_blocks;$i ++)
				{

				if($i == 0 && $blocks[$i][0][1] > 0)
					{
					// записываем код "до"
					$after_code = trim(substr($code, 0, $blocks[$i][0][1]));
					#d(substr($code, $blocks[$i][0][1]));
					$strlen = strlen($code);
					$code = substr($code, $blocks[$i][0][1]);
					$lenght_shift = $strlen - strlen($code);
					#echo $lenght_shift;
					#d(trim(substr($code, 0, $blocks[$i][0][1])),0);
					#$result = null;
					}


				if($blocks[$i][2][0] == '!')
					{
					#d($blocks[$i],0);
					$result_code = '<?php if($this -> vars[\'block\'] != \''.$blocks[$i][3][0].'\'): ?>'.EOL;

					$result_code .= $blocks[$i][4][0];

					$result_code .= EOL.'<?php endif; ?>'.EOL;

					if($i == 0)$after_code .= $result_code;
					else $before_code .= $result_code;
					$result = null;
					}
				else
					{

					$result = '<?php case \''.$blocks[$i][1][0].'\': ?>'.EOL;

					$result .= $blocks[$i][4][0];

					$result .= EOL.'<?php break; ?>'.EOL;

					#d($blocks[$i],0);
					#d($result,0);

					}

				if(($i + 1) == $count_blocks && ($blocks[$i][0][1] + strlen($blocks[$i][0][0])) < $old_strlen)
					{
					#echo nl2br(set_eol(htmlspecialchars(substr($code, $blocks[$i][0][1] + strlen($blocks[$i][0][0]) + $lenght_shift))));
					#echo $lenght_shift;
					// записываем код "после"
					#$before_code .= trim(substr($code, ($blocks[$i][0][1] + strlen($blocks[$i][0][0])) + $lenght_shift));
					#$code = trim(substr($code, 0, ($blocks[$i][0][1] + strlen($blocks[$i][0][0])) + $lenght_shift));
					#d(($blocks[$i][0][1] + strlen($blocks[$i][0][0])),0);
					#d($blocks[$i]);

					// получаем длину конца
					$end_lenght = $old_strlen - ($blocks[$i][0][1] + strlen($blocks[$i][0][0]));

					$before_code .= trim(substr($code, -$end_lenght));
					$code = trim(substr($code, 0, -$end_lenght));

					#echo $end_lenght;
					#echo nl2br(set_eol(htmlspecialchars(substr($code,0, -88))));

					#$result = null;
					}

				$code = preg_replace('~'.preg_quote($blocks[$i][0][0], '~').'~uUs', $result, $code, 1);
				}

			}


		if($use_blocks)
			{
			$code = (!empty($after_code) ? $after_code.EOL : null).'<?php switch(isset($this -> vars[\'block\']) ? $this -> vars[\'block\'] : null): ?>'.EOL.$code.'<?php endswitch; ?>'.(!empty($before_code) ? EOL.$before_code : null);
			/*$code = '<?php switch($this -> vars[\'block\']): ?>'.EOL.$code.'<?php endswitch; ?>';*/
			}

		#if($template == 'post.page')
		#	{
		#	echo '<br /><div class="code">'.nl2br(set_eol(htmlspecialchars($code))).'</div>';
		#	}


		#d($after_code,0);
		#d($before_code,0);

		return $code;
		}


		/**
		* process_ifs
		*
		* обработка условий в шаблоне
		*				{if $somevar}
		*				...
		*				{/if $somevar}
		* в if(...) ... endif;
		*
		*
		* @param string $code код шаблона
		* @return string      обработанный код
		**/
			private function process_ifs($code)
		{

		// условии
		preg_match_all('~\{if ((\!)?(\~)?\$((.+)(\.(.*))?)( (.*) (\$((.+)(\.(.*))?)|.+))?)\}(?:\r\n|\n)?(.*)(?:\r\n|\n)?\{\/if \\1\}~uUs', $code, $ifs, PREG_SET_ORDER);


		$count_ifs = count($ifs);
			if($count_ifs > 0)
				{
						for($i = 0;$i < $count_ifs;$i ++)
					{

					$var = $this -> get_var($ifs[$i][4], false);
					$chapter1 = 'isset('.$var.') && ';


					if(!empty($ifs[$i][8]))
						{
						// если это переменная
						if($ifs[$i][10] == '$'.$ifs[$i][11])
							{

							$var2 = $this -> get_var($ifs[$i][11], false);

							$chapter1 .= 'isset('.$var2.') && ';

							$strlen = strlen($ifs[$i][10]);

							$chapter2 = $var.substr($ifs[$i][8], 0, -$strlen).$var2;

							}
						else
							{
							$chapter2 = $var.$ifs[$i][8];
							}



						}
					else
						{


						if($ifs[$i][2] == '!')
							{
							$chapter1 = '!isset('.$var.') || ';

							if($ifs[$i][3] == '~')$chapter2 = '!(bool)'.$var;
							else $chapter2 = $var.' !== true';

							}
						else
							{
							if($ifs[$i][3] == '~')$chapter2 = '(bool)'.$var;
							else $chapter2 = $var.' === true';
							}

						#if($ifs[$i][3] == '~')$chapter2 = ($ifs[$i][2] == '!' ? '!' : null).'(bool)'.$var;
						#else $chapter2 = $var.($ifs[$i][2] == '!' ? '!' : '=').'== true';

						}

					$result = '<?php if('.$chapter1.$chapter2.'): ?>';
					$result .= $this -> process_ifs($ifs[$i][15]);
					$result .= '<?php endif; ?>';

					$code = preg_replace('~'.preg_quote($ifs[$i][0], '~').'~uUs', $result, $code, 1);
					}
				}

		return $code;

		}


		/**
		* process_cycles
		*
		* обработка циклов в шаблоне типа
		*				{foreach $a}
		*				...
		*				{/foreach $a}
		* в for(...) ... endfor;
		*
		* @param string $code код шаблона
		* @return string      обработанный код
		**/
			private function process_cycles($code, $template)
		{
		// циклы
		preg_match_all('~\{foreach (\$(.*))\}(?:\r\n|\n)?(.*)(?:\r\n|\n)?\{\/foreach \\1\}~uUs', $code, $cycles, PREG_SET_ORDER);
		#d($cycles);

		$count_cycles = count($cycles);
		if($count_cycles > 0)
			{

					for($i = 0;$i < $count_cycles;$i ++)
				{

				$result = null;

				$var = $this -> get_var($cycles[$i][2], false);


				#eval('$is_set = isset('.$var.');');
				#eval('$array = (isset('..'))'.$var.';');


				$last_value = (isset($this -> cfgs['cycles_values']['last_value'])) ? ($this -> cfgs['cycles_values']['last_value'] + 1) :  1;
				$this -> cfgs['cycles_values']['last_value'] = $last_value;

				$index = '_cycles_'.$last_value;

				/*#$this -> vars[$index] = $array;

				#d('{$'.preg_quote($cycles[$i][2], '~').'(.*)}');

				#d($this -> get_recursive_values($array));

				#d($index,0);
				*/

				$cycles[$i][3] = preg_replace('~\{\$'.preg_quote($cycles[$i][2], '~').'\.(.+)\}~uUs', '<?php if(isset($'.$index.'[\'$1\']))echo $'.$index.'[\'$1\']; ?>', $cycles[$i][3]);

				$cycles[$i][3] = preg_replace('~if (\!)?(\~)?\$'.preg_quote($cycles[$i][2], '~').'\.(.*)~uUs', 'if $1$2$'.$cycles[$i][2].'.$'.$index.'_i.$3', $cycles[$i][3]);
				// if ($'.$index.'[\'$2\']



				#$count_values = count($array);

				$result = '<?php if (!empty('.$var.')): ?>'.EOL;
				$result .= '		<?php for($'.$index.'_c = count('.$var.'), $'.$index.'_i = 0; $'.$index.'_i < $'.$index.'_c; $'.$index.'_i ++): ?>'.EOL;
				$result .= '	<?php $'.$index.' = '.$var.'[$'.$index.'_i]; ?>'.EOL;

				$result .= $this -> process_cycles($cycles[$i][3], $template);

				$result .= '		<?php endfor; ?>'.EOL;
				$result .= '<?php endif; ?>';



				$code = preg_replace('~'.preg_quote($cycles[$i][0], '~').'~uUs', $result, $code, 1);

				}

			}

		return $code;
		}


		/**
		* process_vars
		*
		* обработка переменных в шаблоне типа
		*				{$somevar}
		* в echo $somevar;
		*
		* @param string $code код шаблона
		* @return string      обработанный код
		**/
			private function process_vars($code)
		{
		preg_match_all('~\{\$(.+)\}~uUs', $code, $vars, PREG_SET_ORDER);

		$count_vars = count($vars);
		if($count_vars > 0)
			{
					for($i = 0;$i < $count_vars;$i ++)
				{

				$var = $this -> get_var($vars[$i][1], false);

				#$result = null;

				#if(!empty($var))
				#	{
					$result = '<?php if(isset('.$var.'))echo '.$var.'; ?>';
				#	}


				$code = preg_replace('~'.preg_quote($vars[$i][0], '~').'~uUs', $result, $code, 1);
				}
			}

		return $code;
		}

		/**
		* process_tplss
		*
		* вставка содержимого друого файла через конструкцию
		*				{include template: some_template}
		*
		* @param string $code код шаблона
		* @return string      обработанный код
		**/
			private function process_tpls($code)
		{
		// вставка других шаблонов
		preg_match_all('~\{include template\:(.*)\}~uUs', $code, $tpls, PREG_SET_ORDER);

		$count_tpls = count($tpls);
		if($count_tpls > 0)
			{
					for($i = 0;$i < $count_tpls;$i ++)
				{
				$result = null;

				if(file_exists($this -> templates_dir.$tpls[$i][1].'.'.$this -> templates_ext))
					{
					$result = file_get_contents($this -> templates_dir.$tpls[$i][1].'.'.$this -> templates_ext);
					}

				$code = preg_replace('~'.preg_quote($tpls[$i][0]).'~u', $result, $code, 1);
				}
			}

		return $code;
		}


		/**
		* get_var
		*
		* форматирование переменной типа
		*				$one.two.three
		* в $this -> vars['one']['two']['three']
		*
		* @param string $code код шаблона
		* @return string      обработанный код
		**/
			private function get_var($string_var, $isset = true, $type = false)
		{

		// разбиваем строку на секции
		$sections = explode('.', $string_var);

		$count_sections = count($sections);

		if($count_sections > 0)
			{
			$var = null;
					for($i = 0;$i < $count_sections;$i ++)
				{
				if(substr($sections[$i], 0, 1) == '$' || is_numeric($sections[$i]))$var .= '['.$sections[$i].']';
				else $var .= '[\''.$sections[$i].'\']';
				}

			#eval('$var = \'[\\\'\'.implode(\'\\\'][\\\'\', $sections).\'\\\']\';');
			if(!$isset)return '$this -> vars'.$var;

			eval('$is_set = isset($this -> vars'.$var.');');

			$is_type = true;

			if($is_set && is_string($type))eval('$is_type = is_'.$type.'($this -> vars'.$var.');');

			if($is_set && $is_type)
				{
				return '$this -> vars'.$var;
				}

			return 0;
			}

		return 0;
		}


	}




?>