Skip to content

Commit b6f6297

Browse files
authored
Custom Twig Extensions (#49)
* Adding the ability to load custom Twig Extensions * Adding Twig Extension docs and example
1 parent f402a2f commit b6f6297

File tree

6 files changed

+163
-0
lines changed

6 files changed

+163
-0
lines changed

README.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,52 @@ This tag would be used like this in a pattern:
319319
{{ name }}
320320
```
321321

322+
### Adding a custom Twig Extension
323+
324+
A [Twig Extension](https://twig.symfony.com/doc/1.x/advanced.html#creating-an-extension) is a collection of Twig functions, filters, tags, globals, and tests all as a single bundle. This approach is more advanced than adding a single function or filter using the above method, but allows greater flexibility as the whole Twig Extension can be installed in multiple environments.
325+
326+
To add a Twig Extension using the PHP class `\MyProject\MyCustomTwigExtension`, add this to `config.yml`:
327+
328+
```yml
329+
twigExtensions:
330+
- '\MyProject\MyCustomTwigExtension'
331+
```
332+
333+
What happens under the hood is basically this:
334+
335+
```php
336+
$twig = new Twig_Environment($loader);
337+
338+
foreach ($twigExtensions as $twigExtension) {
339+
$twig->addExtension(new $twigExtension());
340+
}
341+
```
342+
343+
If two Twig Extensions declare a function, filter, etc; the later ones override earlier ones. Any ones declared in Pattern Lab's `_twig-components` folder will override any declared using this method of custom Twig Extensions.
344+
345+
For an example of how this works, see `ExampleTwigExtension.php` in this repo. You can enable it by adding this to your `config.yml`:
346+
347+
```yml
348+
twigExtensions:
349+
- '\PatternLab\PatternEngine\Twig\ExampleTwigExtension'
350+
```
351+
352+
Then place this in any Twig file:
353+
354+
```twig
355+
<p>Testing: {{ testPlFunction('testing...') }}</p>
356+
```
357+
358+
That function declaration looks like this in `ExampleTwigExtension.php`:
359+
360+
```php
361+
new Twig_SimpleFunction('testPlFunction', function($arg) {
362+
return 'Thanks for testing out the Pattern Lab Example Twig Extension with this arg: ' . $arg;
363+
}),
364+
```
365+
366+
An incredible amount of exciting possibilities are enabled with this; have fun!
367+
322368
### Enable `dump()`
323369

324370
To use `dump()` set `twigDebug` in `config/config.yml` to `true`.
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<?php
2+
3+
namespace PatternLab\PatternEngine\Twig;
4+
5+
use Twig_Extension;
6+
use Twig_ExtensionInterface;
7+
use Twig_SimpleFilter;
8+
use Twig_SimpleFunction;
9+
10+
class ExampleTwigExtension extends Twig_Extension implements Twig_ExtensionInterface {
11+
12+
/**
13+
* Returns the name of the extension.
14+
*
15+
* @return string The extension name
16+
*
17+
* @deprecated since 1.26 (to be removed in 2.0), not used anymore internally
18+
*/
19+
function getName() {
20+
return 'Pattern Lab Twig ExampleTwigExtension';
21+
}
22+
23+
/**
24+
* Returns a list of filters to add to the existing list.
25+
*
26+
* @return Twig_SimpleFilter[]
27+
*/
28+
function getFilters() {
29+
return [];
30+
}
31+
32+
/**
33+
* Returns a list of functions to add to the existing list.
34+
*
35+
* @return Twig_SimpleFunction[]
36+
*/
37+
function getFunctions() {
38+
return [
39+
new Twig_SimpleFunction('testPlFunction', function($arg) {
40+
return 'Thanks for testing out the Pattern Lab Example Twig Extension with this arg: ' . $arg;
41+
}),
42+
];
43+
}
44+
45+
/**
46+
* Returns a list of operators to add to the existing list.
47+
*
48+
* @return array<array> First array of unary operators, second array of binary operators
49+
*/
50+
function getOperators() {
51+
return [];
52+
}
53+
54+
/**
55+
* Returns a list of global variables to add to the existing list.
56+
*
57+
* @return array An array of global variables
58+
*
59+
* @deprecated since 1.23 (to be removed in 2.0), implement Twig_Extension_GlobalsInterface instead
60+
*/
61+
function getGlobals() {
62+
return [
63+
'pl' => 'is awesome',
64+
];
65+
}
66+
67+
/**
68+
* Returns a list of tests to add to the existing list.
69+
*
70+
* @return Twig_SimpleTest[]
71+
*/
72+
function getTests() {
73+
return [];
74+
}
75+
/**
76+
* Returns the token parser instances to add to the existing list.
77+
*
78+
* @return (Twig_TokenParserInterface|Twig_TokenParserBrokerInterface)[]
79+
*/
80+
function getTokenParsers() {
81+
return [];
82+
}
83+
84+
/**
85+
* Returns the node visitor instances to add to the existing list.
86+
*
87+
* @return Twig_NodeVisitorInterface[]
88+
*/
89+
function getNodeVisitors() {
90+
return [];
91+
}
92+
93+
}

src/PatternLab/PatternEngine/Twig/Loaders/FilesystemLoader.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ public function __construct($options = array()) {
5050

5151
// customize Twig
5252
TwigUtil::setInstance($instance);
53+
TwigUtil::loadCustomExtensions();
5354
TwigUtil::loadFilters();
5455
TwigUtil::loadFunctions();
5556
TwigUtil::loadTags();

src/PatternLab/PatternEngine/Twig/Loaders/PatternLoader.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ public function __construct($options = array()) {
9292

9393
// customize Twig
9494
TwigUtil::setInstance($instance);
95+
TwigUtil::loadCustomExtensions();
9596
TwigUtil::loadFilters();
9697
TwigUtil::loadFunctions();
9798
TwigUtil::loadTags();

src/PatternLab/PatternEngine/Twig/Loaders/StringLoader.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ public function __construct($options = array()) {
5656

5757
// customize Twig
5858
TwigUtil::setInstance($instance);
59+
TwigUtil::loadCustomExtensions();
5960
TwigUtil::loadFilters();
6061
TwigUtil::loadFunctions();
6162
TwigUtil::loadTags();

src/PatternLab/PatternEngine/Twig/TwigUtil.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,27 @@ public static function setInstance($instance = "") {
5050

5151
}
5252

53+
/**
54+
* Load Custom Twig Extensions
55+
* Looks in config for an array of strings that are classes that can be called and implements the interface `Twig_ExtensionInterface`
56+
* Config example:
57+
* twigExtensions:
58+
* - '\MyProject\MyCustomTwigExtension'
59+
* @link https://twig.symfony.com/doc/1.x/advanced.html#creating-an-extension
60+
*/
61+
public static function loadCustomExtensions() {
62+
$twigExtensions = Config::getOption("twigExtensions");
63+
if ($twigExtensions) {
64+
foreach ($twigExtensions as $twigExtension) {
65+
if (class_exists($twigExtension)) {
66+
self::$instance->addExtension(new $twigExtension());
67+
} else {
68+
Console::writeError("Your custom Twig Extension setting isn't a PHP class that exists: `" . $twigExtension . "`");
69+
}
70+
}
71+
}
72+
}
73+
5374
/**
5475
* Get an instance of the Twig loaders
5576
*

0 commit comments

Comments
 (0)