Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 75de5eb

Browse filesBrowse files
committed
bug #21243 [FrameworkBundle] Fix class_exists() checks in PhpArrayAdapter-related cache warmers (nicolas-grekas, mpajunen)
This PR was merged into the 3.2 branch. Discussion ---------- [FrameworkBundle] Fix class_exists() checks in PhpArrayAdapter-related cache warmers | Q | A | ------------- | --- | Branch? | 3.2 | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - Follow up of #21102 Commits ------- e09dccc [FrameworkBundle] Add annotated validator cache test case c60009e [FrameworkBundle] Fix class_exists() checks in PhpArrayAdapter-related cache warmers
2 parents 7ba3bc6 + e09dccc commit 75de5eb
Copy full SHA for 75de5eb

File tree

9 files changed

+141
-19
lines changed
Filter options

9 files changed

+141
-19
lines changed

‎src/Symfony/Bundle/FrameworkBundle/CacheWarmer/AnnotationsCacheWarmer.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/CacheWarmer/AnnotationsCacheWarmer.php
+4-5Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ class AnnotationsCacheWarmer implements CacheWarmerInterface
3636

3737
/**
3838
* @param Reader $annotationReader
39-
* @param string $phpArrayFile The PHP file where annotations are cached.
40-
* @param CacheItemPoolInterface $fallbackPool The pool where runtime-discovered annotations are cached.
39+
* @param string $phpArrayFile The PHP file where annotations are cached
40+
* @param CacheItemPoolInterface $fallbackPool The pool where runtime-discovered annotations are cached
4141
*/
4242
public function __construct(Reader $annotationReader, $phpArrayFile, CacheItemPoolInterface $fallbackPool)
4343
{
@@ -67,9 +67,8 @@ public function warmUp($cacheDir)
6767

6868
$arrayPool = new ArrayAdapter(0, false);
6969
$reader = new CachedReader($this->annotationReader, new DoctrineProvider($arrayPool));
70-
$throwingAutoloader = function ($class) { throw new \ReflectionException(sprintf('Class %s does not exist', $class)); };
71-
spl_autoload_register($throwingAutoloader);
7270

71+
spl_autoload_register(array($adapter, 'throwOnRequiredClass'));
7372
try {
7473
foreach ($annotatedClasses as $class) {
7574
try {
@@ -88,7 +87,7 @@ public function warmUp($cacheDir)
8887
}
8988
}
9089
} finally {
91-
spl_autoload_unregister($throwingAutoloader);
90+
spl_autoload_unregister(array($adapter, 'throwOnRequiredClass'));
9291
}
9392

9493
$values = $arrayPool->getValues();

‎src/Symfony/Bundle/FrameworkBundle/CacheWarmer/SerializerCacheWarmer.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/CacheWarmer/SerializerCacheWarmer.php
+18-6Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Bundle\FrameworkBundle\CacheWarmer;
1313

14+
use Doctrine\Common\Annotations\AnnotationException;
1415
use Psr\Cache\CacheItemPoolInterface;
1516
use Symfony\Component\Cache\Adapter\AdapterInterface;
1617
use Symfony\Component\Cache\Adapter\ArrayAdapter;
@@ -36,9 +37,9 @@ class SerializerCacheWarmer implements CacheWarmerInterface
3637
private $fallbackPool;
3738

3839
/**
39-
* @param LoaderInterface[] $loaders The serializer metadata loaders.
40-
* @param string $phpArrayFile The PHP file where metadata are cached.
41-
* @param CacheItemPoolInterface $fallbackPool The pool where runtime-discovered metadata are cached.
40+
* @param LoaderInterface[] $loaders The serializer metadata loaders
41+
* @param string $phpArrayFile The PHP file where metadata are cached
42+
* @param CacheItemPoolInterface $fallbackPool The pool where runtime-discovered metadata are cached
4243
*/
4344
public function __construct(array $loaders, $phpArrayFile, CacheItemPoolInterface $fallbackPool)
4445
{
@@ -64,10 +65,21 @@ public function warmUp($cacheDir)
6465

6566
$metadataFactory = new CacheClassMetadataFactory(new ClassMetadataFactory(new LoaderChain($this->loaders)), $arrayPool);
6667

67-
foreach ($this->extractSupportedLoaders($this->loaders) as $loader) {
68-
foreach ($loader->getMappedClasses() as $mappedClass) {
69-
$metadataFactory->getMetadataFor($mappedClass);
68+
spl_autoload_register(array($adapter, 'throwOnRequiredClass'));
69+
try {
70+
foreach ($this->extractSupportedLoaders($this->loaders) as $loader) {
71+
foreach ($loader->getMappedClasses() as $mappedClass) {
72+
try {
73+
$metadataFactory->getMetadataFor($mappedClass);
74+
} catch (\ReflectionException $e) {
75+
// ignore failing reflection
76+
} catch (AnnotationException $e) {
77+
// ignore failing annotations
78+
}
79+
}
7080
}
81+
} finally {
82+
spl_autoload_unregister(array($adapter, 'throwOnRequiredClass'));
7183
}
7284

7385
$values = $arrayPool->getValues();

‎src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ValidatorCacheWarmer.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ValidatorCacheWarmer.php
+8-7Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Bundle\FrameworkBundle\CacheWarmer;
1313

14+
use Doctrine\Common\Annotations\AnnotationException;
1415
use Psr\Cache\CacheItemPoolInterface;
1516
use Symfony\Component\Cache\Adapter\AdapterInterface;
1617
use Symfony\Component\Cache\Adapter\ArrayAdapter;
@@ -38,8 +39,8 @@ class ValidatorCacheWarmer implements CacheWarmerInterface
3839

3940
/**
4041
* @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.
42+
* @param string $phpArrayFile The PHP file where metadata are cached
43+
* @param CacheItemPoolInterface $fallbackPool The pool where runtime-discovered metadata are cached
4344
*/
4445
public function __construct(ValidatorBuilderInterface $validatorBuilder, $phpArrayFile, CacheItemPoolInterface $fallbackPool)
4546
{
@@ -66,9 +67,7 @@ public function warmUp($cacheDir)
6667
$loaders = $this->validatorBuilder->getLoaders();
6768
$metadataFactory = new LazyLoadingMetadataFactory(new LoaderChain($loaders), new Psr6Cache($arrayPool));
6869

69-
$throwingAutoloader = function ($class) { throw new \ReflectionException(sprintf('Class %s does not exist', $class)); };
70-
spl_autoload_register($throwingAutoloader);
71-
70+
spl_autoload_register(array($adapter, 'throwOnRequiredClass'));
7271
try {
7372
foreach ($this->extractSupportedLoaders($loaders) as $loader) {
7473
foreach ($loader->getMappedClasses() as $mappedClass) {
@@ -78,15 +77,17 @@ public function warmUp($cacheDir)
7877
}
7978
} catch (\ReflectionException $e) {
8079
// ignore failing reflection
80+
} catch (AnnotationException $e) {
81+
// ignore failing annotations
8182
}
8283
}
8384
}
8485
} finally {
85-
spl_autoload_unregister($throwingAutoloader);
86+
spl_autoload_unregister(array($adapter, 'throwOnRequiredClass'));
8687
}
8788

8889
$values = $arrayPool->getValues();
89-
$adapter->warmUp($values);
90+
$adapter->warmUp(array_filter($values));
9091

9192
foreach ($values as $k => $v) {
9293
$item = $this->fallbackPool->getItem($k);

‎src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/ValidatorCacheWarmerTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/ValidatorCacheWarmerTest.php
+33Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,39 @@ public function testWarmUp()
5151
$this->assertArrayHasKey('Symfony.Bundle.FrameworkBundle.Tests.Fixtures.Validation.Author', $values);
5252
}
5353

54+
public function testWarmUpWithAnnotations()
55+
{
56+
$validatorBuilder = new ValidatorBuilder();
57+
$validatorBuilder->addYamlMapping(__DIR__.'/../Fixtures/Validation/Resources/categories.yml');
58+
$validatorBuilder->enableAnnotationMapping();
59+
60+
$file = sys_get_temp_dir().'/cache-validator-with-annotations.php';
61+
@unlink($file);
62+
63+
$fallbackPool = new ArrayAdapter();
64+
65+
$warmer = new ValidatorCacheWarmer($validatorBuilder, $file, $fallbackPool);
66+
$warmer->warmUp(dirname($file));
67+
68+
$this->assertFileExists($file);
69+
70+
$values = require $file;
71+
72+
$this->assertInternalType('array', $values);
73+
$this->assertCount(1, $values);
74+
$this->assertArrayHasKey('Symfony.Bundle.FrameworkBundle.Tests.Fixtures.Validation.Category', $values);
75+
76+
// Simple check to make sure that at least one constraint is actually cached, in this case the "id" property Type.
77+
$this->assertContains('"int"', $values['Symfony.Bundle.FrameworkBundle.Tests.Fixtures.Validation.Category']);
78+
79+
$values = $fallbackPool->getValues();
80+
81+
$this->assertInternalType('array', $values);
82+
$this->assertCount(2, $values);
83+
$this->assertArrayHasKey('Symfony.Bundle.FrameworkBundle.Tests.Fixtures.Validation.Category', $values);
84+
$this->assertArrayHasKey('Symfony.Bundle.FrameworkBundle.Tests.Fixtures.Validation.SubCategory', $values);
85+
}
86+
5487
public function testWarmUpWithoutLoader()
5588
{
5689
$validatorBuilder = new ValidatorBuilder();
+17Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
namespace Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Validation;
4+
5+
use Symfony\Component\Validator\Constraints as Assert;
6+
7+
class Category
8+
{
9+
const NAME_PATTERN = '/\w+/';
10+
11+
public $id;
12+
13+
/**
14+
* @Assert\Type(Category::NAME_PATTERN)
15+
*/
16+
public $name;
17+
}
+9Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Validation\Category:
2+
properties:
3+
id:
4+
- Type: int
5+
6+
Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Validation\SubCategory:
7+
properties:
8+
id:
9+
- Type: int
+13Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Validation;
4+
5+
// Missing "use" for Assert\Type is on purpose
6+
7+
class SubCategory extends Category
8+
{
9+
/**
10+
* @Assert\Type(Category::class)
11+
*/
12+
public $main;
13+
}

‎src/Symfony/Bundle/FrameworkBundle/composer.json

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/composer.json
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
],
1818
"require": {
1919
"php": ">=5.5.9",
20-
"symfony/cache": "~3.2",
20+
"symfony/cache": "~3.2.2|~3.3",
2121
"symfony/class-loader": "~3.2",
2222
"symfony/dependency-injection": "~3.2.1|~3.3",
2323
"symfony/config": "~2.8|~3.0",

‎src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php
+38Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,4 +365,42 @@ private function generateItems(array $keys)
365365
}
366366
}
367367
}
368+
369+
/**
370+
* @throws \ReflectionException When $class is not found and is required
371+
*
372+
* @internal
373+
*/
374+
public static function throwOnRequiredClass($class)
375+
{
376+
$e = new \ReflectionException(sprintf('Class %s does not exist', $class));
377+
$trace = $e->getTrace();
378+
$autoloadFrame = array(
379+
'function' => 'spl_autoload_call',
380+
'args' => array($class),
381+
);
382+
$i = array_search($autoloadFrame, $trace);
383+
384+
if (false !== $i++ && isset($trace[$i]['function']) && !isset($trace[$i]['class'])) {
385+
switch ($trace[$i]['function']) {
386+
case 'get_class_methods':
387+
case 'get_class_vars':
388+
case 'get_parent_class':
389+
case 'is_a':
390+
case 'is_subclass_of':
391+
case 'class_exists':
392+
case 'class_implements':
393+
case 'class_parents':
394+
case 'trait_exists':
395+
case 'defined':
396+
case 'interface_exists':
397+
case 'method_exists':
398+
case 'property_exists':
399+
case 'is_callable':
400+
return;
401+
}
402+
}
403+
404+
throw $e;
405+
}
368406
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.