Skip to content

Commit 2369a98

Browse files
committed
feature #37351 [FrameworkBundle] allow enabling the HTTP cache using semantic configuration (nicolas-grekas)
This PR was merged into the 5.2-dev branch. Discussion ---------- [FrameworkBundle] allow enabling the HTTP cache using semantic configuration | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | - | License | MIT | Doc PR | - Right now, using the HTTP cache requires tweaking the `public/index.php` file [as explained in the doc](https://symfony.com/doc/current/http_cache.html). This PR removes this requirement by allowing one to do this instead: ```yaml framework: http_cache: true ``` Commits ------- 56b993ac2e [FrameworkBundle] allow enabling the HTTP cache using semantic configuration
2 parents 77ac4f8 + f7a22cd commit 2369a98

File tree

10 files changed

+141
-22
lines changed

10 files changed

+141
-22
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
5.2.0
5+
-----
6+
7+
* Added `framework.http_cache` configuration tree
8+
49
5.1.0
510
-----
611

DependencyInjection/Configuration.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ public function getConfigTreeBuilder()
9393

9494
$this->addCsrfSection($rootNode);
9595
$this->addFormSection($rootNode);
96+
$this->addHttpCacheSection($rootNode);
9697
$this->addEsiSection($rootNode);
9798
$this->addSsiSection($rootNode);
9899
$this->addFragmentsSection($rootNode);
@@ -180,6 +181,36 @@ private function addFormSection(ArrayNodeDefinition $rootNode)
180181
;
181182
}
182183

184+
private function addHttpCacheSection(ArrayNodeDefinition $rootNode)
185+
{
186+
$rootNode
187+
->children()
188+
->arrayNode('http_cache')
189+
->info('HTTP cache configuration')
190+
->canBeEnabled()
191+
->children()
192+
->booleanNode('debug')->defaultValue('%kernel.debug%')->end()
193+
->enumNode('trace_level')
194+
->values(['none', 'short', 'full'])
195+
->end()
196+
->scalarNode('trace_header')->end()
197+
->integerNode('default_ttl')->end()
198+
->arrayNode('private_headers')
199+
->performNoDeepMerging()
200+
->requiresAtLeastOneElement()
201+
->fixXmlConfig('private_header')
202+
->scalarPrototype()->end()
203+
->end()
204+
->booleanNode('allow_reload')->end()
205+
->booleanNode('allow_revalidate')->end()
206+
->integerNode('stale_while_revalidate')->end()
207+
->integerNode('stale_if_error')->end()
208+
->end()
209+
->end()
210+
->end()
211+
;
212+
}
213+
183214
private function addEsiSection(ArrayNodeDefinition $rootNode)
184215
{
185216
$rootNode

DependencyInjection/FrameworkExtension.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,7 @@ public function load(array $configs, ContainerBuilder $container)
366366

367367
$propertyInfoEnabled = $this->isConfigEnabled($container, $config['property_info']);
368368
$this->registerValidationConfiguration($config['validation'], $container, $phpLoader, $propertyInfoEnabled);
369+
$this->registerHttpCacheConfiguration($config['http_cache'], $container);
369370
$this->registerEsiConfiguration($config['esi'], $container, $phpLoader);
370371
$this->registerSsiConfiguration($config['ssi'], $container, $phpLoader);
371372
$this->registerFragmentsConfiguration($config['fragments'], $container, $phpLoader);
@@ -533,6 +534,20 @@ private function registerFormConfiguration(array $config, ContainerBuilder $cont
533534
}
534535
}
535536

537+
private function registerHttpCacheConfiguration(array $config, ContainerBuilder $container)
538+
{
539+
$options = $config;
540+
unset($options['enabled']);
541+
542+
if (!$options['private_headers']) {
543+
unset($options['private_headers']);
544+
}
545+
546+
$container->getDefinition('http_cache')
547+
->setPublic($config['enabled'])
548+
->replaceArgument(3, $options);
549+
}
550+
536551
private function registerEsiConfiguration(array $config, ContainerBuilder $container, PhpFileLoader $loader)
537552
{
538553
if (!$this->isConfigEnabled($container, $config)) {

HttpCache/HttpCache.php

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
use Symfony\Component\HttpKernel\HttpCache\Esi;
1717
use Symfony\Component\HttpKernel\HttpCache\HttpCache as BaseHttpCache;
1818
use Symfony\Component\HttpKernel\HttpCache\Store;
19+
use Symfony\Component\HttpKernel\HttpCache\StoreInterface;
20+
use Symfony\Component\HttpKernel\HttpCache\SurrogateInterface;
1921
use Symfony\Component\HttpKernel\KernelInterface;
2022

2123
/**
@@ -28,22 +30,36 @@ class HttpCache extends BaseHttpCache
2830
protected $cacheDir;
2931
protected $kernel;
3032

33+
private $store;
34+
private $surrogate;
35+
private $options;
36+
3137
/**
32-
* @param string $cacheDir The cache directory (default used if null)
38+
* @param string|StoreInterface $cache The cache directory (default used if null) or the storage instance
3339
*/
34-
public function __construct(KernelInterface $kernel, string $cacheDir = null)
40+
public function __construct(KernelInterface $kernel, $cache = null, SurrogateInterface $surrogate = null, array $options = null)
3541
{
3642
$this->kernel = $kernel;
37-
$this->cacheDir = $cacheDir;
43+
$this->surrogate = $surrogate;
44+
$this->options = $options ?? [];
45+
46+
if ($cache instanceof StoreInterface) {
47+
$this->store = $cache;
48+
} elseif (null !== $cache && !\is_string($cache)) {
49+
throw new \TypeError(sprintf('Argument 2 passed to "%s()" must be a string or a SurrogateInterface, "%s" given.', __METHOD__, get_debug_type($cache)));
50+
} else {
51+
$this->cacheDir = $cache;
52+
}
3853

39-
$isDebug = $kernel->isDebug();
40-
$options = ['debug' => $isDebug];
54+
if (null === $options && $kernel->isDebug()) {
55+
$this->options = ['debug' => true];
56+
}
4157

42-
if ($isDebug) {
43-
$options['stale_if_error'] = 0;
58+
if ($this->options['debug'] ?? false) {
59+
$this->options += ['stale_if_error' => 0];
4460
}
4561

46-
parent::__construct($kernel, $this->createStore(), $this->createSurrogate(), array_merge($options, $this->getOptions()));
62+
parent::__construct($kernel, $this->createStore(), $this->createSurrogate(), array_merge($this->options, $this->getOptions()));
4763
}
4864

4965
/**
@@ -69,11 +85,11 @@ protected function getOptions()
6985

7086
protected function createSurrogate()
7187
{
72-
return new Esi();
88+
return $this->surrogate ?? new Esi();
7389
}
7490

7591
protected function createStore()
7692
{
77-
return new Store($this->cacheDir ?: $this->kernel->getCacheDir().'/http_cache');
93+
return $this->store ?? new Store($this->cacheDir ?: $this->kernel->getCacheDir().'/http_cache');
7894
}
7995
}

Resources/config/schema/symfony-1.0.xsd

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
<xsd:element name="messenger" type="messenger" minOccurs="0" maxOccurs="1" />
3434
<xsd:element name="http-client" type="http_client" minOccurs="0" maxOccurs="1" />
3535
<xsd:element name="mailer" type="mailer" minOccurs="0" maxOccurs="1" />
36+
<xsd:element name="http-cache" type="http_cache" minOccurs="0" maxOccurs="1" />
3637
</xsd:choice>
3738

3839
<xsd:attribute name="http-method-override" type="xsd:boolean" />
@@ -576,4 +577,28 @@
576577
<xsd:element name="recipients" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
577578
</xsd:sequence>
578579
</xsd:complexType>
580+
581+
<xsd:complexType name="http_cache">
582+
<xsd:sequence>
583+
<xsd:element name="private-header" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
584+
</xsd:sequence>
585+
586+
<xsd:attribute name="enabled" type="xsd:boolean" />
587+
<xsd:attribute name="debug" type="xsd:boolean" />
588+
<xsd:attribute name="trace-level" type="http_cache_trace_levels" />
589+
<xsd:attribute name="trace-header" type="xsd:string" />
590+
<xsd:attribute name="default-ttl" type="xsd:integer" />
591+
<xsd:attribute name="allow-reload" type="xsd:boolean" />
592+
<xsd:attribute name="allow-revalidate" type="xsd:boolean" />
593+
<xsd:attribute name="stale-while-revalidate" type="xsd:integer" />
594+
<xsd:attribute name="stale-if-error" type="xsd:integer" />
595+
</xsd:complexType>
596+
597+
<xsd:simpleType name="http_cache_trace_levels">
598+
<xsd:restriction base="xsd:string">
599+
<xsd:enumeration value="none" />
600+
<xsd:enumeration value="short" />
601+
<xsd:enumeration value="full" />
602+
</xsd:restriction>
603+
</xsd:simpleType>
579604
</xsd:schema>

Resources/config/services.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
1313

1414
use Closure;
15+
use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache;
1516
use Symfony\Component\Config\Resource\SelfCheckingResourceChecker;
1617
use Symfony\Component\Config\ResourceCheckerConfigCacheFactory;
1718
use Symfony\Component\Console\Event\ConsoleCommandEvent;
@@ -46,6 +47,7 @@
4647
use Symfony\Component\HttpKernel\Event\TerminateEvent;
4748
use Symfony\Component\HttpKernel\Event\ViewEvent;
4849
use Symfony\Component\HttpKernel\EventListener\LocaleAwareListener;
50+
use Symfony\Component\HttpKernel\HttpCache\Store;
4951
use Symfony\Component\HttpKernel\HttpKernel;
5052
use Symfony\Component\HttpKernel\HttpKernelInterface;
5153
use Symfony\Component\HttpKernel\KernelInterface;
@@ -120,6 +122,20 @@
120122
->public()
121123
->alias(RequestStack::class, 'request_stack')
122124

125+
->set('http_cache', HttpCache::class)
126+
->args([
127+
service('kernel'),
128+
service('http_cache.store'),
129+
service('esi')->nullOnInvalid(),
130+
abstract_arg('options'),
131+
])
132+
->tag('container.hot_path')
133+
134+
->set('http_cache.store', Store::class)
135+
->args([
136+
param('kernel.cache_dir').'/http_cache',
137+
])
138+
123139
->set('url_helper', UrlHelper::class)
124140
->args([
125141
service('request_stack'),

Tests/DependencyInjection/ConfigurationTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,11 @@ class_exists(SemaphoreStore::class) && SemaphoreStore::isSupported() ? 'semaphor
510510
'local_dotenv_file' => '%kernel.project_dir%/.env.%kernel.environment%.local',
511511
'decryption_env_var' => 'base64:default::SYMFONY_DECRYPTION_SECRET',
512512
],
513+
'http_cache' => [
514+
'enabled' => false,
515+
'debug' => '%kernel.debug%',
516+
'private_headers' => [],
517+
],
513518
];
514519
}
515520
}

Tests/Kernel/ConcreteMicroKernel.php

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
use Symfony\Component\Config\Loader\LoaderInterface;
1818
use Symfony\Component\DependencyInjection\ContainerBuilder;
1919
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
20-
use Symfony\Component\Filesystem\Filesystem;
2120
use Symfony\Component\HttpFoundation\Response;
2221
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
2322
use Symfony\Component\HttpKernel\Kernel;
@@ -74,12 +73,6 @@ public function __wakeup()
7473
throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
7574
}
7675

77-
public function __destruct()
78-
{
79-
$fs = new Filesystem();
80-
$fs->remove($this->cacheDir);
81-
}
82-
8376
protected function configureRoutes(RoutingConfigurator $routes): void
8477
{
8578
$routes->add('halloween', '/')->controller('kernel::halloweenAction');

Tests/Kernel/MicroKernelTraitTest.php

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
2020
use Symfony\Component\DependencyInjection\Loader\ClosureLoader;
2121
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
22+
use Symfony\Component\Filesystem\Filesystem;
2223
use Symfony\Component\HttpFoundation\Request;
2324
use Symfony\Component\HttpFoundation\Response;
2425
use Symfony\Component\HttpKernel\HttpKernelInterface;
@@ -29,9 +30,21 @@
2930

3031
class MicroKernelTraitTest extends TestCase
3132
{
33+
private $kernel;
34+
35+
protected function tearDown(): void
36+
{
37+
if ($this->kernel) {
38+
$kernel = $this->kernel;
39+
$this->kernel = null;
40+
$fs = new Filesystem();
41+
$fs->remove($kernel->getCacheDir());
42+
}
43+
}
44+
3245
public function test()
3346
{
34-
$kernel = new ConcreteMicroKernel('test', false);
47+
$kernel = $this->kernel = new ConcreteMicroKernel('test', false);
3548
$kernel->boot();
3649

3750
$request = Request::create('/');
@@ -44,7 +57,7 @@ public function test()
4457

4558
public function testAsEventSubscriber()
4659
{
47-
$kernel = new ConcreteMicroKernel('test', false);
60+
$kernel = $this->kernel = new ConcreteMicroKernel('test', false);
4861
$kernel->boot();
4962

5063
$request = Request::create('/danger');
@@ -62,7 +75,7 @@ public function testRoutingRouteLoaderTagIsAdded()
6275
->willReturn('framework');
6376
$container = new ContainerBuilder();
6477
$container->registerExtension($frameworkExtension);
65-
$kernel = new ConcreteMicroKernel('test', false);
78+
$kernel = $this->kernel = new ConcreteMicroKernel('test', false);
6679
$kernel->registerContainerConfiguration(new ClosureLoader($container));
6780
$this->assertTrue($container->getDefinition('kernel')->hasTag('routing.route_loader'));
6881
}
@@ -80,7 +93,7 @@ public function testFlexStyle()
8093

8194
public function testSecretLoadedFromExtension()
8295
{
83-
$kernel = new ConcreteMicroKernel('test', false);
96+
$kernel = $this->kernel = new ConcreteMicroKernel('test', false);
8497
$kernel->boot();
8598

8699
self::assertSame('$ecret', $kernel->getContainer()->getParameter('kernel.secret'));

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
"symfony/event-dispatcher": "^5.1",
2525
"symfony/error-handler": "^4.4.1|^5.0.1",
2626
"symfony/http-foundation": "^4.4|^5.0",
27-
"symfony/http-kernel": "^5.0",
27+
"symfony/http-kernel": "^5.2",
2828
"symfony/polyfill-mbstring": "~1.0",
2929
"symfony/polyfill-php80": "^1.15",
3030
"symfony/filesystem": "^4.4|^5.0",

0 commit comments

Comments
 (0)