8000 Add metadata caching · api-platform/core@16cb4f8 · GitHub
[go: up one dir, main page]

Skip to content

Commit 16cb4f8

Browse files
committed
Add metadata caching
1 parent b85c30b commit 16cb4f8

File tree

11 files changed

+405
-9
lines changed

11 files changed

+405
-9
lines changed

composer.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
],
2121
"require": {
2222
"php": ">=7.0",
23+
"psr/cache": "^1.0.0",
2324
"symfony/http-foundation": "~2.3|~3.0|~3.1@dev",
2425
"symfony/serializer": "~3.1@dev",
2526
"doctrine/inflector": "~1.0",
@@ -33,6 +34,7 @@
3334
"behat/mink-extension": "~2.2",
3435
"behat/mink-browserkit-driver": "^1.3.1",
3536
"behatch/contexts": "~2.5",
37+
"symfony/cache": "^3.1.0@dev",
3638
"symfony/framework-bundle": "~3.1@dev",
3739
"symfony/finder": "~2.3",
3840
"symfony/security": "~2.7|~3.0",
@@ -47,7 +49,9 @@
4749
},
4850
"suggest": {
4951
"friendsofsymfony/user-bundle": "To use the FOSUserBundle bridge.",
50-
"nelmio/api-doc-bundle": "To have the api sandbox & documentation."
52+
"nelmio/api-doc-bundle": "To have the api sandbox & documentation.",
53+
"psr/cache-implementation": "To use metadata caching.",
54+
"symfony/cache": "To have metadata caching when using Symfony integration."
5155
},
5256
"autoload": {
5357
"psr-4": { "ApiPlatform\\Core\\": "src/" }

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

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

8181
$this->enableJsonLd($loader);
8282
$this->registerAnnotationLoaders($container);
83+
$this->setUpMetadataCaching($container, $config);
8384

8485
$bundles = $container->getParameter('kernel.bundles');
8586

@@ -130,4 +131,35 @@ private function registerAnnotationLoaders(ContainerBuilder $container)
130131

131132
$container->getDefinition('api_platform.metadata.resource.name_collection_factory.annotation')->addArgument($paths);
132133
}
134+
135+
/**
136+
* Sets up metadata caching.
137+
*
138+
* @param ContainerBuilder $container
139+
* @param array $config
140+
*/
141+
private function setUpMetadataCaching(ContainerBuilder $container, array $config)
142+
{
143+
$container->setAlias('api_platform.metadata.resource.cache', $config['metadata']['resource']['cache']);
144+
$container->setAlias('api_platform.metadata.property.cache', $config['metadata']['property']['cache']);
145+
146+
if (!class_exists('Symfony\Component\Cache\Adapter\ArrayAdapter')) {
147+
$container->removeDefinition('api_platform.metadata.resource.cache.array');
148+
$container->removeDefinition('api_platform.metadata.resource.cache.apcu');
149+
$container->removeDefinition('api_platform.metadata.property.cache.array');
150+
$container->removeDefinition('api_platform.metadata.property.cache.apcu');
151+
}
152+
153+
if (!$container->has($config['metadata']['resource']['cache'])) {
154+
$container->removeAlias('api_platform.metadata.resource.cache');
155+
$container->removeDefinition('api_platform.metadata.resource.name_collection_factory.cached');
156+
$container->removeDefinition('api_platform.metadata.resource.metadata_factory.cached');
157+
}
158+
159+
if (!$container->has($config['metadata']['property']['cache'])) {
160+
$container->removeAlias('api_platform.metadata.property.cache');
161+
$container->removeDefinition('api_platform.metadata.property.name_collection_factory.cached');
162+
$container->removeDefinition('api_platform.metadata.property.metadata_factory.cached');
163+
}
164+
}
133165
}

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,23 @@ public function getConfigTreeBuilder()
8181
->end()
8282
->end()
8383
->end()
84+
->arrayNode('metadata')
85+
->addDefaultsIfNotSet()
86+
->children()
87+
->arrayNode('resource')
88+
->addDefaultsIfNotSet()
89+
->children()
90+
->scalarNode('cache')->defaultValue('api_platform.metadata.resource.cache.array')->cannotBeEmpty()->info('Cache service for resource metadata.')->end()
91+
->end()
92+
->end()
93+
->arrayNode('property')
94+
->addDefaultsIfNotSet()
95+
->children()
96+
->scalarNode('cache')->defaultValue('api_platform.metadata.property.cache.array')->cannotBeEmpty()->info('Cache service for property metadata.')->end()
97+
->end()
98+
->end()
99+
->end()
100+
->end()
84101
->end();
85102

86103
return $treeBuilder;

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@
5454

5555
<!-- Metadata loader -->
5656

57-
<service id="api_platform.doctrine.orm.metadata.property.factory.item" class="ApiPlatform\Core\Bridge\Doctrine\Orm\Metadata\Property\DoctrineOrmPropertyMetadataFactory" decorates="api_platform.metadata.property.metadata_factory" public="false">
57+
<service id="api_platform.doctrine.orm.metadata.property.metadata_factory" class="ApiPlatform\Core\Bridge\Doctrine\Orm\Metadata\Property\DoctrineOrmPropertyMetadataFactory" decorates="api_platform.metadata.property.metadata_factory" public="false">
5858
<argument type="service" id="doctrine" />
59-
<argument type="service" id="api_platform.doctrine.orm.metadata.property.factory.item.inner" />
59+
<argument type="service" id="api_platform.doctrine.orm.metadata.property.metadata_factory.inner" />
6060
</service>
6161

6262
<!-- Event listener -->

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

Lines changed: 46 additions & 4 deletions
112
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,20 @@
55
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
66

77
<services>
8-
<!-- Resource collection -->
8+
<!-- Resource name collection -->
99

1010
<service id="api_platform.metadata.resource.name_collection_factory" alias="api_platform.metadata.resource.name_collection_factory.annotation" />
1111

1212
<service id="api_platform.metadata.resource.name_collection_factory.annotation" class="ApiPlatform\Core\Metadata\Resource\Factory\AnnotationResourceNameCollectionFactory" public="false">
1313
<argument type="service" id="annotation_reader" />
1414
</service>
1515

16-
<!-- Resource item -->
16+
<service id="api_platform.metadata.resource.name_collection_factory.cached" class="ApiPlatform\Core\Metadata\Resource\Factory\CachedResourceNameCollectionFactory" decorates="api_platform.metadata.resource.name_collection_factory" decoration-priority="-1" public="false">
17+
<argument type="service" id="api_platform.metadata.resource.cache" />
18+
<argument type="service" id="api_platform.metadata.resource.name_collection_factory.cached.inner" />
19+
</service>
20+
21+
<!-- Resource metadata -->
1722

1823
<service id="api_platform.metadata.resource.metadata_factory" alias="api_platform.metadata.resource.metadata_factory.annotation" />
1924

@@ -33,7 +38,12 @@
3338
<argument type="service" id="api_platform.metadata.resource.metadata_factory.operation.inner" />
3439
</service>
3540

36-
<!-- Property collection -->
41+
<service id="api_platform.metadata.resource.metadata_factory.cached" class="ApiPlatform\Core\Metadata\Resource\Factory\CachedResourceMetadataFactory" decorates="api_platform.metadata.resource.metadata_factory" decoration-priority="-1" public="false">
42+
<argument type="service" id="api_platform.metadata.resource.cache" />
43+
<argument type="service" id="api_platform.metadata.resource.metadata_factory.cached.inner" />
44+
</service>
45 10000 +
46+
<!-- Property name collection -->
3747

3848
<service id="api_platform.metadata.property.name_collection_factory" alias="api_platform.metadata.property.name_collection_factory.property_info" />
3949

@@ -49,7 +59,12 @@
4959
<argument type="service" id="api_platform.property_info" />
5060
</service>
5161

52-
<!-- Property item -->
62+
<service id="api_platform.metadata.property.name_collection_factory.cached" class="ApiPlatform\Core\Metadata\Property\Factory\CachedPropertyNameCollectionFactory" decorates="api_platform.metadata.property.name_collection_factory" decoration-priority="-1" public="false">
63+
<argument type="service" id="api_platform.metadata.property.cache" />
64+
<argument type="service" id="api_platform.metadata.property.name_collection_factory.cached.inner" />
65+
</service>
66+
67+
<!-- Property metadata -->
5368

5469
<service id="api_platform.metadata.property.metadata_factory" alias="api_platform.metadata.property.metadata_factory.annotation" />
5570

@@ -74,6 +89,33 @@
7489
<argument type="service" id="api_platform.metadata.property.metadata_factory.validator.inner" />
7590
</service>
7691

92+
<service id="api_platform.metadata.property.metadata_factory.cached" class="ApiPlatform\Core\Metadata\Property\Factory\CachedPropertyMetadataFactory" decorates="api_platform.metadata.property.metadata_factory" decoration-priority="-1" public="false">
93+
<argument type="service" id="api_platform.metadata.property.cache" />
94+
<argument type="service" id="api_platform.metadata.property.metadata_factory.cached.inner" />
95+
</service>
96+
97+
<!-- Cache -->
98+
99+
<service id="api_platform.metadata.resource.cache.array" class="Symfony\Component\Cache\Adapter\ArrayAdapter" public="false">
100+
<argument>0</argument>
101+
<argument>false</argument>
102+
</service>
103+
104+
<service id="api_platform.metadata.resource.cache.apcu" class="Symfony\Component\Cache\Adapter\ApcuAdapter" public="false">
105+
<argument>api_platform_metadata_resource</argument>
106+
<argument>0</argument>
107+
</service>
108+
109+
<service id="api_platform.metadata.property.cache.array" class="Symfony\Component\Cache\Adapter\ArrayAdapter" public="false">
110+
<argument>0</argument>
111+
<argument>false</argument>
+
</service>
113+
114+
<service id="api_platform.metadata.property.cache.apcu" class="Symfony\Component\Cache\Adapter\ApcuAdapter" public="false">
115+
<argument>api_platform_metadata_property</argument>
116+
<argument>0</argument>
117+
</service>
118+
77119
</services>
78120

79121
</container>
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <dunglas@gmail.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 ApiPlatform\Core\Metadata\Property\Factory;
13+
14+
use ApiPlatform\Core\Metadata\Property\PropertyMetadata;
15+
use Psr\Cache\CacheException;
16+
use Psr\Cache\CacheItemPoolInterface;
17+
18+
/**
19+
* Caches property metadata.
20+
*
21+
* @author Teoh Han Hui <teohhanhui@gmail.com>
22+
*/
23+
final class CachedPropertyMetadataFactory implements PropertyMetadataFactoryInterface
24+
{
25+
const CACHE_KEY_PREFIX = 'property_metadata_';
26+
27+
private $cacheItemPool;
28+
private $decorated;
29+
30+
public function __construct(CacheItemPoolInterface $cacheItemPool, PropertyMetadataFactoryInterface $decorated)
31+
{
32+
$this->cacheItemPool = $cacheItemPool;
33+
$this->decorated = $decorated;
34+
}
35+
36+
/**
37+
* {@inheritdoc}
38+
*/
39+
public function create(string $resourceClass, string $property, array $options = []) : PropertyMetadata
40+
{
41+
$cacheKey = self::CACHE_KEY_PREFIX.md5(serialize([$resourceClass, $property, $options]));
42+
43+
try {
44+
$cacheItem = $this->cacheItemPool->getItem($cacheKey);
45+
46+
if ($cacheItem->isHit()) {
47+
return $cacheItem->get();
48+
}
49+
} catch (CacheException $e) {
50+
// do nothing
51+
}
52+
53+
$propertyMetadata = $this->decorated->create($resourceClass, $property, $options);
54+
55+
if (isset($cacheItem)) {
56+
try {
57+
$cacheItem->set($propertyMetadata);
58+
$this->cacheItemPool->save($cacheItem);
59+
} catch (CacheException $e) {
60+
// do nothing
61+
}
62+
}
63+
64+
return $propertyMetadata;
65+
}
66+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <dunglas@gmail.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 ApiPlatform\Core\Metadata\Property\Factory;
13+
14+
use ApiPlatform\Core\Metadata\Property\PropertyNameCollection;
15+
use Psr\Cache\CacheException;
16+
use Psr\Cache\CacheItemPoolInterface;
17+
18+
/**
19+
* Caches property name collection.
20+
*
21+
* @author Teoh Han Hui <teohhanhui@gmail.com>
22+
*/
23+
final class CachedPropertyNameCollectionFactory implements PropertyNameCollectionFactoryInterface
24+
{
25+
const CACHE_KEY_PREFIX = 'property_name_collection_';
26+
27+
private $cacheItemPool;
28+
private $decorated;
29+
30+
public function __construct(CacheItemPoolInterface $cacheItemPool, PropertyNameCollectionFactoryInterface $decorated)
31+
{
32+
$this->cacheItemPool = $cacheItemPool;
33+
$this->decorated = $decorated;
34+
}
35+
36+
/**
37+
* {@inheritdoc}
38+
*/
39+
public function create(string $resourceClass, array $options = []) : PropertyNameCollection
40+
{
41+
$cacheKey = self::CACHE_KEY_PREFIX.md5(serialize([$resourceClass, $options]));
42+
43+
try {
44+
$cacheItem = $this->cacheItemPool->getItem($cacheKey);
45+
46+
if ($cacheItem->isHit()) {
47+
return $cacheItem->get();
48+
}
49+
} catch (CacheException $e) {
50+
10000 // do nothing
51+
}
52+
53+
$propertyNameCollection = $this->decorated->create($resourceClass, $options);
54+
55+
if (isset($cacheItem)) {
56+
try {
57+
$cacheItem->set($propertyNameCollection);
58+
$this->cacheItemPool->save($cacheItem);
59+
} catch (CacheException $e) {
60+
// do nothing
61+
}
62+
}
63+
64+
return $propertyNameCollection;
65+
}
66+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <dunglas@gmail.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 ApiPlatform\Core\Metadata\Resource\Factory;
13+
14+
use ApiPlatform\Core\Metadata\Resource\ResourceMetadata;
15+
use Psr\Cache\CacheException;
16+
use Psr\Cache\CacheItemPoolInterface;
17+
18+
/**
19+
* Caches resource metadata.
20+
*
21+
* @author Teoh Han Hui <teohhanhui@gmail.com>
22+
*/
23+
final class CachedResourceMetadataFactory implements ResourceMetadataFactoryInterface
24+
{
25+
const CACHE_KEY_PREFIX = 'resource_metadata_';
26+
27+
private $cacheItemPool;
28+
private $decorated;
29+
30+
public function __construct(CacheItemPoolInterface $cacheItemPool, ResourceMetadataFactoryInterface $decorated)
31+
{
32+
$this->cacheItemPool = $cacheItemPool;
33+
$this->decorated = $decorated;
34+
}
35+
36+
/**
37+
* {@inheritdoc}
38+
*/
39+
public function create(string $resourceClass) : ResourceMetadata
40+
{
41+
$cacheKey = self::CACHE_KEY_PREFIX.md5(serialize([$resourceClass]));
42+
43+
try {
44+
$cacheItem = $this->cacheItemPool->getItem($cacheKey);
45+
46+
if ($cacheItem->isHit()) {
47+
return $cacheItem->get();
48+
}
49+
} catch (CacheException $e) {
50+
// do nothing
51+
}
52+
53+
$resourceMetadata = $this->decorated->create($resourceClass);
54+
55+
if (isset($cacheItem)) {
56+
try {
57+
$cacheItem->set($resourceMetadata);
58+
$this->cacheItemPool->save($cacheItem);
59+
} catch (CacheException $e) {
60+
// do nothing
61+
}
62+
}
63+
64+
return $resourceMetadata;
65+
}
66+
}

0 commit comments

Comments
 (0)
0