Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 532e408

Browse 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

File tree

19 files changed

+210
-28
lines changed

19 files changed

+210
-28
lines changed

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

+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

+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

+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

+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

+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

+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

+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

+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

+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)