From b053fa82811549dd44ec78c8e2278dc5c322f666 Mon Sep 17 00:00:00 2001 From: dev-meghraj Date: Tue, 24 Dec 2013 02:16:47 +0530 Subject: [PATCH 1/4] add old yii-ext twig renderer's function into this. and as per yii2's view system changed so for now add simple directory of file based file loader for twig --- extensions/yii/twig/TwigSimpleFileLoader.php | 36 +++++ extensions/yii/twig/ViewRenderer.php | 175 +++++++++++++++++++-- .../yii/twig/ViewRendererStaticClassProxy.php | 37 +++++ 3 files changed, 238 insertions(+), 10 deletions(-) create mode 100644 extensions/yii/twig/TwigSimpleFileLoader.php create mode 100644 extensions/yii/twig/ViewRendererStaticClassProxy.php diff --git a/extensions/yii/twig/TwigSimpleFileLoader.php b/extensions/yii/twig/TwigSimpleFileLoader.php new file mode 100644 index 0000000..af7115b --- /dev/null +++ b/extensions/yii/twig/TwigSimpleFileLoader.php @@ -0,0 +1,36 @@ + + * @version 1.0.0 + */ +class TwigSimpleFileLoader implements \Twig_LoaderInterface { + + /** + * Path to directory where all file exists + * @param $view string + */ + private $dir; + + public function __construct($dir){ + $this->dir=$dir; + } + + public function isFresh($name, $time){ + return filemtime($this->getFilePath($name))<=$time; + } + public function getSource($name){ + return file_get_contents($this->getFilePath($name)); + } + public function getCacheKey($name){ + return $this->getFilePath($name); + } + + protected function getFilePath($name){ + return $this->dir.'/'.$name; + } +} \ No newline at end of file diff --git a/extensions/yii/twig/ViewRenderer.php b/extensions/yii/twig/ViewRenderer.php index 7483f04..09367ce 100644 --- a/extensions/yii/twig/ViewRenderer.php +++ b/extensions/yii/twig/ViewRenderer.php @@ -28,34 +28,99 @@ class ViewRenderer extends BaseViewRenderer public $cachePath = '@runtime/Twig/cache'; /** - * @var array extentions list. - */ - public $extensions = []; - - /** * @var array Twig options * @see http://twig.sensiolabs.org/doc/api.html#environment-options */ public $options = []; - /** + /** + * @var array Objects or static classes + * Keys of array are names to call in template, values - objects or names of static class as string + * Example: array('html'=>'\yii\helpers\Html') + * Than in template: {{ html.link('Login', 'site/login') }} + */ + public $globals = array(); + + /** + * @var array Custom functions + * Keys of array are names to call in template, values - names of functions or static methods of some class + * Example: array('rot13'=>'str_rot13', 'link'=>'\yii\helpers\Html::link') + * Than in template: {{ rot13('test') }} or {{ link('Login', 'site/login') }} + */ + public $functions = array(); + + /** + * @var array Custom filters + * Keys of array are names to call in template, values - names of functions or static methods of some class + * Example: array('rot13'=>'str_rot13', 'jsonEncode'=>'\yii\helpers\Json::encode') + * Then in template: {{ 'test'|rot13 }} or {{ model|jsonEncode }} + */ + public $filters = array(); + + /** + * @var array Custom extensions + * Example: array('Twig_Extension_Sandbox', 'Twig_Extension_Text') + */ + public $extensions = array(); + + /** + * @var array Twig lexer options + * @see http://twig.sensiolabs.org/doc/recipes.html#customizing-the-syntax + * Example: Smarty-like syntax + * array( + * 'tag_comment' => array('{*', '*}'), + * 'tag_block' => array('{', '}'), + * 'tag_variable' => array('{$', '}') + * ) + */ + public $lexerOptions = array(); + + /** * @var \Twig_Environment */ public $twig; public function init() { - $loader = new \Twig_Loader_String(); - $this->twig = new \Twig_Environment($loader, array_merge([ + $this->twig = new \Twig_Environment(null, array_merge([ 'cache' => Yii::getAlias($this->cachePath), + 'auto_reload' => true, + 'charset' => Yii::$app->charset, ], $this->options)); - + + // Adding custom extensions if (!empty($this->extensions)) { foreach ($this->extensions as $extension) { $this->twig->addExtension(new $extension()); } } + // Adding custom globals (objects or static classes) + if (!empty($this->globals)) { + $this->addGlobals($this->globals); + } + // Adding custom functions + if (!empty($this->functions)) { + $this->addFunctions($this->functions); + } + // Adding custom filters + if (!empty($this->filters)) { + $this->addFilters($this->filters); + } + // Adding custom extensions + if (!empty($this->extensions)) { + $this->addExtensions($this->extensions); + } + // Change lexer syntax + if (!empty($this->lexerOptions)) { + $this->setLexerOptions($this->lexerOptions); + } + + + // Adding global 'void' function (usage: {{void(App.clientScript.registerScriptFile(...))}}) + $this->twig->addFunction('void', new \Twig_Function_Function(function($argument){ + + })); $this->twig->addFunction('path', new \Twig_Function_Function(function ($path, $args = []) { return Html::url(array_merge([$path], $args)); @@ -64,6 +129,7 @@ class ViewRenderer extends BaseViewRenderer $this->twig->addGlobal('app', \Yii::$app); } + /** * Renders a view file. * @@ -79,6 +145,95 @@ class ViewRenderer extends BaseViewRenderer public function render($view, $file, $params) { $this->twig->addGlobal('this', $view); - return $this->twig->render(file_get_contents($file), $params); + $this->twig->setLoader(new TwigSimpleFileLoader(dirname($file))); + return $this->twig->render(pathinfo($file,PATHINFO_BASENAME), $params); } + + /** + * Adds global objects or static classes + * @param array $globals @see self::$globals + */ + public function addGlobals($globals) + { + foreach ($globals as $name => $value) { + if (!is_object($value)) { + $value = new ViewRendererStaticClassProxy($value); + } + $this->twig->addGlobal($name, $value); + } + } + + /** + * Adds custom functions + * @param array $functions @see self::$functions + */ + public function addFunctions($functions) + { + $this->_addCustom('Function', $functions); + } + + /** + * Adds custom filters + * @param array $filters @see self::$filters + */ + public function addFilters($filters) + { + $this->_addCustom('Filter', $filters); + } + + /** + * Adds custom extensions + * @param array $extensions @see self::$extensions + */ + public function addExtensions($extensions) + { + foreach ($extensions as $extName) { + $this->twig->addExtension(new $extName()); + } + } + + /** + * Sets Twig lexer options to change templates syntax + * @param array $options @see self::$lexerOptions + */ + public function setLexerOptions($options) + { + $lexer = new \Twig_Lexer($this->twig, $options); + $this->twig->setLexer($lexer); + } + + /** + * Adds custom function or filter + * @param string $classType 'Function' or 'Filter' + * @param array $elements Parameters of elements to add + * @throws \Exception + */ + private function _addCustom($classType, $elements) + { + $classFunction = 'Twig_'.$classType.'_Function'; + + foreach ($elements as $name => $func) { + $twigElement = null; + + switch ($func) { + // Just a name of function + case is_string($func): + $twigElement = new $classFunction($func); + break; + // Name of function + options array + case is_array($func) && is_string($func[0]) && isset($func[1]) && is_array($func[1]): + $twigElement = new $classFunction($func[0], $func[1]); + break; + } + + if ($twigElement !== null) { + $this->twig->{'add'.$classType}($name, $twigElement); + } else { + throw new \Exception(Yii::t('yiiext', + 'Incorrect options for "{classType}" [{name}]', + array('{classType}'=>$classType, '{name}'=>$name))); + } + } + } } + diff --git a/extensions/yii/twig/ViewRendererStaticClassProxy.php b/extensions/yii/twig/ViewRendererStaticClassProxy.php new file mode 100644 index 0000000..993d8a9 --- /dev/null +++ b/extensions/yii/twig/ViewRendererStaticClassProxy.php @@ -0,0 +1,37 @@ + + * @version 1.0.0 + */ +class ViewRendererStaticClassProxy +{ + private $_staticClassName; + + public function __construct($staticClassName) { + $this->_staticClassName = $staticClassName; + } + + public function __get($property) + { + $class = new \ReflectionClass($this->_staticClassName); + return $class->getStaticPropertyValue($property); + } + + public function __set($property, $value) + { + $class = new \ReflectionClass($this->_staticClassName); + $class->setStaticPropertyValue($property, $value); + return $value; + } + + public function __call($method, $arguments) + { + return call_user_func_array(array($this->_staticClassName, $method), $arguments); + } +} \ No newline at end of file From 9ea15107f468231c925c213e1c52e6f13803deb8 Mon Sep 17 00:00:00 2001 From: dev-meghraj Date: Tue, 24 Dec 2013 02:27:02 +0530 Subject: [PATCH 2/4] add old yii-ext twig renderer's function into this. and as per yii2's view system changed so for now add simple directory of file based file loader for twig --- extensions/yii/twig/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/yii/twig/CHANGELOG.md b/extensions/yii/twig/CHANGELOG.md index 85b09d5..f13ea3f 100644 --- a/extensions/yii/twig/CHANGELOG.md +++ b/extensions/yii/twig/CHANGELOG.md @@ -10,3 +10,4 @@ Yii Framework 2 twig extension Change Log ----------------------------- - Initial release. +- Add more features like in old and file based loader for twig files From eabcf1c7de8ab48f4606bf165dadc0d4d435e7a0 Mon Sep 17 00:00:00 2001 From: dev-meghraj Date: Tue, 24 Dec 2013 02:44:32 +0530 Subject: [PATCH 3/4] minor typos --- extensions/yii/twig/TwigSimpleFileLoader.php | 2 +- extensions/yii/twig/ViewRenderer.php | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/extensions/yii/twig/TwigSimpleFileLoader.php b/extensions/yii/twig/TwigSimpleFileLoader.php index af7115b..b5002dd 100644 --- a/extensions/yii/twig/TwigSimpleFileLoader.php +++ b/extensions/yii/twig/TwigSimpleFileLoader.php @@ -12,7 +12,7 @@ class TwigSimpleFileLoader implements \Twig_LoaderInterface { /** * Path to directory where all file exists - * @param $view string + * @var string */ private $dir; diff --git a/extensions/yii/twig/ViewRenderer.php b/extensions/yii/twig/ViewRenderer.php index 09367ce..e63a858 100644 --- a/extensions/yii/twig/ViewRenderer.php +++ b/extensions/yii/twig/ViewRenderer.php @@ -39,7 +39,7 @@ class ViewRenderer extends BaseViewRenderer * Example: array('html'=>'\yii\helpers\Html') * Than in template: {{ html.link('Login', 'site/login') }} */ - public $globals = array(); + public $globals = []; /** * @var array Custom functions @@ -47,7 +47,7 @@ class ViewRenderer extends BaseViewRenderer * Example: array('rot13'=>'str_rot13', 'link'=>'\yii\helpers\Html::link') * Than in template: {{ rot13('test') }} or {{ link('Login', 'site/login') }} */ - public $functions = array(); + public $functions = []; /** * @var array Custom filters @@ -55,13 +55,13 @@ class ViewRenderer extends BaseViewRenderer * Example: array('rot13'=>'str_rot13', 'jsonEncode'=>'\yii\helpers\Json::encode') * Then in template: {{ 'test'|rot13 }} or {{ model|jsonEncode }} */ - public $filters = array(); + public $filters = []; /** * @var array Custom extensions * Example: array('Twig_Extension_Sandbox', 'Twig_Extension_Text') */ - public $extensions = array(); + public $extensions = []; /** * @var array Twig lexer options @@ -73,7 +73,7 @@ class ViewRenderer extends BaseViewRenderer * 'tag_variable' => array('{$', '}') * ) */ - public $lexerOptions = array(); + public $lexerOptions = []; /** * @var \Twig_Environment From b1a1458d704d1936744a210f020fdcce90ea4725 Mon Sep 17 00:00:00 2001 From: dev-meghraj Date: Thu, 26 Dec 2013 21:47:37 +0530 Subject: [PATCH 4/4] fixes code style. --- extensions/yii/twig/CHANGELOG.md | 2 +- extensions/yii/twig/TwigSimpleFileLoader.php | 88 ++++++++---- extensions/yii/twig/ViewRenderer.php | 151 +++++++++++---------- .../yii/twig/ViewRendererStaticClassProxy.php | 43 +++--- 4 files changed, 166 insertions(+), 118 deletions(-) diff --git a/extensions/yii/twig/CHANGELOG.md b/extensions/yii/twig/CHANGELOG.md index f13ea3f..85ea863 100644 --- a/extensions/yii/twig/CHANGELOG.md +++ b/extensions/yii/twig/CHANGELOG.md @@ -5,9 +5,9 @@ Yii Framework 2 twig extension Change Log ---------------------------- - no changes in this release. +- Add File based Twig loader for better caching and usability of twig's file based function 2.0.0 alpha, December 1, 2013 ----------------------------- - Initial release. -- Add more features like in old and file based loader for twig files diff --git a/extensions/yii/twig/TwigSimpleFileLoader.php b/extensions/yii/twig/TwigSimpleFileLoader.php index b5002dd..2ffaddd 100644 --- a/extensions/yii/twig/TwigSimpleFileLoader.php +++ b/extensions/yii/twig/TwigSimpleFileLoader.php @@ -1,36 +1,76 @@ * @version 1.0.0 */ class TwigSimpleFileLoader implements \Twig_LoaderInterface { - /** - * Path to directory where all file exists - * @var string - */ - private $dir; - - public function __construct($dir){ - $this->dir=$dir; - } - - public function isFresh($name, $time){ - return filemtime($this->getFilePath($name))<=$time; - } - public function getSource($name){ - return file_get_contents($this->getFilePath($name)); - } - public function getCacheKey($name){ - return $this->getFilePath($name); - } - - protected function getFilePath($name){ - return $this->dir.'/'.$name; - } + /** + * @var string Path to directory + */ + private $_dir; + + /* + * @param @dir string path to directory + */ + public function __construct($dir) + { + $this->_dir=$dir; + } + + /** + * Compare a file's freshness with previously stored timestamp + * + * @param $name string file name to check + * @param $time int timestamp to compare with + * @return bool true if file is still fresh and not changes, false otherwise + */ + public function isFresh($name, $time) + { + return filemtime($this->getFilePath($name))<=$time; + } + + /** + * get the source of given file name + * + * @param $name string file name + * @return string contents of given file name + */ + public function getSource($name) + { + return file_get_contents($this->getFilePath($name)); + } + + /** + * get a unique key that can represent this file uniquely among other files. + * @param $name + * @return string + */ + public function getCacheKey($name) + { + return $this->getFilePath($name); + } + + /** + * internally used to get absolute path of given file name + * @param $name string file name + * @return string absolute path of file + */ + protected function getFilePath($name){ + return $this->_dir.'/'.$name; + } + } \ No newline at end of file diff --git a/extensions/yii/twig/ViewRenderer.php b/extensions/yii/twig/ViewRenderer.php index e63a858..05f66d7 100644 --- a/extensions/yii/twig/ViewRenderer.php +++ b/extensions/yii/twig/ViewRenderer.php @@ -13,6 +13,7 @@ use Yii; use yii\base\View; use yii\base\ViewRenderer as BaseViewRenderer; use yii\helpers\Html; +use yii\twig\TwigSimpleFileLoader; /** * TwigViewRenderer allows you to use Twig templates in views. @@ -76,7 +77,7 @@ class ViewRenderer extends BaseViewRenderer public $lexerOptions = []; /** - * @var \Twig_Environment + * @var \Twig_Environment twig environment object that do all rendering twig templates */ public $twig; @@ -85,40 +86,40 @@ class ViewRenderer extends BaseViewRenderer $this->twig = new \Twig_Environment(null, array_merge([ 'cache' => Yii::getAlias($this->cachePath), - 'auto_reload' => true, - 'charset' => Yii::$app->charset, + 'charset' => Yii::$app->charset, ], $this->options)); - // Adding custom extensions + // Adding custom extensions if (!empty($this->extensions)) { foreach ($this->extensions as $extension) { $this->twig->addExtension(new $extension()); } } - // Adding custom globals (objects or static classes) - if (!empty($this->globals)) { - $this->addGlobals($this->globals); - } - // Adding custom functions - if (!empty($this->functions)) { - $this->addFunctions($this->functions); - } - // Adding custom filters - if (!empty($this->filters)) { - $this->addFilters($this->filters); - } - // Adding custom extensions - if (!empty($this->extensions)) { - $this->addExtensions($this->extensions); - } - // Change lexer syntax - if (!empty($this->lexerOptions)) { - $this->setLexerOptions($this->lexerOptions); - } - - - // Adding global 'void' function (usage: {{void(App.clientScript.registerScriptFile(...))}}) - $this->twig->addFunction('void', new \Twig_Function_Function(function($argument){ + + // Adding custom globals (objects or static classes) + if (!empty($this->globals)) { + $this->addGlobals($this->globals); + } + // Adding custom functions + if (!empty($this->functions)) { + $this->addFunctions($this->functions); + } + // Adding custom filters + if (!empty($this->filters)) { + $this->addFilters($this->filters); + } + // Adding custom extensions + if (!empty($this->extensions)) { + $this->addExtensions($this->extensions); + } + // Change lexer syntax + if (!empty($this->lexerOptions)) { + $this->setLexerOptions($this->lexerOptions); + } + + + // Adding global 'void' function (usage: {{void(App.clientScript.registerScriptFile(...))}}) + $this->twig->addFunction('void', new \Twig_Function_Function(function($argument){ })); @@ -145,31 +146,31 @@ class ViewRenderer extends BaseViewRenderer public function render($view, $file, $params) { $this->twig->addGlobal('this', $view); - $this->twig->setLoader(new TwigSimpleFileLoader(dirname($file))); + $this->twig->setLoader(new TwigSimpleFileLoader(dirname($file))); return $this->twig->render(pathinfo($file,PATHINFO_BASENAME), $params); } - /** - * Adds global objects or static classes - * @param array $globals @see self::$globals - */ + /** + * Adds global objects or static classes + * @param array $globals @see self::$globals + */ public function addGlobals($globals) { - foreach ($globals as $name => $value) { - if (!is_object($value)) { - $value = new ViewRendererStaticClassProxy($value); - } - $this->twig->addGlobal($name, $value); - } + foreach ($globals as $name => $value) { + if (!is_object($value)) { + $value = new ViewRendererStaticClassProxy($value); + } + $this->twig->addGlobal($name, $value); + } } - /** - * Adds custom functions - * @param array $functions @see self::$functions - */ + /** + * Adds custom functions + * @param array $functions @see self::$functions + */ public function addFunctions($functions) { - $this->_addCustom('Function', $functions); + $this->_addCustom('Function', $functions); } /** @@ -178,7 +179,7 @@ class ViewRenderer extends BaseViewRenderer */ public function addFilters($filters) { - $this->_addCustom('Filter', $filters); + $this->_addCustom('Filter', $filters); } /** @@ -187,9 +188,9 @@ class ViewRenderer extends BaseViewRenderer */ public function addExtensions($extensions) { - foreach ($extensions as $extName) { - $this->twig->addExtension(new $extName()); - } + foreach ($extensions as $extName) { + $this->twig->addExtension(new $extName()); + } } /** @@ -198,8 +199,8 @@ class ViewRenderer extends BaseViewRenderer */ public function setLexerOptions($options) { - $lexer = new \Twig_Lexer($this->twig, $options); - $this->twig->setLexer($lexer); + $lexer = new \Twig_Lexer($this->twig, $options); + $this->twig->setLexer($lexer); } /** @@ -210,30 +211,30 @@ class ViewRenderer extends BaseViewRenderer */ private function _addCustom($classType, $elements) { - $classFunction = 'Twig_'.$classType.'_Function'; - - foreach ($elements as $name => $func) { - $twigElement = null; - - switch ($func) { - // Just a name of function - case is_string($func): - $twigElement = new $classFunction($func); - break; - // Name of function + options array - case is_array($func) && is_string($func[0]) && isset($func[1]) && is_array($func[1]): - $twigElement = new $classFunction($func[0], $func[1]); - break; - } - - if ($twigElement !== null) { - $this->twig->{'add'.$classType}($name, $twigElement); - } else { - throw new \Exception(Yii::t('yiiext', - 'Incorrect options for "{classType}" [{name}]', - array('{classType}'=>$classType, '{name}'=>$name))); - } - } - } + $classFunction = 'Twig_'.$classType.'_Function'; + + foreach ($elements as $name => $func) { + $twigElement = null; + + switch ($func) { + // Just a name of function + case is_string($func): + $twigElement = new $classFunction($func); + break; + // Name of function + options array + case is_array($func) && is_string($func[0]) && isset($func[1]) && is_array($func[1]): + $twigElement = new $classFunction($func[0], $func[1]); + break; + } + + if ($twigElement !== null) { + $this->twig->{'add'.$classType}($name, $twigElement); + } else { + throw new \Exception(Yii::t('yiiext', + 'Incorrect options for "{classType}" [{name}]', + array('{classType}'=>$classType, '{name}'=>$name))); + } + } + } } diff --git a/extensions/yii/twig/ViewRendererStaticClassProxy.php b/extensions/yii/twig/ViewRendererStaticClassProxy.php index 993d8a9..0a4a598 100644 --- a/extensions/yii/twig/ViewRendererStaticClassProxy.php +++ b/extensions/yii/twig/ViewRendererStaticClassProxy.php @@ -1,4 +1,11 @@ _staticClassName = $staticClassName; - } + $this->_staticClassName = $staticClassName; + } - public function __get($property) - { - $class = new \ReflectionClass($this->_staticClassName); - return $class->getStaticPropertyValue($property); - } + public function __get($property) + { + $class = new \ReflectionClass($this->_staticClassName); + return $class->getStaticPropertyValue($property); + } - public function __set($property, $value) - { - $class = new \ReflectionClass($this->_staticClassName); - $class->setStaticPropertyValue($property, $value); - return $value; - } + public function __set($property, $value) + { + $class = new \ReflectionClass($this->_staticClassName); + $class->setStaticPropertyValue($property, $value); + return $value; + } - public function __call($method, $arguments) - { - return call_user_func_array(array($this->_staticClassName, $method), $arguments); - } + public function __call($method, $arguments) + { + return call_user_func_array(array($this->_staticClassName, $method), $arguments); + } } \ No newline at end of file