Skip to content

Navigation Menu

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 532e408

Browse filesBrowse files
committed
feature #54384 [TwigBundle] Use kernel.build_dir to store the templates known at build time (Okhoshi)
This PR was merged into the 7.3 branch. Discussion ---------- [TwigBundle] Use `kernel.build_dir` to store the templates known at build time | Q | A | ------------- | --- | Branch? | 7.3 | Bug fix? | no | New feature? | yes | Deprecations? | no | Issues | none | License | MIT Follow up to #50391, set up the Twig `TemplateCacheWarmer` to use the `kernel.build_dir` instead of `kernel.cache_dir`. A new argument is added to its constructor to specify the directory to use for the cache. Commits ------- 0f841d2 [TwigBundle] Use `kernel.build_dir` to store the templates known at build time
2 parents e532750 + 0f841d2 commit 532e408
Copy full SHA for 532e408

File tree

19 files changed

+210
-28
lines changed
Filter options

19 files changed

+210
-28
lines changed

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

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/TwigBundle/CHANGELOG.md
+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ CHANGELOG
77
* Enable `#[AsTwigFilter]`, `#[AsTwigFunction]` and `#[AsTwigTest]` attributes
88
to configure extensions on runtime classes
99
* Add support for a `twig` validator
10+
* Use `ChainCache` to store warmed-up cache in `kernel.build_dir` and runtime cache in `kernel.cache_dir`
11+
* Make `TemplateCacheWarmer` use `kernel.build_dir` instead of `kernel.cache_dir`
1012

1113
7.1
1214
---

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

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/TwigBundle/CacheWarmer/TemplateCacheWarmer.php
+34-10
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
use Psr\Container\ContainerInterface;
1515
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
1616
use Symfony\Contracts\Service\ServiceSubscriberInterface;
17+
use Twig\Cache\CacheInterface;
18+
use Twig\Cache\NullCache;
1719
use Twig\Environment;
1820
use Twig\Error\Error;
1921

@@ -34,26 +36,48 @@ class TemplateCacheWarmer implements CacheWarmerInterface, ServiceSubscriberInte
3436
public function __construct(
3537
private ContainerInterface $container,
3638
private iterable $iterator,
39+
private ?CacheInterface $cache = null,
3740
) {
3841
}
3942

4043
public function warmUp(string $cacheDir, ?string $buildDir = null): array
4144
{
4245
$this->twig ??= $this->container->get('twig');
4346

44-
foreach ($this->iterator as $template) {
45-
try {
46-
$this->twig->load($template);
47-
} catch (Error) {
47+
$originalCache = $this->twig->getCache();
48+
if ($originalCache instanceof NullCache) {
49+
// There's no point to warm up a cache that won't be used afterward
50+
return [];
51+
}
52+
53+
if (null !== $this->cache) {
54+
if (!$buildDir) {
4855
/*
49-
* Problem during compilation, give up for this template (e.g. syntax errors).
50-
* Failing silently here allows to ignore templates that rely on functions that aren't available in
51-
* the current environment. For example, the WebProfilerBundle shouldn't be available in the prod
52-
* environment, but some templates that are never used in prod might rely on functions the bundle provides.
53-
* As we can't detect which templates are "really" important, we try to load all of them and ignore
54-
* errors. Error checks may be performed by calling the lint:twig command.
56+
* The cache has already been warmup during the build of the container, when $buildDir was set.
5557
*/
58+
return [];
59+
}
60+
// Swap the cache for the warmup as the Twig Environment has the ChainCache injected
61+
$this->twig->setCache($this->cache);
62+
}
63+
64+
try {
65+
foreach ($this->iterator as $template) {
66+
try {
67+
$this->twig->load($template);
68+
} catch (Error) {
69+
/*
70+
* Problem during compilation, give up for this template (e.g. syntax errors).
71+
* Failing silently here allows to ignore templates that rely on functions that aren't available in
72+
* the current environment. For example, the WebProfilerBundle shouldn't be available in the prod
73+
* environment, but some templates that are never used in prod might rely on functions the bundle provides.
74+
* As we can't detect which templates are "really" important, we try to load all of them and ignore
75+
* errors. Error checks may be performed by calling the lint:twig command.
76+
*/
77+
}
5678
}
79+
} finally {
80+
$this->twig->setCache($originalCache);
5781
}
5882

5983
return [];

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

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/TwigBundle/DependencyInjection/Configuration.php
+1-1
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ private function addTwigOptions(ArrayNodeDefinition $rootNode): void
136136
->example('Twig\Template')
137137
->cannotBeEmpty()
138138
->end()
139-
->scalarNode('cache')->defaultValue('%kernel.cache_dir%/twig')->end()
139+
->scalarNode('cache')->defaultTrue()->end()
140140
->scalarNode('charset')->defaultValue('%kernel.charset%')->end()
141141
->booleanNode('debug')->defaultValue('%kernel.debug%')->end()
142142
->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
+26-4
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
use Twig\Attribute\AsTwigFilter;
3131
use Twig\Attribute\AsTwigFunction;
3232
use Twig\Attribute\AsTwigTest;
33+
use Twig\Cache\FilesystemCache;
3334
use Twig\Environment;
3435
use Twig\Extension\ExtensionInterface;
3536
use Twig\Extension\RuntimeExtensionInterface;
@@ -167,6 +168,31 @@ public function load(array $configs, ContainerBuilder $container): void
167168
}
168169
}
169170

171+
if (true === $config['cache']) {
172+
$autoReloadOrDefault = $container->getParameterBag()->resolveValue($config['auto_reload'] ?? $config['debug']);
173+
$buildDir = $container->getParameter('kernel.build_dir');
174+
$cacheDir = $container->getParameter('kernel.cache_dir');
175+
176+
if ($autoReloadOrDefault || $cacheDir === $buildDir) {
177+
$config['cache'] = '%kernel.cache_dir%/twig';
178+
}
179+
}
180+
181+
if (true === $config['cache']) {
182+
$config['cache'] = new Reference('twig.template_cache.chain');
183+
} else {
184+
$container->removeDefinition('twig.template_cache.chain');
185+
$container->removeDefinition('twig.template_cache.runtime_cache');
186+
$container->removeDefinition('twig.template_cache.readonly_cache');
187+
$container->removeDefinition('twig.template_cache.warmup_cache');
188+
189+
if (false === $config['cache']) {
190+
$container->removeDefinition('twig.template_cache_warmer');
191+
} else {
192+
$container->getDefinition('twig.template_cache_warmer')->replaceArgument(2, null);
193+
}
194+
}
195+
170196
if (isset($config['autoescape_service'])) {
171197
$config['autoescape'] = [new Reference($config['autoescape_service']), $config['autoescape_service_method'] ?? '__invoke'];
172198
} else {
@@ -191,10 +217,6 @@ public function load(array $configs, ContainerBuilder $container): void
191217
$container->registerAttributeForAutoconfiguration(AsTwigFilter::class, AttributeExtensionPass::autoconfigureFromAttribute(...));
192218
$container->registerAttributeForAutoconfiguration(AsTwigFunction::class, AttributeExtensionPass::autoconfigureFromAttribute(...));
193219
$container->registerAttributeForAutoconfiguration(AsTwigTest::class, AttributeExtensionPass::autoconfigureFromAttribute(...));
194-
195-
if (false === $config['cache']) {
196-
$container->removeDefinition('twig.template_cache_warmer');
197-
}
198220
}
199221

200222
private function getBundleTemplatePaths(ContainerBuilder $container, array $config): array

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

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/TwigBundle/Resources/config/twig.php
+19-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@
3636
use Symfony\Bundle\TwigBundle\CacheWarmer\TemplateCacheWarmer;
3737
use Symfony\Bundle\TwigBundle\DependencyInjection\Configurator\EnvironmentConfigurator;
3838
use Symfony\Bundle\TwigBundle\TemplateIterator;
39+
use Twig\Cache\ChainCache;
3940
use Twig\Cache\FilesystemCache;
41+
use Twig\Cache\ReadOnlyFilesystemCache;
4042
use Twig\Environment;
4143
use Twig\Extension\CoreExtension;
4244
use Twig\Extension\DebugExtension;
@@ -79,8 +81,24 @@
7981
->set('twig.template_iterator', TemplateIterator::class)
8082
->args([service('kernel'), abstract_arg('Twig paths'), param('twig.default_path'), abstract_arg('File name pattern')])
8183

84+
->set('twig.template_cache.runtime_cache', FilesystemCache::class)
85+
->args([param('kernel.cache_dir').'/twig'])
86+
87+
->set('twig.template_cache.readonly_cache', ReadOnlyFilesystemCache::class)
88+
->args([param('kernel.build_dir').'/twig'])
89+
90+
->set('twig.template_cache.warmup_cache', FilesystemCache::class)
91+
->args([param('kernel.build_dir').'/twig'])
92+
93+
->set('twig.template_cache.chain', ChainCache::class)
94+
->args([[service('twig.template_cache.readonly_cache'), service('twig.template_cache.runtime_cache')]])
95+
8296
->set('twig.template_cache_warmer', TemplateCacheWarmer::class)
83-
->args([service(ContainerInterface::class), service('twig.template_iterator')])
97+
->args([
98+
service(ContainerInterface::class),
99+
service('twig.template_iterator'),
100+
service('twig.template_cache.warmup_cache'),
101+
])
84102
->tag('kernel.cache_warmer')
85103
->tag('container.service_subscriber', ['id' => 'twig'])
86104

‎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
+1-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@
1010
'pi' => 3.14,
1111
'bad' => ['key' => 'foo'],
1212
],
13-
'auto_reload' => true,
14-
'cache' => '/tmp',
13+
'auto_reload' => false,
1514
'charset' => 'ISO-8859-1',
1615
'debug' => true,
1716
'strict_variables' => true,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
3+
$container->loadFromExtension('twig', [
4+
'cache' => false,
5+
]);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
3+
$container->loadFromExtension('twig', [
4+
'cache' => 'random-path',
5+
]);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?php
2+
3+
$container->loadFromExtension('twig', [
4+
'cache' => true,
5+
'auto_reload' => false,
6+
]);

‎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-1
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" cache="/tmp" charset="ISO-8859-1" debug="true" strict-variables="true">
9+
<twig:config auto-reload="true" 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-1
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" cache="/tmp" charset="ISO-8859-1" debug="true" strict-variables="true" default-path="%kernel.project_dir%/Fixtures/templates">
9+
<twig:config auto-reload="false" 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>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" ?>
2+
3+
<container xmlns="http://symfony.com/schema/dic/services"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xmlns:twig="http://symfony.com/schema/dic/twig"
6+
xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd
7+
http://symfony.com/schema/dic/twig https://symfony.com/schema/dic/twig/twig-1.0.xsd">
8+
9+
<twig:config cache="false" />
10+
</container>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" ?>
2+
3+
<container xmlns="http://symfony.com/schema/dic/services"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xmlns:twig="http://symfony.com/schema/dic/twig"
6+
xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd
7+
http://symfony.com/schema/dic/twig https://symfony.com/schema/dic/twig/twig-1.0.xsd">
8+
9+
<twig:config cache="random-path" />
10+
</container>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" ?>
2+
3+
<container xmlns="http://symfony.com/schema/dic/services"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xmlns:twig="http://symfony.com/schema/dic/twig"
6+
xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd
7+
http://symfony.com/schema/dic/twig https://symfony.com/schema/dic/twig/twig-1.0.xsd">
8+
9+
<twig:config cache="true" auto-reload="false" />
10+
</container>

‎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
+1-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ twig:
66
baz: "@@qux"
77
pi: 3.14
88
bad: {key: foo}
9-
auto_reload: true
10-
cache: /tmp
9+
auto_reload: false
1110
charset: ISO-8859-1
1211
debug: true
1312
strict_variables: true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
twig:
2+
cache: false
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
twig:
2+
cache: random-path
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
twig:
2+
cache: true
3+
auto_reload: false

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

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/TwigExtensionTest.php
+71-6
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,11 @@ public function testLoadEmptyConfiguration()
6464
}
6565

6666
/**
67-
* @dataProvider getFormats
67+
* @dataProvider getFormatsAndBuildDir
6868
*/
69-
public function testLoadFullConfiguration(string $format)
69+
public function testLoadFullConfiguration(string $format, ?string $buildDir)
7070
{
71-
$container = $this->createContainer();
71+
$container = $this->createContainer($buildDir);
7272
$container->registerExtension(new TwigExtension());
7373
$this->loadFromFile($container, 'full', $format);
7474
$this->compileContainer($container);
@@ -99,13 +99,64 @@ public function testLoadFullConfiguration(string $format)
9999

100100
// Twig options
101101
$options = $container->getDefinition('twig')->getArgument(1);
102-
$this->assertTrue($options['auto_reload'], '->load() sets the auto_reload option');
102+
$this->assertFalse($options['auto_reload'], '->load() sets the auto_reload option');
103103
$this->assertSame('name', $options['autoescape'], '->load() sets the autoescape option');
104104
$this->assertArrayNotHasKey('base_template_class', $options, '->load() does not set the base_template_class if none is provided');
105-
$this->assertEquals('/tmp', $options['cache'], '->load() sets the cache option');
106105
$this->assertEquals('ISO-8859-1', $options['charset'], '->load() sets the charset option');
107106
$this->assertTrue($options['debug'], '->load() sets the debug option');
108107
$this->assertTrue($options['strict_variables'], '->load() sets the strict_variables option');
108+
$this->assertEquals($buildDir !== null ? new Reference('twig.template_cache.chain') : '%kernel.cache_dir%/twig', $options['cache'], '->load() sets the cache option');
109+
}
110+
111+
/**
112+
* @dataProvider getFormatsAndBuildDir
113+
*/
114+
public function testLoadNoCacheConfiguration(string $format, ?string $buildDir)
115+
{
116+
$container = $this->createContainer($buildDir);
117+
$container->registerExtension(new TwigExtension());
118+
$this->loadFromFile($container, 'no-cache', $format);
119+
$this->compileContainer($container);
120+
121+
$this->assertEquals(Environment::class, $container->getDefinition('twig')->getClass(), '->load() loads the twig.xml file');
122+
123+
// Twig options
124+
$options = $container->getDefinition('twig')->getArgument(1);
125+
$this->assertFalse($options['cache'], '->load() sets cache option to false');
126+
}
127+
128+
/**
129+
* @dataProvider getFormatsAndBuildDir
130+
*/
131+
public function testLoadPathCacheConfiguration(string $format, ?string $buildDir)
132+
{
133+
$container = $this->createContainer($buildDir);
134+
$container->registerExtension(new TwigExtension());
135+
$this->loadFromFile($container, 'path-cache', $format);
136+
$this->compileContainer($container);
137+
138+
$this->assertEquals(Environment::class, $container->getDefinition('twig')->getClass(), '->load() loads the twig.xml file');
139+
140+
// Twig options
141+
$options = $container->getDefinition('twig')->getArgument(1);
142+
$this->assertSame('random-path', $options['cache'], '->load() sets cache option to string path');
143+
}
144+
145+
/**
146+
* @dataProvider getFormatsAndBuildDir
147+
*/
148+
public function testLoadProdCacheConfiguration(string $format, ?string $buildDir)
149+
{
150+
$container = $this->createContainer($buildDir);
151+
$container->registerExtension(new TwigExtension());
152+
$this->loadFromFile($container, 'prod-cache', $format);
153+
$this->compileContainer($container);
154+
155+
$this->assertEquals(Environment::class, $container->getDefinition('twig')->getClass(), '->load() loads the twig.xml file');
156+
157+
// Twig options
158+
$options = $container->getDefinition('twig')->getArgument(1);
159+
$this->assertEquals($buildDir !== null ? new Reference('twig.template_cache.chain') : '%kernel.cache_dir%/twig', $options['cache'], '->load() sets cache option to CacheChain reference');
109160
}
110161

111162
/**
@@ -245,6 +296,19 @@ public static function getFormats(): array
245296
];
246297
}
247298

299+
public static function getFormatsAndBuildDir(): array
300+
{
301+
return [
302+
['php', null],
303+
['php', __DIR__.'/build'],
304+
['yml', null],
305+
['yml', __DIR__.'/build'],
306+
['xml', null],
307+
['xml', __DIR__.'/build'],
308+
];
309+
}
310+
311+
248312
/**
249313
* @dataProvider stopwatchExtensionAvailabilityProvider
250314
*/
@@ -319,10 +383,11 @@ public function testCustomHtmlToTextConverterService(string $format)
319383
$this->assertEquals(new Reference('my_converter'), $bodyRenderer->getArgument('$converter'));
320384
}
321385

322-
private function createContainer(): ContainerBuilder
386+
private function createContainer(?string $buildDir = null): ContainerBuilder
323387
{
324388
$container = new ContainerBuilder(new ParameterBag([
325389
'kernel.cache_dir' => __DIR__,
390+
'kernel.build_dir' => $buildDir ?? __DIR__,
326391
'kernel.project_dir' => __DIR__,
327392
'kernel.charset' => 'UTF-8',
328393
'kernel.debug' => false,

0 commit comments

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