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

Skip to content

Commit 4365d7c

Browse files
committed
[FrameworkBundle] Introduce a cache warmer for Validator based on PhpArrayAdapter
1 parent 983b560 commit 4365d7c

File tree

18 files changed

+349
-76
lines changed

18 files changed

+349
-76
lines changed
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[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+
namespace Symfony\Bundle\FrameworkBundle\CacheWarmer;
13+
14+
use Psr\Cache\CacheItemPoolInterface;
15+
use Symfony\Component\Cache\Adapter\AdapterInterface;
16+
use Symfony\Component\Cache\Adapter\ArrayAdapter;
17+
use Symfony\Component\Cache\Adapter\PhpArrayAdapter;
18+
use Symfony\Component\Cache\Adapter\ProxyAdapter;
19+
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
20+
use Symfony\Component\Validator\Mapping\Cache\Psr6Cache;
21+
use Symfony\Component\Validator\Mapping\Factory\LazyLoadingMetadataFactory;
22+
use Symfony\Component\Validator\Mapping\Loader\LoaderChain;
23+
use Symfony\Component\Validator\Mapping\Loader\LoaderInterface;
24+
use Symfony\Component\Validator\Mapping\Loader\XmlFileLoader;
25+
use Symfony\Component\Validator\Mapping\Loader\YamlFileLoader;
26+
use Symfony\Component\Validator\ValidatorBuilderInterface;
27+
28+
/**
29+
* Warms up XML and YAML validator metadata.
30+
*
31+
* @author Titouan Galopin <[email protected]>
32+
*/
33+
class ValidatorCacheWarmer implements CacheWarmerInterface
34+
{
35+
private $validatorBuilder;
36+
private $phpArrayFile;
37+
private $fallbackPool;
38+
39+
/**
40+
* @param ValidatorBuilderInterface $validatorBuilder
41+
* @param string $phpArrayFile The PHP file where metadata are cached.
42+
* @param CacheItemPoolInterface $fallbackPool The pool where runtime-discovered metadata are cached.
43+
*/
44+
public function __construct(ValidatorBuilderInterface $validatorBuilder, $phpArrayFile, CacheItemPoolInterface $fallbackPool)
45+
{
46+
$this->validatorBuilder = $validatorBuilder;
47+
$this->phpArrayFile = $phpArrayFile;
48+
if (!$fallbackPool instanceof AdapterInterface) {
49+
$fallbackPool = new ProxyAdapter($fallbackPool);
50+
}
51+
$this->fallbackPool = $fallbackPool;
52+
}
53+
54+
/**
55+
* {@inheritdoc}
56+
*/
57+
public function warmUp($cacheDir)
58+
{
59+
if (!method_exists($this->validatorBuilder, 'getLoaders')) {
60+
return;
61+
}
62+
63+
$adapter = new PhpArrayAdapter($this->phpArrayFile, $this->fallbackPool);
64+
$arrayPool = new ArrayAdapter(0, false);
65+
66+
$loaders = $this->validatorBuilder->getLoaders();
67+
$metadataFactory = new LazyLoadingMetadataFactory(new LoaderChain($loaders), new Psr6Cache($arrayPool));
68+
69+
foreach ($this->extractSupportedLoaders($loaders) as $loader) {
70+
foreach ($loader->getMappedClasses() as $mappedClass) {
71+
$metadataFactory->getMetadataFor($mappedClass);
72+
}
73+
}
74+
75+
$values = $arrayPool->getValues();
76+
$adapter->warmUp($values);
77+
78+
foreach ($values as $k => $v) {
79+
$item = $this->fallbackPool->getItem($k);
80+
$this->fallbackPool->saveDeferred($item->set($v));
81+
}
82+
$this->fallbackPool->commit();
83+
}
84+
85+
/**
86+
* {@inheritdoc}
87+
*/
88+
public function isOptional()
89+
{
90+
return true;
91+
}
92+
93+
/**
94+
* @param LoaderInterface[] $loaders
95+
*
96+
* @return XmlFileLoader[]|YamlFileLoader[]
97+
*/
98+
private function extractSupportedLoaders(array $loaders)
99+
{
100+
$supportedLoaders = array();
101+
102+
foreach ($loaders as $loader) {
103+
if ($loader instanceof XmlFileLoader || $loader instanceof YamlFileLoader) {
104+
$supportedLoaders[] = $loader;
105+
} elseif ($loader instanceof LoaderChain) {
106+
$supportedLoaders = array_merge($supportedLoaders, $this->extractSupportedLoaders($loader->getDelegatedLoaders()));
107+
}
108+
}
109+
110+
return $supportedLoaders;
111+
}
112+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,7 @@ private function addValidationSection(ArrayNodeDefinition $rootNode)
567567
->info('validation configuration')
568568
->canBeEnabled()
569569
->children()
570-
->scalarNode('cache')->defaultValue('validator.mapping.cache.symfony')->end()
570+
->scalarNode('cache')->end()
571571
->booleanNode('enable_annotations')->defaultFalse()->end()
572572
->arrayNode('static_method')
573573
->defaultValue(array('loadValidatorMetadata'))

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -858,13 +858,17 @@ private function registerValidationConfiguration(array $config, ContainerBuilder
858858
}
859859
}
860860

861-
if (!$container->getParameter('kernel.debug')) {
861+
if (isset($config['cache']) && $config['cache']) {
862+
@trigger_error('The "framework.validation.cache" option is deprecated since Symfony 3.2 and will be removed in 4.0. Configure the "cache.validator" service under "framework.cache.pools" instead.', E_USER_DEPRECATED);
863+
862864
$container->setParameter(
863865
'validator.mapping.cache.prefix',
864866
'validator_'.$this->getKernelRootHash($container)
865867
);
866868

867869
$validatorBuilder->addMethodCall('setMetadataCache', array(new Reference($config['cache'])));
870+
} elseif (!$container->getParameter('kernel.debug')) {
871+
$validatorBuilder->addMethodCall('setMetadataCache', array(new Reference('validator.mapping.cache.symfony')));
868872
}
869873
}
870874

src/Symfony/Bundle/FrameworkBundle/Resources/config/validator.xml

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
<parameters>
88
<parameter key="validator.mapping.cache.prefix" />
9+
<parameter key="validator.mapping.cache.file">%kernel.cache_dir%/validation.php</parameter>
910
</parameters>
1011

1112
<services>
@@ -28,8 +29,21 @@
2829

2930
<service id="validator.mapping.class_metadata_factory" alias="validator" public="false" />
3031

31-
<service id="validator.mapping.cache.symfony" class="Symfony\Component\Validator\Mapping\Cache\Psr6Cache" public="false">
32+
<service id="validator.mapping.cache_warmer" class="Symfony\Bundle\FrameworkBundle\CacheWarmer\ValidatorCacheWarmer" public="false">
33+
<argument type="service" id="validator.builder" />
34+
<argument>%validator.mapping.cache.file%</argument>
3235
<argument type="service" id="cache.validator" />
36+
<tag name="kernel.cache_warmer" />
37+
</service>
38+
39+
<service id="validator.mapping.cache.symfony" class="Symfony\Component\Validator\Mapping\Cache\Psr6Cache" public="false">
40+
<argument type="service">
41+
<service class="Symfony\Component\Cache\Adapter\PhpArrayAdapter">
42+
<factory class="Symfony\Component\Cache\Adapter\PhpArrayAdapter" method="create" />
43+
<argument>%validator.mapping.cache.file%</argument>
44+
<argument type="service" id="cache.validator" />
45+
</service>
46+
</argument>
3347
</service>
3448

3549
<service id="validator.mapping.cache.doctrine.apc" class="Symfony\Component\Validator\Mapping\Cache\DoctrineCache" public="false">
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[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+
namespace Symfony\Bundle\FrameworkBundle\Tests\CacheWarmer;
13+
14+
use Symfony\Bundle\FrameworkBundle\CacheWarmer\ValidatorCacheWarmer;
15+
use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
16+
use Symfony\Component\Cache\Adapter\ArrayAdapter;
17+
use Symfony\Component\Validator\ValidatorBuilder;
18+
19+
class ValidatorCacheWarmerTest extends TestCase
20+
{
21+
public function testWarmUp()
22+
{
23+
$validatorBuilder = new ValidatorBuilder();
24+
$validatorBuilder->addXmlMapping(__DIR__.'/../Fixtures/Validation/Resources/person.xml');
25+
$validatorBuilder->addYamlMapping(__DIR__.'/../Fixtures/Validation/Resources/author.yml');
26+
$validatorBuilder->addMethodMapping('loadValidatorMetadata');
27+
$validatorBuilder->enableAnnotationMapping();
28+
29+
$file = sys_get_temp_dir().'/cache-validator.php';
30+
@unlink($file);
31+
32+
$fallbackPool = new ArrayAdapter();
33+
34+
$warmer = new ValidatorCacheWarmer($validatorBuilder, $file, $fallbackPool);
35+
$warmer->warmUp(dirname($file));
36+
37+
$this->assertFileExists($file);
38+
39+
$values = require $file;
40+
41+
$this->assertInternalType('array', $values);
42+
$this->assertCount(2, $values);
43+
$this->assertArrayHasKey('Symfony.Bundle.FrameworkBundle.Tests.Fixtures.Validation.Person', $values);
44+
$this->assertArrayHasKey('Symfony.Bundle.FrameworkBundle.Tests.Fixtures.Validation.Author', $values);
45+
46+
$values = $fallbackPool->getValues();
47+
48+
$this->assertInternalType('array', $values);
49+
$this->assertCount(2, $values);
50+
$this->assertArrayHasKey('Symfony.Bundle.FrameworkBundle.Tests.Fixtures.Validation.Person', $values);
51+
$this->assertArrayHasKey('Symfony.Bundle.FrameworkBundle.Tests.Fixtures.Validation.Author', $values);
52+
}
53+
54+
public function testWarmUpWithoutLoader()
55+
{
56+
$validatorBuilder = new ValidatorBuilder();
57+
58+
$file = sys_get_temp_dir().'/cache-validator-without-loaders.php';
59+
@unlink($file);
60+
61+
$fallbackPool = new ArrayAdapter();
62+
63+
$warmer = new ValidatorCacheWarmer($validatorBuilder, $file, $fallbackPool);
64+
$warmer->warmUp(dirname($file));
65+
66+
$this->assertFileExists($file);
67+
68+
$values = require $file;
69+
70+
$this->assertInternalType('array', $values);
71+
$this->assertCount(0, $values);
72+
73+
$values = $fallbackPool->getValues();
74+
75+
$this->assertInternalType('array', $values);
76+
$this->assertCount(0, $values);
77+
}
78+
}

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,6 @@ protected static function getBundleDefaultConfig()
211211
'static_method' => array('loadValidatorMetadata'),
212212
'translation_domain' => 'validators',
213213
'strict_email' => false,
214-
'cache' => 'validator.mapping.cache.symfony',
215214
),
216215
'annotations' => array(
217216
'cache' => 'php_array',

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@
5656
),
5757
'validation' => array(
5858
'enabled' => true,
59-
'cache' => 'validator.mapping.cache.doctrine.apc',
6059
),
6160
'annotations' => array(
6261
'cache' => 'file',

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
<framework:translator enabled="true" fallback="fr" logging="true">
3939
<framework:path>%kernel.root_dir%/Fixtures/translations</framework:path>
4040
</framework:translator>
41-
<framework:validation enabled="true" cache="validator.mapping.cache.doctrine.apc" />
41+
<framework:validation enabled="true" />
4242
<framework:annotations cache="file" debug="true" file-cache-dir="%kernel.cache_dir%/annotations" />
4343
<framework:serializer enabled="true" enable-annotations="true" name-converter="serializer.name_converter.camel_case_to_snake_case" />
4444
<framework:property-info />

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ framework:
4444
paths: ['%kernel.root_dir%/Fixtures/translations']
4545
validation:
4646
enabled: true
47-
cache: validator.mapping.cache.doctrine.apc
4847
annotations:
4948
cache: file
5049
debug: true

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ public function testValidation()
336336
$this->assertSame('addMethodMapping', $calls[4][0]);
337337
$this->assertSame(array('loadValidatorMetadata'), $calls[4][1]);
338338
$this->assertSame('setMetadataCache', $calls[5][0]);
339-
$this->assertEquals(array(new Reference('validator.mapping.cache.doctrine.apc')), $calls[5][1]);
339+
$this->assertEquals(array(new Reference('validator.mapping.cache.symfony')), $calls[5][1]);
340340
}
341341

342342
public function testValidationService()
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Validation;
4+
5+
class Author
6+
{
7+
public $gender;
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Validation;
4+
5+
class Person
6+
{
7+
public $gender;
8+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Validation\Author:
2+
properties:
3+
gender:
4+
- Choice: { choices: [male, female, other], message: Choose a valid gender. }
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping http://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">
5+
6+
<class name="Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Validation\Person">
7+
<property name="gender">
8+
<constraint name="Choice">
9+
<option name="choices">
10+
<value>male</value>
11+
<value>female</value>
12+
<value>other</value>
13+
</option>
14+
<option name="message">Choose a valid gender.</option>
15+
</constraint>
16+
</property>
17+
</class>
18+
</constraint-mapping>

src/Symfony/Bundle/FrameworkBundle/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
"symfony/expression-language": "~2.8|~3.0",
4949
"symfony/process": "~2.8|~3.0",
5050
"symfony/serializer": "~2.8|^3.0",
51-
"symfony/validator": "~3.1",
51+
"symfony/validator": "~3.2",
5252
"symfony/yaml": "~3.2",
5353
"symfony/property-info": "~2.8|~3.0",
5454
"phpdocumentor/reflection-docblock": "^3.0",

0 commit comments

Comments
 (0)