Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 95b994c

Browse filesBrowse files
committed
[TwigBundle] Use kernel.build_dir to store the templates known at build time
Signed-off-by: Quentin Devos <4972091+Okhoshi@users.noreply.github.com>
1 parent b5ee977 commit 95b994c
Copy full SHA for 95b994c

File tree

13 files changed

+155
-14
lines changed
Filter options

13 files changed

+155
-14
lines changed

‎src/Symfony/Bundle/TwigBundle/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/TwigBundle/CHANGELOG.md
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ CHANGELOG
55
---
66

77
* Mark class `TemplateCacheWarmer` as `final`
8+
* Create `ChainCache` to store warmed-up cache in `kernel.build_dir` and runtime cache in `cache_dir`
9+
* Make `TemplateCacheWarmer` use `kernel.build_dir` instead of `cache_dir`
810

911
7.0
1012
---
+83Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\TwigBundle\Cache;
13+
14+
use Twig\Cache\CacheInterface;
15+
16+
/**
17+
* Chains several caches together.
18+
*
19+
* Cached items are fetched from the first cache having them in its data store.
20+
* They are saved and deleted in all adapters at once.
21+
*/
22+
class ChainCache implements CacheInterface
23+
{
24+
/**
25+
* @param CacheInterface[] $caches The ordered list of caches used to store and fetch cached items
26+
*/
27+
public function __construct(private array $caches)
28+
{
29+
if (!$caches) {
30+
throw new \InvalidArgumentException('At least one cache must be specified.');
31+
}
32+
33+
foreach ($caches as $cache) {
34+
if (!$cache instanceof CacheInterface) {
35+
throw new \InvalidArgumentException(sprintf('The class "%s" does not implement the "%s" interface.', get_debug_type($cache), CacheInterface::class));
36+
}
37+
}
38+
}
39+
40+
public function generateKey(string $name, string $className): string
41+
{
42+
return $name.'#'.$className;
43+
}
44+
45+
public function write(string $key, string $content): void
46+
{
47+
foreach ($this->caches as $cache) {
48+
[$name, $className] = explode('#', $key, 2);
49+
50+
$cacheKey = $cache->generateKey($name, $className);
51+
$cache->write($cacheKey, $content);
52+
}
53+
}
54+
55+
public function load(string $key): void
56+
{
57+
foreach ($this->caches as $cache) {
58+
[$name, $className] = explode('#', $key, 2);
59+
60+
$cacheKey = $cache->generateKey($name, $className);
61+
$cache->load($cacheKey);
62+
63+
if (class_exists($className, false)) {
64+
break;
65+
}
66+
}
67+
}
68+
69+
public function getTimestamp(string $key): int
70+
{
71+
foreach ($this->caches as $cache) {
72+
[$name, $className] = explode('#', $key, 2);
73+
74+
$cacheKey = $cache->generateKey($name, $className);
75+
$timestamp = $cache->getTimestamp($cacheKey);
76+
if ($timestamp > 0) {
77+
return $timestamp;
78+
}
79+
}
80+
81+
return 0;
82+
}
83+
}
+25Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\TwigBundle\Cache;
13+
14+
use Twig\Cache\FilesystemCache;
15+
16+
/**
17+
* Implements a cache on the filesystem that can only be read, not written to.
18+
*/
19+
class ReadOnlyFilesystemCache extends FilesystemCache
20+
{
21+
public function write(string $key, string $content): void
22+
{
23+
// Do nothing with the content, it's a read-only filesystem.
24+
}
25+
}

‎src/Symfony/Bundle/TwigBundle/CacheWarmer/TemplateCacheWarmer.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/TwigBundle/CacheWarmer/TemplateCacheWarmer.php
+13-6Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,26 @@
2626
*/
2727
class TemplateCacheWarmer implements CacheWarmerInterface, ServiceSubscriberInterface
2828
{
29-
private ContainerInterface $container;
3029
private Environment $twig;
31-
private iterable $iterator;
3230

33-
public function __construct(ContainerInterface $container, iterable $iterator)
31+
public function __construct(private ContainerInterface $container, private iterable $iterator, private string $cacheFolder = 'twig')
3432
{
35-
// As this cache warmer is optional, dependencies should be lazy-loaded, that's why a container should be injected.
36-
$this->container = $container;
37-
$this->iterator = $iterator;
33+
if (\func_num_args() < 3) {
34+
trigger_deprecation('symfony/twig-bundle', '7.1', 'The "string $cacheFolder" argument of "%s()" method will not be optional anymore in version 8.0, not defining it is deprecated.', __METHOD__);
35+
}
3836
}
3937

4038
public function warmUp(string $cacheDir, ?string $buildDir = null): array
4139
{
40+
if (!$buildDir) {
41+
return [];
42+
}
43+
4244
$this->twig ??= $this->container->get('twig');
4345

46+
$originalCache = $this->twig->getCache();
47+
$this->twig->setCache($buildDir.\DIRECTORY_SEPARATOR.$this->cacheFolder);
48+
4449
foreach ($this->iterator as $template) {
4550
try {
4651
$this->twig->load($template);
@@ -56,6 +61,8 @@ public function warmUp(string $cacheDir, ?string $buildDir = null): array
5661
}
5762
}
5863

64+
$this->twig->setCache($originalCache);
65+
5966
return [];
6067
}
6168

‎src/Symfony/Bundle/TwigBundle/DependencyInjection/Configuration.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/TwigBundle/DependencyInjection/Configuration.php
+3-1Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,9 @@ private function addTwigOptions(ArrayNodeDefinition $rootNode): void
130130
->scalarNode('autoescape_service')->defaultNull()->end()
131131
->scalarNode('autoescape_service_method')->defaultNull()->end()
132132
->scalarNode('base_template_class')->example('Twig\Template')->cannotBeEmpty()->end()
133-
->scalarNode('cache')->defaultValue('%kernel.cache_dir%/twig')->end()
133+
->scalarNode('cache')
134+
->setDeprecated('symfony/twig-bundle', '7.1', 'Setting the "%path%.%node%" configuration option is deprecated. It will be removed in version 8.0.')
135+
->end()
134136
->scalarNode('charset')->defaultValue('%kernel.charset%')->end()
135137
->booleanNode('debug')->defaultValue('%kernel.debug%')->end()
136138
->booleanNode('strict_variables')->defaultValue('%kernel.debug%')->end()

‎src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php
+12Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use Symfony\Component\Translation\LocaleSwitcher;
2626
use Symfony\Component\Translation\Translator;
2727
use Symfony\Contracts\Service\ResetInterface;
28+
use Twig\Cache\FilesystemCache;
2829
use Twig\Extension\ExtensionInterface;
2930
use Twig\Extension\RuntimeExtensionInterface;
3031
use Twig\Loader\LoaderInterface;
@@ -153,6 +154,17 @@ public function load(array $configs, ContainerBuilder $container): void
153154
}
154155
}
155156

157+
if (!isset($config['cache'])) {
158+
$config['cache'] = new Reference('twig.template_cache.chain');
159+
160+
$cacheOptions = ($config['auto_reload'] ?? false) ? FilesystemCache::FORCE_BYTECODE_INVALIDATION : 0;
161+
$container->getDefinition('twig.template_cache.runtime_cache')->replaceArgument(1, $cacheOptions);
162+
} else {
163+
$container->removeDefinition('twig.template_cache.chain');
164+
$container->removeDefinition('twig.template_cache.runtime_cache');
165+
$container->removeDefinition('twig.template_cache.readonly_cache');
166+
}
167+
156168
if (isset($config['autoescape_service'])) {
157169
$config['autoescape'] = [new Reference($config['autoescape_service']), $config['autoescape_service_method'] ?? '__invoke'];
158170
} else {

‎src/Symfony/Bundle/TwigBundle/Resources/config/twig.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/TwigBundle/Resources/config/twig.php
+12-1Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
use Symfony\Bridge\Twig\Extension\WorkflowExtension;
3333
use Symfony\Bridge\Twig\Extension\YamlExtension;
3434
use Symfony\Bridge\Twig\Translation\TwigExtractor;
35+
use Symfony\Bundle\TwigBundle\Cache\ChainCache;
36+
use Symfony\Bundle\TwigBundle\Cache\ReadOnlyFilesystemCache;
3537
use Symfony\Bundle\TwigBundle\CacheWarmer\TemplateCacheWarmer;
3638
use Symfony\Bundle\TwigBundle\DependencyInjection\Configurator\EnvironmentConfigurator;
3739
use Symfony\Bundle\TwigBundle\TemplateIterator;
@@ -78,8 +80,17 @@
7880
->set('twig.template_iterator', TemplateIterator::class)
7981
->args([service('kernel'), abstract_arg('Twig paths'), param('twig.default_path'), abstract_arg('File name pattern')])
8082

83+
->set('twig.template_cache.runtime_cache', FilesystemCache::class)
84+
->args([param('kernel.cache_dir').'/twig', abstract_arg('Twig filesystem cache options')])
85+
86+
->set('twig.template_cache.readonly_cache', ReadOnlyFilesystemCache::class)
87+
->args([param('kernel.build_dir').'/twig'])
88+
89+
->set('twig.template_cache.chain', ChainCache::class)
90+
->args([[service('twig.template_cache.runtime_cache'), service('twig.template_cache.readonly_cache')]])
91+
8192
->set('twig.template_cache_warmer', TemplateCacheWarmer::class)
82-
->args([service(ContainerInterface::class), service('twig.template_iterator')])
93+
->args([service(ContainerInterface::class), service('twig.template_iterator'), 'twig'])
8394
->tag('kernel.cache_warmer')
8495
->tag('container.service_subscriber', ['id' => 'twig'])
8596

‎src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/php/full.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/php/full.php
-1Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
],
1313
'auto_reload' => true,
1414
'base_template_class' => 'stdClass',
15-
'cache' => '/tmp',
1615
'charset' => 'ISO-8859-1',
1716
'debug' => true,
1817
'strict_variables' => true,

‎src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/xml/extra.xml

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/xml/extra.xml
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd
77
http://symfony.com/schema/dic/twig https://symfony.com/schema/dic/twig/twig-1.0.xsd">
88

9-
<twig:config auto-reload="true" base-template-class="stdClass" cache="/tmp" charset="ISO-8859-1" debug="true" strict-variables="true">
9+
<twig:config auto-reload="true" base-template-class="stdClass" charset="ISO-8859-1" debug="true" strict-variables="true">
1010
<twig:path namespace="namespace3">namespaced_path3</twig:path>
1111
</twig:config>
1212
</container>

‎src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/xml/full.xml

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/xml/full.xml
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd
77
http://symfony.com/schema/dic/twig https://symfony.com/schema/dic/twig/twig-1.0.xsd">
88

9-
<twig:config auto-reload="true" base-template-class="stdClass" cache="/tmp" charset="ISO-8859-1" debug="true" strict-variables="true" default-path="%kernel.project_dir%/Fixtures/templates">
9+
<twig:config auto-reload="true" base-template-class="stdClass" charset="ISO-8859-1" debug="true" strict-variables="true" default-path="%kernel.project_dir%/Fixtures/templates">
1010
<twig:form-theme>MyBundle::form.html.twig</twig:form-theme>
1111
<twig:global key="foo" id="bar" type="service" />
1212
<twig:global key="baz">@@qux</twig:global>

‎src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/yml/full.yml

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Fixtures/yml/full.yml
-1Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ twig:
88
bad: {key: foo}
99
auto_reload: true
1010
base_template_class: stdClass
11-
cache: /tmp
1211
charset: ISO-8859-1
1312
debug: true
1413
strict_variables: true

‎src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/TwigExtensionTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/TwigExtensionTest.php
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public function testLoadEmptyConfiguration()
4444

4545
// Twig options
4646
$options = $container->getDefinition('twig')->getArgument(1);
47-
$this->assertEquals('%kernel.cache_dir%/twig', $options['cache'], '->load() sets default value for cache option');
47+
$this->assertEquals(new Reference('twig.template_cache.chain'), $options['cache'], '->load() sets default value for cache option');
4848
$this->assertEquals('%kernel.charset%', $options['charset'], '->load() sets default value for charset option');
4949
$this->assertEquals('%kernel.debug%', $options['debug'], '->load() sets default value for debug option');
5050

@@ -92,7 +92,7 @@ public function testLoadFullConfiguration($format)
9292
$this->assertTrue($options['auto_reload'], '->load() sets the auto_reload option');
9393
$this->assertSame('name', $options['autoescape'], '->load() sets the autoescape option');
9494
$this->assertEquals('stdClass', $options['base_template_class'], '->load() sets the base_template_class option');
95-
$this->assertEquals('/tmp', $options['cache'], '->load() sets the cache option');
95+
$this->assertEquals(new Reference('twig.template_cache.chain'), $options['cache'], '->load() sets the cache option');
9696
$this->assertEquals('ISO-8859-1', $options['charset'], '->load() sets the charset option');
9797
$this->assertTrue($options['debug'], '->load() sets the debug option');
9898
$this->assertTrue($options['strict_variables'], '->load() sets the strict_variables option');

‎src/Symfony/Bundle/TwigBundle/composer.json

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/TwigBundle/composer.json
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"composer-runtime-api": ">=2.1",
2121
"symfony/config": "^6.4|^7.0",
2222
"symfony/dependency-injection": "^6.4|^7.0",
23+
"symfony/deprecation-contracts": "^2.5|^3",
2324
"symfony/twig-bridge": "^6.4|^7.0",
2425
"symfony/http-foundation": "^6.4|^7.0",
2526
"symfony/http-kernel": "^6.4|^7.0",

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.