Skip to content

Commit 2c7a861

Browse files
authored
Merge pull request #2650 from teohhanhui/fix/metadata-cache-in-dev
Add a cache warmer to clear cache pools in dev
2 parents 637d85d + b8d22f8 commit 2c7a861

File tree

5 files changed

+154
-23
lines changed

5 files changed

+154
-23
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
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+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Core\Bridge\Symfony\Bundle\CacheWarmer;
15+
16+
use Symfony\Component\HttpKernel\CacheClearer\Psr6CacheClearer;
17+
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
18+
19+
/**
20+
* Clears the cache pools when warming up the cache.
21+
*
22+
* Do not use in production!
23+
*
24+
* @internal
25+
*/
26+
final class CachePoolClearerCacheWarmer implements CacheWarmerInterface
27+
{
28+
private $poolClearer;
29+
private $pools;
30+
31+
public function __construct(Psr6CacheClearer $poolClearer, array $pools = [])
32+
{
33+
$this->poolClearer = $poolClearer;
34+
$this->pools = $pools;
35+
}
36+
37+
/**
38+
* {@inheritdoc}
39+
*/
40+
public function warmUp($cacheDirectory): void
41+
{
42+
foreach ($this->pools as $pool) {
43+
if ($this->poolClearer->hasPool($pool)) {
44+
$this->poolClearer->clearPool($pool);
45+
}
46+
}
47+
}
48+
49+
/**
50+
* {@inheritdoc}
51+
*/
52+
public function isOptional(): bool
53+
{
54+
// optional cache warmers are not run when handling the request
55+
return false;
56+
}
57+
}

src/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -436,17 +436,27 @@ private function registerBundlesConfiguration(array $bundles, array $config, Xml
436436
*/
437437
private function registerCacheConfiguration(ContainerBuilder $container)
438438
{
439-
// Don't use system cache pool in dev
440-
if ($container->hasParameter('api_platform.metadata_cache') ? $container->getParameter('api_platform.metadata_cache') : !$container->getParameter('kernel.debug')) {
439+
if (!$container->hasParameter('kernel.debug') || !$container->getParameter('kernel.debug')) {
440+
$container->removeDefinition('api_platform.cache_warmer.cache_pool_clearer');
441+
}
442+
443+
if (!$container->hasParameter('api_platform.metadata_cache')) {
441444
return;
442445
}
443446

444-
$container->register('api_platform.cache.metadata.property', ArrayAdapter::class);
445-
$container->register('api_platform.cache.metadata.resource', ArrayAdapter::class);
446-
$container->register('api_platform.cache.route_name_resolver', ArrayAdapter::class);
447-
$container->register('api_platform.cache.identifiers_extractor', ArrayAdapter::class);
448-
$container->register('api_platform.cache.subresource_operation_factory', ArrayAdapter::class);
449-
$container->register('api_platform.elasticsearch.cache.metadata.document', ArrayAdapter::class);
447+
@trigger_error('The "api_platform.metadata_cache" parameter is deprecated since version 2.4 and will have no effect in 3.0.', E_USER_DEPRECATED);
448+
449+
// BC
450+
if (!$container->getParameter('api_platform.metadata_cache')) {
451+
$container->removeDefinition('api_platform.cache_warmer.cache_pool_clearer');
452+
453+
$container->register('api_platform.cache.metadata.property', ArrayAdapter::class);
454+
$container->register('api_platform.cache.metadata.resource', ArrayAdapter::class);
455+
$container->register('api_platform.cache.route_name_resolver', ArrayAdapter::class);
456+
$container->register('api_platform.cache.identifiers_extractor', ArrayAdapter::class);
457+
$container->register('api_platform.cache.subresource_operation_factory', ArrayAdapter::class);
458+
$container->register('api_platform.elasticsearch.cache.metadata.document', ArrayAdapter::class);
459+
}
450460
}
451461

452462
/**

src/Bridge/Symfony/Bundle/Resources/config/api.xml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,19 @@
306306
<service id="api_platform.cache.subresource_operation_factory" parent="cache.system" public="false">
307307
<tag name="cache.pool" />
308308
</service>
309+
310+
<service id="api_platform.cache_warmer.cache_pool_clearer" class="ApiPlatform\Core\Bridge\Symfony\Bundle\CacheWarmer\CachePoolClearerCacheWarmer" public="false">
311+
<argument type="service" id="cache.system_clearer" />
312+
<argument type="collection">
313+
<argument>api_platform.cache.metadata.property</argument>
314+
<argument>api_platform.cache.metadata.resource</argument>
315+
<argument>api_platform.cache.route_name_resolver</argument>
316+
<argument>api_platform.cache.identifiers_extractor</argument>
317+
<argument>api_platform.cache.subresource_operation_factory</argument>
318+
<argument>api_platform.elasticsearch.cache.metadata.document</argument>
319+
</argument>
320+
<tag name="kernel.cache_warmer" priority="64" />
321+
</service>
309322
</services>
310323

311324
</container>

tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php

Lines changed: 66 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
use Prophecy\Argument;
7777
use Prophecy\Exception\Doubler\MethodNotFoundException;
7878
use Symfony\Bundle\SecurityBundle\SecurityBundle;
79+
use Symfony\Component\Cache\Adapter\ArrayAdapter;
7980
use Symfony\Component\Config\FileLocator;
8081
use Symfony\Component\Config\Resource\DirectoryResource;
8182
use Symfony\Component\Config\Resource\ResourceInterface;
@@ -133,7 +134,7 @@ protected function setUp()
133134
$this->childDefinitionProphecy = $this->prophesize(ChildDefinition::class);
134135
}
135136

136-
public function tearDown()
137+
protected function tearDown()
137138
{
138139
unset($this->extension);
139140
}
@@ -603,6 +604,58 @@ public function testEnableElasticsearch()
603604
$this->extension->load($config, $containerBuilderProphecy->reveal());
604605
}
605606

607+
/**
608+
* @group legacy
609+
* @expectedDeprecation The "api_platform.metadata_cache" parameter is deprecated since version 2.4 and will have no effect in 3.0.
610+
*/
611+
public function testDisableMetadataCache()
612+
{
613+
$containerBuilderProphecy = $this->getBaseContainerBuilderProphecy();
614+
$containerBuilderProphecy->hasParameter('api_platform.metadata_cache')->willReturn(true);
615+
$containerBuilderProphecy->getParameter('api_platform.metadata_cache')->willReturn(false);
616+
$containerBuilderProphecy->removeDefinition('api_platform.cache_warmer.cache_pool_clearer')->shouldBeCalled();
617+
$containerBuilderProphecy->register('api_platform.cache.metadata.property', ArrayAdapter::class)->shouldBeCalled();
618+
$containerBuilderProphecy->register('api_platform.cache.metadata.resource', ArrayAdapter::class)->shouldBeCalled();
619+
$containerBuilderProphecy->register('api_platform.cache.route_name_resolver', ArrayAdapter::class)->shouldBeCalled();
620+
$containerBuilderProphecy->register('api_platform.cache.identifiers_extractor', ArrayAdapter::class)->shouldBeCalled();
621+
$containerBuilderProphecy->register('api_platform.cache.subresource_operation_factory', ArrayAdapter::class)->shouldBeCalled();
622+
$containerBuilderProphecy->register('api_platform.elasticsearch.cache.metadata.document', ArrayAdapter::class)->shouldBeCalled();
623+
624+
$containerBuilder = $containerBuilderProphecy->reveal();
625+
626+
$this->extension->load(self::DEFAULT_CONFIG, $containerBuilder);
627+
}
628+
629+
public function testRemoveCachePoolClearerCacheWarmerWithoutDebug()
630+
{
631+
$containerBuilderProphecy = $this->getBaseContainerBuilderProphecy();
632+
$containerBuilderProphecy->hasParameter('kernel.debug')->willReturn(true);
633+
$containerBuilderProphecy->getParameter('kernel.debug')->willReturn(false);
634+
$containerBuilderProphecy->removeDefinition('api_platform.cache_warmer.cache_pool_clearer')->shouldBeCalled();
635+
636+
$containerBuilder = $containerBuilderProphecy->reveal();
637+
638+
$this->extension->load(self::DEFAULT_CONFIG, $containerBuilder);
639+
}
640+
641+
public function testKeepCachePoolClearerCacheWarmerWithDebug()
642+
{
643+
$containerBuilderProphecy = $this->getBaseContainerBuilderProphecy();
644+
$containerBuilderProphecy->hasParameter('kernel.debug')->willReturn(true);
645+
$containerBuilderProphecy->getParameter('kernel.debug')->willReturn(true);
646+
$containerBuilderProphecy->removeDefinition('api_platform.cache_warmer.cache_pool_clearer')->shouldNotBeCalled();
647+
648+
// irrelevant, but to prevent errors
649+
$containerBuilderProphecy->setDefinition('debug.api_platform.collection_data_provider', Argument::type(Definition::class))->will(function () {});
650+
$containerBuilderProphecy->setDefinition('debug.api_platform.item_data_provider', Argument::type(Definition::class))->will(function () {});
651+
$containerBuilderProphecy->setDefinition('debug.api_platform.subresource_data_provider', Argument::type(Definition::class))->will(function () {});
652+
$containerBuilderProphecy->setDefinition('debug.api_platform.data_persister', Argument::type(Definition::class))->will(function () {});
653+
654+
$containerBuilder = $containerBuilderProphecy->reveal();
655+
656+
$this->extension->load(self::DEFAULT_CONFIG, $containerBuilder);
657+
}
658+
606659
private function getPartialContainerBuilderProphecy()
607660
{
608661
$containerBuilderProphecy = $this->prophesize(ContainerBuilder::class);
@@ -708,31 +761,29 @@ private function getPartialContainerBuilderProphecy()
708761
$containerBuilderProphecy->hasExtension('http://symfony.com/schema/dic/services')->shouldBeCalled();
709762

710763
$definitions = [
711-
'api_platform.data_persister',
712764
'api_platform.action.documentation',
713-
'api_platform.action.placeholder',
714765
'api_platform.action.entrypoint',
715766
'api_platform.action.exception',
716767
'api_platform.action.placeholder',
717-
'api_platform.cache.metadata.property',
718768
'api_platform.cache.identifiers_extractor',
769+
'api_platform.cache.metadata.property',
719770
'api_platform.cache.metadata.resource',
720771
'api_platform.cache.route_name_resolver',
721772
'api_platform.cache.subresource_operation_factory',
773+
'api_platform.cache_warmer.cache_pool_clearer',
722774
'api_platform.collection_data_provider',
723-
'api_platform.formats_provider',
724-
'api_platform.filter_locator',
775+
'api_platform.data_persister',
725776
'api_platform.filter_collection_factory',
777+
'api_platform.filter_locator',
726778
'api_platform.filters',
779+
'api_platform.formats_provider',
727780
'api_platform.identifiers_extractor',
728781
'api_platform.identifiers_extractor.cached',
729782
'api_platform.iri_converter',
730783
'api_platform.identifier.converter',
731-
'api_platform.identifier.integer',
732784
'api_platform.identifier.date_normalizer',
785+
'api_platform.identifier.integer',
733786
'api_platform.identifier.uuid_normalizer',
734-
'api_platform.identifiers_extractor',
735-
'api_platform.identifiers_extractor.cached',
736787
'api_platform.item_data_provider',
737788
'api_platform.listener.exception',
738789
'api_platform.listener.exception.validation',
@@ -779,14 +830,14 @@ private function getPartialContainerBuilderProphecy()
779830
'api_platform.router',
780831
'api_platform.serializer.context_builder',
781832
'api_platform.serializer.context_builder.filter',
782-
'api_platform.serializer.property_filter',
783833
'api_platform.serializer.group_filter',
784834
'api_platform.serializer.normalizer.item',
785835
'api_platform.serializer.normalizer.item.non_resource',
836+
'api_platform.serializer.property_filter',
837+
'api_platform.serializer_locator',
786838
'api_platform.subresource_data_provider',
787839
'api_platform.subresource_operation_factory',
788840
'api_platform.subresource_operation_factory.cached',
789-
'api_platform.serializer_locator',
790841
'api_platform.validator',
791842
];
792843

@@ -1035,8 +1086,10 @@ private function getBaseContainerBuilderProphecy()
10351086
$containerBuilderProphecy->setAlias($alias, $service)->shouldBeCalled();
10361087
}
10371088

1038-
$containerBuilderProphecy->hasParameter('api_platform.metadata_cache')->willReturn(true)->shouldBeCalled();
1039-
$containerBuilderProphecy->getParameter('api_platform.metadata_cache')->willReturn(true)->shouldBeCalled();
1089+
$containerBuilderProphecy->hasParameter('api_platform.metadata_cache')->willReturn(false);
1090+
1091+
// irrelevant, but to prevent errors
1092+
$containerBuilderProphecy->removeDefinition('api_platform.cache_warmer.cache_pool_clearer')->will(function () {});
10401093

10411094
$containerBuilderProphecy->getDefinition('api_platform.mercure.listener.response.add_link_header')->willReturn(new Definition());
10421095

tests/Fixtures/app/config/config_common.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,6 @@ api_platform:
8989
parameters:
9090
container.autowiring.strict_mode: true
9191
container.dumper.inline_class_loader: true
92-
# Enable the metadata cache to speedup the builds
93-
api_platform.metadata_cache: true
9492

9593
services:
9694
contain_non_resource.item_data_provider:

0 commit comments

Comments
 (0)