From 56c73827750e6e0f5d94a290e8f00a9a8f48e459 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 18 Aug 2015 10:14:17 +0200 Subject: [PATCH] added Twig_Util_DeprecationCollector to collect deprecation notices for a set of templates --- doc/recipes.rst | 45 ++++++++++---- lib/Twig/Util/DeprecationCollector.php | 82 ++++++++++++++++++++++++++ lib/Twig/Util/TemplateDirIterator.php | 26 ++++++++ 3 files changed, 141 insertions(+), 12 deletions(-) create mode 100644 lib/Twig/Util/DeprecationCollector.php create mode 100644 lib/Twig/Util/TemplateDirIterator.php diff --git a/doc/recipes.rst b/doc/recipes.rst index 36c669d4e8..b863e103c7 100644 --- a/doc/recipes.rst +++ b/doc/recipes.rst @@ -6,9 +6,37 @@ Recipes Displaying Deprecation Notices ------------------------------ +.. versionadded:: 1.21 + This works as of Twig 1.21. + Deprecated features generate deprecation notices (via a call to the -``trigger_error()`` PHP function). By default, they are silenced, but you can -easily display them by registering a custom error handler like the one below:: +``trigger_error()`` PHP function). By default, they are silenced and never +displayed nor logged. + +To easily remove all deprecated feature usages from your templates, write and +run a script along the lines of the following:: + + require_once __DIR__.'/vendor/autoload.php'; + + $twig = create_your_twig_env(); + + $deprecations = new Twig_Util_DeprecationCollector($twig); + + print_r($deprecations->collectDir(__DIR__.'/templates')); + +The ``collectDir()`` method compiles all templates found in a directory, +catches deprecation notices, and return them. + +.. tip:: + + If your templates are not stored on the filesystem, use the ``collect()`` + method instead which takes an ``Iterator``; the iterator must return + template names as keys and template contents as values (as done by + ``Twig_Util_TemplateDirIterator``). + +However, this code won't find all deprecations (like using deprecated some Twig +classes). To catch all notices, register a custom error handler like the one +below:: $deprecations = array(); set_error_handler(function ($type, $msg) use (&$deprecations) { @@ -17,19 +45,12 @@ easily display them by registering a custom error handler like the one below:: } }); - try { - $twig->compile($twig->parse($twig->tokenize($template))); - } catch (Twig_Error_Syntax $e) { - // $template contains one or more syntax errors - } + // run your application print_r($deprecations); -Compile all templates with such an error handler in a script to easily remove -all deprecated feature usages from your templates. - -You must be aware that most deprecation notices are triggered during -**compilation**, so they won't be generated when templates are already cached. +Note that most deprecation notices are triggered during **compilation**, so +they won't be generated when templates are already cached. .. tip:: diff --git a/lib/Twig/Util/DeprecationCollector.php b/lib/Twig/Util/DeprecationCollector.php new file mode 100644 index 0000000000..e406f0aa71 --- /dev/null +++ b/lib/Twig/Util/DeprecationCollector.php @@ -0,0 +1,82 @@ + + */ +class Twig_Util_DeprecationCollector +{ + private $twig; + private $deprecations; + + public function __construct(Twig_Environment $twig) + { + $this->twig = $twig; + } + + /** + * Returns deprecations for templates contained in a directory. + * + * @param string $dir A directory where templates are stored + * @param string $ext Limit the loaded templates by extension + * + * @return array() An array of deprecations + */ + public function collectDir($dir, $ext = '.twig') + { + $iterator = new RegexIterator( + new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($dir), RecursiveIteratorIterator::LEAVES_ONLY + ), '{'.preg_quote($ext).'$}' + ); + + return $this->collect(new Twig_Util_TemplateDirIterator($iterator)); + } + + /** + * Returns deprecations for passed templates. + * + * @param Iterator $iterator An iterator of templates (where keys are template names and values the contents of the template) + * + * @return array() An array of deprecations + */ + public function collect(Iterator $iterator) + { + $this->deprecations = array(); + + set_error_handler(array($this, 'errorHandler')); + + foreach ($iterator as $name => $contents) { + try { + $this->twig->parse($this->twig->tokenize($contents, $name)); + } catch (Twig_Error_Syntax $e) { + // ignore templates containing syntax errors + } + } + + restore_error_handler(); + + $deprecations = $this->deprecations; + $this->deprecations = array(); + + return $deprecations; + } + + /** + * @internal + */ + public function errorHandler($type, $msg) + { + if (E_USER_DEPRECATED === $type) { + $this->deprecations[] = $msg; + } + } +} diff --git a/lib/Twig/Util/TemplateDirIterator.php b/lib/Twig/Util/TemplateDirIterator.php new file mode 100644 index 0000000000..3fb8932780 --- /dev/null +++ b/lib/Twig/Util/TemplateDirIterator.php @@ -0,0 +1,26 @@ + + */ +class Twig_Util_TemplateDirIterator extends IteratorIterator +{ + public function current() + { + return file_get_contents(parent::current()); + } + + public function key() + { + return (string) parent::key(); + } +}