feature #31452 [FrameworkBundle] Add cache configuration for PropertyInfo (alanpoulain)

This PR was squashed before being merged into the 4.3 branch (closes #31452).

Discussion
----------

[FrameworkBundle] Add cache configuration for PropertyInfo

| Q             | A
| ------------- | ---
| Branch?       | 4.3
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? |
| Tests pass?   | yes
| Fixed tickets | n/a
| License       | MIT
| Doc PR        | n/a

The PropertyInfoExtractor was not cached by default but the class to do it was surprisingly here, unused.

I've added the configuration to enable it by default when it's not the development environment.

I haven't added the warmup part because there are too much arguments for the methods (class, property, context).

It will be a big boost for the performance! For this code:

```php
$book = $this->serializer->deserialize('{"id":3,"reviews":[{"id": 7, "body": "This book is fantastic!", "rating": 9, "letter": "A", "publicationDate": "2019"}],"isbn":"978-0-5533-9243-2","title":"Fool\'s Assassin","description":"A famous saga","author":"Robin Hobb","publicationDate":"2014"}', Book::class, 'json');
$this->serializer->serialize($book, 'json');
```

We obtain this:

![image](https://user-images.githubusercontent.com/10920253/57487994-2874d000-72b2-11e9-92a2-28b14a038194.png)

The Blackfire comparison is here: https://blackfire.io/profiles/compare/2c746d26-320a-4aab-80ef-7276c2e92b96/graph

Commits
-------

17f6225d0f [FrameworkBundle] Add cache configuration for PropertyInfo
This commit is contained in:
Fabien Potencier 2019-05-13 08:44:35 +02:00
commit 3a17701343
5 changed files with 36 additions and 13 deletions

View File

@ -99,7 +99,6 @@ use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Serializer\Encoder\DecoderInterface;
use Symfony\Component\Serializer\Encoder\EncoderInterface;
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorFromClassMetadata;
use Symfony\Component\Serializer\Mapping\Factory\CacheClassMetadataFactory;
use Symfony\Component\Serializer\Normalizer\ConstraintViolationListNormalizer;
use Symfony\Component\Serializer\Normalizer\DateIntervalNormalizer;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
@ -1505,18 +1504,8 @@ class FrameworkExtension extends Extension
$chainLoader->replaceArgument(0, $serializerLoaders);
$container->getDefinition('serializer.mapping.cache_warmer')->replaceArgument(0, $serializerLoaders);
if (!$container->getParameter('kernel.debug')) {
$cacheMetadataFactory = new Definition(
CacheClassMetadataFactory::class,
[
new Reference('serializer.mapping.cache_class_metadata_factory.inner'),
new Reference('serializer.mapping.cache.symfony'),
]
);
$cacheMetadataFactory->setPublic(false);
$cacheMetadataFactory->setDecoratedService('serializer.mapping.class_metadata_factory');
$container->setDefinition('serializer.mapping.cache_class_metadata_factory', $cacheMetadataFactory);
if ($container->getParameter('kernel.debug')) {
$container->removeDefinition('serializer.mapping.cache_class_metadata_factory');
}
if (isset($config['name_converter']) && $config['name_converter']) {
@ -1551,6 +1540,10 @@ class FrameworkExtension extends Extension
$definition->addTag('property_info.description_extractor', ['priority' => -1000]);
$definition->addTag('property_info.type_extractor', ['priority' => -1001]);
}
if ($container->getParameter('kernel.debug')) {
$container->removeDefinition('property_info.cache');
}
}
private function registerLockConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader)

View File

@ -36,6 +36,10 @@
<tag name="cache.pool" />
</service>
<service id="cache.property_info" parent="cache.system" public="false">
<tag name="cache.pool" />
</service>
<service id="cache.messenger.restart_workers_signal" parent="cache.app" public="false">
<tag name="cache.pool" />
</service>

View File

@ -21,6 +21,11 @@
<service id="Symfony\Component\PropertyInfo\PropertyListExtractorInterface" alias="property_info" />
<service id="Symfony\Component\PropertyInfo\PropertyInitializableExtractorInterface" alias="property_info" />
<service id="property_info.cache" decorates="property_info" class="Symfony\Component\PropertyInfo\PropertyInfoCacheExtractor">
<argument type="service" id="property_info.cache.inner" />
<argument type="service" id="cache.property_info" />
</service>
<!-- Extractor -->
<service id="property_info.reflection_extractor" class="Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor">
<tag name="property_info.list_extractor" priority="-1000" />

View File

@ -104,6 +104,11 @@
<argument type="service" id="cache.serializer" />
</service>
<service id="serializer.mapping.cache_class_metadata_factory" decorates="serializer.mapping.class_metadata_factory" class="Symfony\Component\Serializer\Mapping\Factory\CacheClassMetadataFactory">
<argument type="service" id="serializer.mapping.cache_class_metadata_factory.inner" />
<argument type="service" id="serializer.mapping.cache.symfony" />
</service>
<!-- Encoders -->
<service id="serializer.encoder.xml" class="Symfony\Component\Serializer\Encoder\XmlEncoder">
<tag name="serializer.encoder" />

View File

@ -1357,6 +1357,22 @@ abstract class FrameworkExtensionTest extends TestCase
$this->assertTrue($container->has('property_info'));
}
public function testPropertyInfoCacheActivated()
{
$container = $this->createContainerFromFile('property_info');
$this->assertTrue($container->hasDefinition('property_info.cache'));
$cache = $container->getDefinition('property_info.cache')->getArgument(1);
$this->assertEquals(new Reference('cache.property_info'), $cache);
}
public function testPropertyInfoCacheDisabled()
{
$container = $this->createContainerFromFile('property_info', ['kernel.debug' => true, 'kernel.container_class' => __CLASS__]);
$this->assertFalse($container->hasDefinition('property_info.cache'));
}
public function testEventDispatcherService()
{
$container = $this->createContainer(['kernel.charset' => 'UTF-8', 'kernel.secret' => 'secret']);