From 1f7d142351f6981f8ceb1e31664b158cda3f2afa Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 8 Jan 2011 15:14:59 +0100 Subject: [PATCH] added callbacks for undefined functions and filters --- doc/recipes.rst | 33 +++++++++++++++++++++++++++++++++ lib/Twig/Environment.php | 26 ++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 0 deletions(-) diff --git a/doc/recipes.rst b/doc/recipes.rst index a615507..3387a35 100644 --- a/doc/recipes.rst +++ b/doc/recipes.rst @@ -208,3 +208,36 @@ The output will be similar to: In the inner loop, the ``loop.parent`` variable is used to access the outer context. So, the index of the current ``topic`` defined in the outer for loop is accessible via the ``loop.parent.loop.index`` variable. + +Define undefined Functions and Filters on the Fly +------------------------------------------------- + +When a function (or a filter) is not defined, Twig defaults to throw a +``Twig_Error_Syntax`` exception. However, it can also call a `callback`_ (any +valid PHP callable) which should return a function (or a filter). + +For filters, register callbacks with ``registerUndefinedFunctionCallback()``. +For functions, use ``registerUndefinedFunctionCallback()``:: + + // auto-register all native PHP functions as Twig functions + // don't try this at home as it's not secure at all! + $twig->registerUndefinedFunctionCallback(function ($name) { + if (function_exists($name)) { + return new Twig_Function_Function($name); + } + + return false; + }); + +If the callable is not able to return a valid function (or filter), it must +return ``false``. + +If you register more than one callback, Twig will call them in turn until one +does not return ``false``. + +.. tip:: + + As the resolution of functions and filters is done during compilation, + there is no overhead when registering these callbacks. + +.. _callback:: http://www.php.net/manual/en/function.is-callable.php diff --git a/lib/Twig/Environment.php b/lib/Twig/Environment.php index cfe92a1..ac52398 100644 --- a/lib/Twig/Environment.php +++ b/lib/Twig/Environment.php @@ -41,6 +41,8 @@ class Twig_Environment protected $unaryOperators; protected $binaryOperators; protected $templateClassPrefix = '__TwigTemplate_'; + protected $functionCallbacks; + protected $filterCallbacks; /** * Constructor. @@ -104,6 +106,8 @@ class Twig_Environment $this->strictVariables = (bool) $options['strict_variables']; $this->runtimeInitialized = false; $this->setCache($options['cache']); + $this->functionCallbacks = array(); + $this->filterCallbacks = array(); } /** @@ -673,9 +677,20 @@ class Twig_Environment return $this->filters[$name]; } + foreach ($this->filterCallbacks as $callback) { + if (false !== $filter = call_user_func($callback, $name)) { + return $filter; + } + } + return false; } + public function registerUndefinedFilterCallback($callable) + { + $this->filterCallbacks[] = $callable; + } + /** * Gets the registered Filters. * @@ -756,9 +771,20 @@ class Twig_Environment return $this->functions[$name]; } + foreach ($this->functionCallbacks as $callback) { + if (false !== $function = call_user_func($callback, $name)) { + return $function; + } + } + return false; } + public function registerUndefinedFunctionCallback($callable) + { + $this->functionCallbacks[] = $callable; + } + protected function loadFunctions() { $this->functions = array(); foreach ($this->getExtensions() as $extension) { -- 1.7.2.5