|
|
@@ -14,14 +14,28 @@ class LightweightTemplate {
|
|
|
static $cache_enabled = (ENV == 'prod') || true;
|
|
|
static $tpl_last_updated = null;
|
|
|
|
|
|
-
|
|
|
+ protected $tpl_cache_enabled = true; // and if $cache_enabled is true
|
|
|
protected $data = [];
|
|
|
|
|
|
+
|
|
|
public function __construct($tpl_path=null, $variables=[], $layout=null)
|
|
|
{
|
|
|
$this->data = $variables;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ public function disableCache()
|
|
|
+ {
|
|
|
+ $this->tpl_cache_enabled = false;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public function enableCache()
|
|
|
+ {
|
|
|
+ $this->tpl_cache_enabled = true;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
public function assign($k, $v=null)
|
|
|
{
|
|
|
if (is_array($k)) {
|
|
|
@@ -34,17 +48,20 @@ class LightweightTemplate {
|
|
|
$this->data[$k] = $v;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
|
|
|
public function getVariables()
|
|
|
{
|
|
|
return $this->data;
|
|
|
}
|
|
|
+
|
|
|
|
|
|
public function getVar($var_name, $default_value=null)
|
|
|
{
|
|
|
return isset($this->data[$var_name]) ? $this->data[$var_name] : $default_value;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
public function fetch($tpl=null, $extra_vars=[], $layout=null, $options=[])
|
|
|
{
|
|
|
ob_start();
|
|
|
@@ -54,16 +71,19 @@ class LightweightTemplate {
|
|
|
return $content;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
public function display($tpl=null, $extra_vars=[], $layout=null, $options=[])
|
|
|
{
|
|
|
+ $allow_template_debug_traces = empty($options['deny_template_debug']);
|
|
|
$tpl_data = $this->data + $extra_vars;
|
|
|
- self::view($tpl, $tpl_data);
|
|
|
+ self::view($tpl, $tpl_data, $allow_template_debug_traces);
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
|
|
|
- public static function view($file, $tpl_data = array()) {
|
|
|
- $cached_file = self::cache($file);
|
|
|
+ public static function view($file, $tpl_data = array(), $allow_template_debug_traces=true) {
|
|
|
+ $cached_file = self::cache($file, $allow_template_debug_traces);
|
|
|
+
|
|
|
extract($tpl_data, EXTR_SKIP);
|
|
|
|
|
|
$debugbar = App::getData('debugbar');
|
|
|
@@ -78,7 +98,7 @@ class LightweightTemplate {
|
|
|
}
|
|
|
|
|
|
|
|
|
- protected static function cache($file) {
|
|
|
+ protected static function cache($file, $allow_template_debug_traces=true) {
|
|
|
if (!file_exists(self::$cache_path)) {
|
|
|
if (! @mkdir(self::$cache_path, 0744)) {
|
|
|
throw new \Exception("Cannot create templates cache dir " . self::$cache_path, 1);
|
|
|
@@ -91,30 +111,38 @@ class LightweightTemplate {
|
|
|
if ($cached_file_exists) {
|
|
|
$cached_file_updated = filemtime($cached_file);
|
|
|
$file_path = strpos($file, '/') === 0 ? $file : (self::$tpl_path . '/' . $file);
|
|
|
- self::$tpl_last_updated = filemtime($file_path);
|
|
|
+ self::$tpl_last_updated = filemtime($file_path);
|
|
|
+
|
|
|
} else {
|
|
|
$cached_file_updated = null;
|
|
|
}
|
|
|
|
|
|
if (ENV == 'dev') {
|
|
|
// on force le parcours de tous les fichiers inclus pour avoir la vraie valeur de self::$tpl_last_updated
|
|
|
- $code = self::includeFiles($file);
|
|
|
+ $code = self::includeFiles($file, 0, null, null, $allow_template_debug_traces);
|
|
|
}
|
|
|
|
|
|
if (!self::$cache_enabled || ! $cached_file_exists || $cached_file_updated < self::$tpl_last_updated) {
|
|
|
+ // (re)regenere le template
|
|
|
+
|
|
|
if (! isset($code)) {
|
|
|
- $code = self::includeFiles($file);
|
|
|
- }
|
|
|
- $code = self::compileCode($code);
|
|
|
+ // si env != 'dev' (car pour env=dev on a déjà rempli la variable $code. voir quelques lignes au-dessus)
|
|
|
+ $code = self::includeFiles($file, 0, null, null, $allow_template_debug_traces);
|
|
|
+ }
|
|
|
+
|
|
|
+ $code = self::compileCode($code); // compilation du template
|
|
|
+
|
|
|
file_put_contents($cached_file, '<?php class_exists(\'' . __CLASS__ . '\') or exit; ?>' . PHP_EOL . $code);
|
|
|
|
|
|
- } else {
|
|
|
+ } else if (ENV == 'dev') {
|
|
|
+ // affichage des infos du cached_template dans la debugbar
|
|
|
+
|
|
|
//header('X-Template: cached'); // TODO: $response->addHeader(...)
|
|
|
|
|
|
$debugbar = App::getData('debugbar');
|
|
|
if ($debugbar) {
|
|
|
if (isset($debugbar['templates'])) {
|
|
|
- $debugbar_message_idx = $debugbar['templates']->addMessage([
|
|
|
+ $debugbar['templates']->addMessage([
|
|
|
'tpl' => $cached_file,
|
|
|
'content_length' => filesize($cached_file),
|
|
|
'content_length_str' => formatSize(filesize($cached_file)),
|
|
|
@@ -127,12 +155,14 @@ class LightweightTemplate {
|
|
|
return $cached_file;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
public static function clearCache() {
|
|
|
foreach(glob(self::$cache_path . '/*') as $file) {
|
|
|
unlink($file);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+
|
|
|
protected static function compileCode($code) {
|
|
|
$code = self::compileBlock($code);
|
|
|
$code = self::compileYield($code);
|
|
|
@@ -140,11 +170,12 @@ class LightweightTemplate {
|
|
|
$code = self::compileModules($code);
|
|
|
$code = self::compileEscapedEchos($code);
|
|
|
$code = self::compileEchos($code);
|
|
|
- //$code = self::compilePHP($code);
|
|
|
+
|
|
|
return $code;
|
|
|
}
|
|
|
|
|
|
- protected static function includeFiles($file, $level=0, $caller_file=null, $parent_file=null) {
|
|
|
+
|
|
|
+ protected static function includeFiles($file, $level=0, $caller_file=null, $parent_file=null, $allow_template_debug_traces=true) {
|
|
|
$file_path = strpos($file, '/') === 0 ? $file : (self::$tpl_path . '/' . $file);
|
|
|
|
|
|
if (! is_file($file_path)) {
|
|
|
@@ -189,6 +220,7 @@ class LightweightTemplate {
|
|
|
|
|
|
|
|
|
if (defined('ENV') && ENV == 'dev') {
|
|
|
+ // show dev/debug infos when on development ENV
|
|
|
$tpl_infos = '';
|
|
|
if ($caller_file) {
|
|
|
$tpl_infos .= ' layout for ' . $caller_file . '';
|
|
|
@@ -200,10 +232,12 @@ class LightweightTemplate {
|
|
|
$tpl_infos .= ' with layout ' . $layout . '';
|
|
|
}
|
|
|
|
|
|
- $begin = '<!-- [' . $level . '] BEGIN TEMPLATE #' . $tpl_idx . ' : ' . $file . ' (size: ' . formatSize(strlen($code)) . ' - ' . $tpl_infos . ') -->';
|
|
|
- $end = '<!-- [' . $level . '] END TEMPLATE #' . $tpl_idx . ' : ' . $file . ' (size: ' . formatSize(strlen($code)) . ' - ' . $tpl_infos . ') -->';
|
|
|
+ if ($allow_template_debug_traces) {
|
|
|
+ $begin = '<!-- [' . $level . '] BEGIN TEMPLATE #' . $tpl_idx . ' : ' . $file . ' (size: ' . formatSize(strlen($code)) . ' - ' . $tpl_infos . ') -->';
|
|
|
+ $end = '<!-- [' . $level . '] END TEMPLATE #' . $tpl_idx . ' : ' . $file . ' (size: ' . formatSize(strlen($code)) . ' - ' . $tpl_infos . ') -->';
|
|
|
+ $code = PHP_EOL . $begin . PHP_EOL . $code . PHP_EOL . $end . PHP_EOL;
|
|
|
+ }
|
|
|
|
|
|
- $code = PHP_EOL . $begin . PHP_EOL . $code . PHP_EOL . $end . PHP_EOL;
|
|
|
}
|
|
|
|
|
|
// Layout (2)
|
|
|
@@ -211,9 +245,10 @@ class LightweightTemplate {
|
|
|
$value = $layout_matches[0];
|
|
|
$layout = $value[1];
|
|
|
|
|
|
- $layout_code = self::includeFiles($layout, $level-1, $file);
|
|
|
+ $layout_code = self::includeFiles($layout, $level-1, $file, null, $allow_template_debug_traces);
|
|
|
$code = str_replace($value[0], '', $code);
|
|
|
-
|
|
|
+
|
|
|
+ // @content
|
|
|
$layout_code = str_replace('<' . '?=$child_content?' . '>', '{@content}', $layout_code);
|
|
|
$layout_code = str_replace('{$child_content}', '{@content}', $layout_code);
|
|
|
$layout_code = str_replace('{@content}', $code, $layout_code);
|
|
|
@@ -224,7 +259,7 @@ class LightweightTemplate {
|
|
|
// includes
|
|
|
preg_match_all('/{include ?\'?(.*?)\'? ?}/i', $code, $matches, PREG_SET_ORDER);
|
|
|
foreach ($matches as $value) {
|
|
|
- $included_code = self::includeFiles($value[1], $level+1, null, $file);
|
|
|
+ $included_code = self::includeFiles($value[1], $level+1, null, $file, $allow_template_debug_traces);
|
|
|
$code = str_replace($value[0], $included_code, $code);
|
|
|
}
|
|
|
|
|
|
@@ -249,27 +284,16 @@ class LightweightTemplate {
|
|
|
return $code;
|
|
|
}
|
|
|
|
|
|
- protected static function compilePHP($code) {
|
|
|
- /* return preg_replace('~\{%\s*(.+?)\s*\%}~is', '<?php $1 ?>', $code); */
|
|
|
- return $code;
|
|
|
- }
|
|
|
|
|
|
protected static function compileModules($code) {
|
|
|
|
|
|
// url => {url clients_list}
|
|
|
$code = preg_replace('/{routeUrl /', '{url ', $code); // for compatibility with old templates
|
|
|
+ $code = preg_replace('/{route /', '{url ', $code); // for compatibility with old templates
|
|
|
preg_match_all('~{url (.*?)}~is', $code, $matches, PREG_SET_ORDER);
|
|
|
foreach ($matches as $value) {
|
|
|
- //pre($matches); exit;
|
|
|
- if (false) {
|
|
|
- // {url clients_list} => "/clients/"
|
|
|
- $code = str_replace($value[0], getRouteUrl($value[1]), $code);
|
|
|
- // si on utilise des prefix d'urls, le prefix sera hardcodé dans le cache et crééra des erreurs d'urls quand on passera sur une url d'un prefix different
|
|
|
-
|
|
|
- } else {
|
|
|
- // {url clients_list} => "< ?=getRouteUrl('clients_list')? >" (dans espaces)
|
|
|
- $code = str_replace($value[0], '<?=getRouteUrl("' . $value[1] . '")?>', $code);
|
|
|
- }
|
|
|
+ // {url clients_list} => "< ?=getRouteUrl('clients_list')? >" (dans espaces)
|
|
|
+ $code = str_replace($value[0], '<?=getRouteUrl("' . $value[1] . '")?>', $code);
|
|
|
}
|
|
|
|
|
|
// foreach => {foreach $list as $item}<div>...</div>{/foreach}
|
|
|
@@ -284,7 +308,10 @@ class LightweightTemplate {
|
|
|
foreach ($matches as $value) {
|
|
|
|
|
|
$replaced = '<' . '?php elseif ( $1 ) : ?' . '>';
|
|
|
- $value[2] = preg_replace('/{elseif (.*?) ?}/', $replaced, $value[2]);
|
|
|
+ $value[2] = preg_replace('/\{ ?elseif (.*?) ?\}/', $replaced, $value[2]);
|
|
|
+
|
|
|
+ $replaced = '<' . '?php else : ?' . '>';
|
|
|
+ $value[2] = preg_replace('/\{ ?else ?\}/', $replaced, $value[2]);
|
|
|
|
|
|
$replaced = PHP_EOL . '<' . '?php if (' . $value[1] . ') : ?' . '>' . PHP_EOL . $value[2] . PHP_EOL . '<' . '?php endif; ?' . '>';
|
|
|
$code = str_replace($value[0], $replaced, $code);
|
|
|
@@ -293,43 +320,55 @@ class LightweightTemplate {
|
|
|
return $code;
|
|
|
}
|
|
|
|
|
|
- protected static function compileEchos($code, $strict=true) {
|
|
|
- // compile PHP variables (method 1) => {$my_var}
|
|
|
- if ($strict) {
|
|
|
- $code = preg_replace('~\{\$(.+?)}~is', '<?php echo \$$1 ?>', $code);
|
|
|
- } else {
|
|
|
- $code = preg_replace('~\{\$(.+?)}~is', '<?php echo isset(\$$1) ? (\$$1) : ""; ?>', $code);
|
|
|
- }
|
|
|
- // compile PHP variables (method 2) => {{ $my_var }}
|
|
|
- return preg_replace('~\{{\s*(.+?)\s*\}}~is', '<?php echo $1 ?>', $code);
|
|
|
+
|
|
|
+ protected static function compileEchos($code) {
|
|
|
+ // compile PHP optional variables => {{$my_optional_var}} => echo (isset($my_optional_var) ? $my_optional_var : '')
|
|
|
+ $code = preg_replace('~\{{\$(.+?)}}~is', '<?php echo isset(\$$1) ? (\$$1) : ""; ?>', $code);
|
|
|
+
|
|
|
+ // compile PHP strict variables => {$my_var} => echo $my_var
|
|
|
+ $code = preg_replace('~\{\$(.+?)}~is', '<?php echo \$$1 ?>', $code);
|
|
|
+
|
|
|
+ // compile PHP code => {{ my_php_code }} => echo my_php_code
|
|
|
+ $code = preg_replace('~\{{\s*(.+?)\s*\}}~is', '<?php echo $1 ?>', $code);
|
|
|
+
|
|
|
+ return $code;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
protected static function compileEscapedEchos($code) {
|
|
|
// compile PHP escaped variables => {{{ $my_var }}}
|
|
|
return preg_replace('~\{{{\s*(.+?)\s*\}}}~is', '<?php echo htmlentities($1, ENT_QUOTES, \'UTF-8\') ?>', $code);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
protected static function compileBlock($code) {
|
|
|
preg_match_all('~{block ?(.*?) ?}(.*?){/block}~is', $code, $matches, PREG_SET_ORDER);
|
|
|
+
|
|
|
foreach ($matches as $value) {
|
|
|
- if (!array_key_exists($value[1], self::$blocks)) self::$blocks[$value[1]] = '';
|
|
|
- if (strpos($value[2], '@parent') === false) {
|
|
|
- self::$blocks[$value[1]] = $value[2];
|
|
|
- } else {
|
|
|
- self::$blocks[$value[1]] = str_replace('@parent', self::$blocks[$value[1]], $value[2]);
|
|
|
+ $block_outer = $value[0];
|
|
|
+ $block_name = $value[1];
|
|
|
+ $block_inner = $value[2];
|
|
|
+
|
|
|
+ if (!array_key_exists($block_name, self::$blocks)) {
|
|
|
+ self::$blocks[$block_name] = [];
|
|
|
}
|
|
|
- $code = str_replace($value[0], '', $code);
|
|
|
+
|
|
|
+ self::$blocks[$block_name][] = $block_inner;
|
|
|
+
|
|
|
+ $code = str_replace($block_outer, '', $code);
|
|
|
}
|
|
|
return $code;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
protected static function compileYield($code) {
|
|
|
// compile yields => {yield my_block}
|
|
|
- foreach(self::$blocks as $block => $value) {
|
|
|
- $code = preg_replace('/{yield ' . $block . ' ?}/', $value, $code);
|
|
|
+ foreach(self::$blocks as $block_name => $block_chunks) {
|
|
|
+ $block_replace = implode('', $block_chunks);
|
|
|
+ $code = preg_replace('/{yield ' . $block_name . ' ?}/', $block_replace, $code);
|
|
|
}
|
|
|
$code = preg_replace('/{yield ?(.*?) ?}/i', '', $code);
|
|
|
return $code;
|
|
|
}
|
|
|
|
|
|
-}
|
|
|
+}
|