├── README.md ├── CacheExtension.php ├── CacheRuntime.php ├── composer.json ├── LICENSE ├── Node └── CacheNode.php └── TokenParser └── CacheTokenParser.php /README.md: -------------------------------------------------------------------------------- 1 | Cache Extension 2 | =============== 3 | 4 | This package is a Twig extension that provides integration with the Symfony 5 | Cache component. 6 | 7 | It provides a single [`cache`][1] tag that allows to cache template fragments. 8 | 9 | [1]: https://twig.symfony.com/cache 10 | -------------------------------------------------------------------------------- /CacheExtension.php: -------------------------------------------------------------------------------- 1 | cache = $cache; 23 | } 24 | 25 | public function getCache(): CacheInterface 26 | { 27 | return $this->cache; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "twig/cache-extra", 3 | "type": "library", 4 | "description": "A Twig extension for Symfony Cache", 5 | "keywords": ["twig", "html", "cache"], 6 | "homepage": "https://twig.symfony.com", 7 | "license": "MIT", 8 | "minimum-stability": "dev", 9 | "authors": [ 10 | { 11 | "name": "Fabien Potencier", 12 | "email": "fabien@symfony.com", 13 | "homepage": "http://fabien.potencier.org", 14 | "role": "Lead Developer" 15 | } 16 | ], 17 | "require": { 18 | "php": ">=8.1.0", 19 | "symfony/cache": "^5.4|^6.4|^7.0|^8.0", 20 | "twig/twig": "^3.21|^4.0" 21 | }, 22 | "require-dev": { 23 | "symfony/phpunit-bridge": "^6.4|^7.0" 24 | }, 25 | "autoload": { 26 | "psr-4" : { "Twig\\Extra\\Cache\\" : "" }, 27 | "exclude-from-classmap": [ 28 | "/Tests/" 29 | ] 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021-present Fabien Potencier 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Node/CacheNode.php: -------------------------------------------------------------------------------- 1 | setAttribute('raw', true); 25 | 26 | $nodes = ['key' => $key, 'body' => $body]; 27 | if (null !== $ttl) { 28 | $nodes['ttl'] = $ttl; 29 | } 30 | if (null !== $tags) { 31 | $nodes['tags'] = $tags; 32 | } 33 | 34 | parent::__construct($nodes, [], $lineno); 35 | } 36 | 37 | public function compile(Compiler $compiler): void 38 | { 39 | $compiler 40 | ->addDebugInfo($this) 41 | ->raw('$this->env->getRuntime(\'Twig\Extra\Cache\CacheRuntime\')->getCache()->get(') 42 | ->subcompile($this->getNode('key')) 43 | ->raw(", function (\Symfony\Contracts\Cache\ItemInterface \$item) use (\$context, \$macros, \$blocks) {\n") 44 | ->indent() 45 | ; 46 | 47 | if ($this->hasNode('tags')) { 48 | $compiler 49 | ->write('$item->tag(') 50 | ->subcompile($this->getNode('tags')) 51 | ->raw(");\n") 52 | ; 53 | } 54 | 55 | if ($this->hasNode('ttl')) { 56 | $compiler 57 | ->write('$item->expiresAfter(') 58 | ->subcompile($this->getNode('ttl')) 59 | ->raw(");\n") 60 | ; 61 | } 62 | 63 | $compiler 64 | ->write('return ') 65 | ->subcompile($this->getNode('body')) 66 | ->raw(";\n") 67 | ->outdent() 68 | ->write("})\n") 69 | ; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /TokenParser/CacheTokenParser.php: -------------------------------------------------------------------------------- 1 | parser->getStream(); 27 | $key = $this->parser->parseExpression(); 28 | 29 | $ttl = null; 30 | $tags = null; 31 | while ($stream->test(Token::NAME_TYPE)) { 32 | $k = $stream->getCurrent()->getValue(); 33 | if (!\in_array($k, ['ttl', 'tags'], true)) { 34 | throw new SyntaxError(\sprintf('Unknown "%s" configuration.', $k), $stream->getCurrent()->getLine(), $stream->getSourceContext()); 35 | } 36 | 37 | $stream->next(); 38 | $stream->expect(Token::OPERATOR_TYPE, '('); 39 | $line = $stream->getCurrent()->getLine(); 40 | if ($stream->test(Token::PUNCTUATION_TYPE, ')')) { 41 | throw new SyntaxError(\sprintf('The "%s" modifier takes exactly one argument (0 given).', $k), $line, $stream->getSourceContext()); 42 | } 43 | $arg = $this->parser->parseExpression(); 44 | if ($stream->test(Token::PUNCTUATION_TYPE, ',')) { 45 | throw new SyntaxError(\sprintf('The "%s" modifier takes exactly one argument (2 given).', $k), $line, $stream->getSourceContext()); 46 | } 47 | $stream->expect(Token::PUNCTUATION_TYPE, ')'); 48 | 49 | if ('ttl' === $k) { 50 | $ttl = $arg; 51 | } elseif ('tags' === $k) { 52 | $tags = $arg; 53 | } 54 | } 55 | 56 | $stream->expect(Token::BLOCK_END_TYPE); 57 | $body = $this->parser->subparse([$this, 'decideCacheEnd'], true); 58 | $stream->expect(Token::BLOCK_END_TYPE); 59 | 60 | $body = new CacheNode($key, $ttl, $tags, $body, $token->getLine()); 61 | 62 | return new PrintNode(new RawFilter($body), $token->getLine()); 63 | } 64 | 65 | public function decideCacheEnd(Token $token): bool 66 | { 67 | return $token->test('endcache'); 68 | } 69 | 70 | public function getTag(): string 71 | { 72 | return 'cache'; 73 | } 74 | } 75 | --------------------------------------------------------------------------------