123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- Creating a Twig Extension
- =========================
-
- The main motivation for writing an extension is to move often used code into a
- reusable class like adding support for internationalization. An extension can
- define tags, filters, tests, operators, global variables, functions, and node
- visitors.
-
- Creating an extension also makes for a better separation of code that is
- executed at compilation time and code needed at runtime. As such, it makes
- your code faster.
-
- Most of the time, it is useful to create a single extension for your project,
- to host all the specific tags and filters you want to add to Twig.
-
- .. note::
-
- Before writing your own extensions, have a look at the Twig official
- extension repository: http://github.com/fabpot/Twig-extensions.
-
- An extension is a class that implements the following interface::
-
- interface Twig_ExtensionInterface
- {
- /**
- * Initializes the runtime environment.
- *
- * This is where you can load some file that contains filter functions for instance.
- *
- * @param Twig_Environment $environment The current Twig_Environment instance
- */
- function initRuntime(Twig_Environment $environment);
-
- /**
- * Returns the token parser instances to add to the existing list.
- *
- * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
- */
- function getTokenParsers();
-
- /**
- * Returns the node visitor instances to add to the existing list.
- *
- * @return array An array of Twig_NodeVisitorInterface instances
- */
- function getNodeVisitors();
-
- /**
- * Returns a list of filters to add to the existing list.
- *
- * @return array An array of filters
- */
- function getFilters();
-
- /**
- * Returns a list of tests to add to the existing list.
- *
- * @return array An array of tests
- */
- function getTests();
-
- /**
- * Returns a list of functions to add to the existing list.
- *
- * @return array An array of functions
- */
- function getFunctions();
-
- /**
- * Returns a list of operators to add to the existing list.
- *
- * @return array An array of operators
- */
- function getOperators();
-
- /**
- * Returns a list of global variables to add to the existing list.
- *
- * @return array An array of global variables
- */
- function getGlobals();
-
- /**
- * Returns the name of the extension.
- *
- * @return string The extension name
- */
- function getName();
- }
-
- To keep your extension class clean and lean, it can inherit from the built-in
- ``Twig_Extension`` class instead of implementing the whole interface. That
- way, you just need to implement the ``getName()`` method as the
- ``Twig_Extension`` provides empty implementations for all other methods.
-
- The ``getName()`` method must return a unique identifier for your extension.
-
- Now, with this information in mind, let's create the most basic extension
- possible::
-
- class Project_Twig_Extension extends Twig_Extension
- {
- public function getName()
- {
- return 'project';
- }
- }
-
- .. note::
-
- Of course, this extension does nothing for now. We will customize it in
- the next sections.
-
- Twig does not care where you save your extension on the filesystem, as all
- extensions must be registered explicitly to be available in your templates.
-
- You can register an extension by using the ``addExtension()`` method on your
- main ``Environment`` object::
-
- $twig = new Twig_Environment($loader);
- $twig->addExtension(new Project_Twig_Extension());
-
- Of course, you need to first load the extension file by either using
- ``require_once()`` or by using an autoloader (see `spl_autoload_register()`_).
-
- .. tip::
-
- The bundled extensions are great examples of how extensions work.
-
- Globals
- -------
-
- Global variables can be registered in an extension via the ``getGlobals()``
- method::
-
- class Project_Twig_Extension extends Twig_Extension
- {
- public function getGlobals()
- {
- return array(
- 'text' => new Text(),
- );
- }
-
- // ...
- }
-
- Functions
- ---------
-
- Functions can be registered in an extension via the ``getFunctions()``
- method::
-
- class Project_Twig_Extension extends Twig_Extension
- {
- public function getFunctions()
- {
- return array(
- 'lipsum' => new Twig_Function_Function('generate_lipsum'),
- );
- }
-
- // ...
- }
-
- Filters
- -------
-
- To add a filter to an extension, you need to override the ``getFilters()``
- method. This method must return an array of filters to add to the Twig
- environment::
-
- class Project_Twig_Extension extends Twig_Extension
- {
- public function getFilters()
- {
- return array(
- 'rot13' => new Twig_Filter_Function('str_rot13'),
- );
- }
-
- // ...
- }
-
- As you can see in the above code, the ``getFilters()`` method returns an array
- where keys are the name of the filters (``rot13``) and the values the
- definition of the filter (``new Twig_Filter_Function('str_rot13')``).
-
- As seen in the previous chapter, you can also define filters as static methods
- on the extension class::
-
- $twig->addFilter('rot13', new Twig_Filter_Function('Project_Twig_Extension::rot13Filter'));
-
- You can also use ``Twig_Filter_Method`` instead of ``Twig_Filter_Function``
- when defining a filter to use a method::
-
- class Project_Twig_Extension extends Twig_Extension
- {
- public function getFilters()
- {
- return array(
- 'rot13' => new Twig_Filter_Method($this, 'rot13Filter'),
- );
- }
-
- public function rot13Filter($string)
- {
- return str_rot13($string);
- }
-
- // ...
- }
-
- The first argument of the ``Twig_Filter_Method`` constructor is always
- ``$this``, the current extension object. The second one is the name of the
- method to call.
-
- Using methods for filters is a great way to package your filter without
- polluting the global namespace. This also gives the developer more flexibility
- at the cost of a small overhead.
-
- Overriding default Filters
- ~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- If some default core filters do not suit your needs, you can easily override
- them by creating your own core extension. Of course, you don't need to copy
- and paste the whole core extension code of Twig. Instead, you can just extends
- it and override the filter(s) you want by overriding the ``getFilters()``
- method::
-
- class MyCoreExtension extends Twig_Extension_Core
- {
- public function getFilters()
- {
- return array_merge(parent::getFilters(), array(
- 'date' => new Twig_Filter_Method($this, 'dateFilter'),
- // ...
- ));
- }
-
- public function dateFilter($timestamp, $format = 'F j, Y H:i')
- {
- return '...'.twig_date_format_filter($timestamp, $format);
- }
-
- // ...
- }
-
- Here, we override the ``date`` filter with a custom one. Using this new core
- extension is as simple as registering the ``MyCoreExtension`` extension by
- calling the ``addExtension()`` method on the environment instance::
-
- $twig = new Twig_Environment($loader);
- $twig->addExtension(new MyCoreExtension());
-
- But I can already hear some people wondering how it can work as the Core
- extension is loaded by default. That's true, but the trick is that both
- extensions share the same unique identifier (``core`` - defined in the
- ``getName()`` method). By registering an extension with the same name as an
- existing one, you have actually overridden the default one, even if it is
- already registered::
-
- $twig->addExtension(new Twig_Extension_Core());
- $twig->addExtension(new MyCoreExtension());
-
- Tags
- ----
-
- Adding a tag in an extension can be done by overriding the
- ``getTokenParsers()`` method. This method must return an array of tags to add
- to the Twig environment::
-
- class Project_Twig_Extension extends Twig_Extension
- {
- public function getTokenParsers()
- {
- return array(new Project_Set_TokenParser());
- }
-
- // ...
- }
-
- In the above code, we have added a single new tag, defined by the
- ``Project_Set_TokenParser`` class. The ``Project_Set_TokenParser`` class is
- responsible for parsing the tag and compiling it to PHP.
-
- Operators
- ---------
-
- The ``getOperators()`` methods allows to add new operators. Here is how to add
- ``!``, ``||``, and ``&&`` operators::
-
- class Project_Twig_Extension extends Twig_Extension
- {
- public function getOperators()
- {
- return array(
- array(
- '!' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Not'),
- ),
- array(
- '||' => array('precedence' => 10, 'class' => 'Twig_Node_Expression_Binary_Or', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
- '&&' => array('precedence' => 15, 'class' => 'Twig_Node_Expression_Binary_And', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
- ),
- );
- }
-
- // ...
- }
-
- Tests
- -----
-
- The ``getTests()`` methods allows to add new test functions::
-
- class Project_Twig_Extension extends Twig_Extension
- {
- public function getTests()
- {
- return array(
- 'even' => new Twig_Test_Function('twig_test_even'),
- );
- }
-
- // ...
- }
-
- .. _`spl_autoload_register()`: http://www.php.net/spl_autoload_register
|