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 d13f943

Browse filesBrowse files
committed
[FrameworkBundle][CacheWarmer] Ignore exeptions thrown during reflection classes autoload
1 parent 5dc8bc0 commit d13f943
Copy full SHA for d13f943

File tree

Expand file treeCollapse file tree

12 files changed

+258
-26
lines changed
Filter options
Expand file treeCollapse file tree

12 files changed

+258
-26
lines changed

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

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/CacheWarmer/AbstractPhpFileCacheWarmer.php
+11-2Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Symfony\Component\Cache\Adapter\ArrayAdapter;
1717
use Symfony\Component\Cache\Adapter\PhpArrayAdapter;
1818
use Symfony\Component\Cache\Adapter\ProxyAdapter;
19+
use Symfony\Component\Config\Resource\ClassExistenceResource;
1920
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
2021

2122
/**
@@ -54,13 +55,13 @@ public function warmUp($cacheDir)
5455
{
5556
$arrayAdapter = new ArrayAdapter();
5657

57-
spl_autoload_register([PhpArrayAdapter::class, 'throwOnRequiredClass']);
58+
spl_autoload_register([ClassExistenceResource::class, 'throwOnRequiredClass']);
5859
try {
5960
if (!$this->doWarmUp($cacheDir, $arrayAdapter)) {
6061
return;
6162
}
6263
} finally {
63-
spl_autoload_unregister([PhpArrayAdapter::class, 'throwOnRequiredClass']);
64+
spl_autoload_unregister([ClassExistenceResource::class, 'throwOnRequiredClass']);
6465
}
6566

6667
// the ArrayAdapter stores the values serialized
@@ -82,6 +83,14 @@ protected function warmUpPhpArrayAdapter(PhpArrayAdapter $phpArrayAdapter, array
8283
$phpArrayAdapter->warmUp($values);
8384
}
8485

86+
protected function ignoreAutoloadException($class, \Exception $exception)
87+
{
88+
try {
89+
ClassExistenceResource::throwOnRequiredClass($class, $exception);
90+
} catch (\ReflectionException $e) {
91+
}
92+
}
93+
8594
/**
8695
* @param string $cacheDir
8796
* @param ArrayAdapter $arrayAdapter

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

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/CacheWarmer/AnnotationsCacheWarmer.php
+23-12Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,8 @@ protected function doWarmUp($cacheDir, ArrayAdapter $arrayAdapter)
6666
$this->readAllComponents($reader, $class);
6767
} catch (\ReflectionException $e) {
6868
// ignore failing reflection
69-
} catch (AnnotationException $e) {
70-
/*
71-
* Ignore any AnnotationException to not break the cache warming process if an Annotation is badly
72-
* configured or could not be found / read / etc.
73-
*
74-
* In particular cases, an Annotation in your code can be used and defined only for a specific
75-
* environment but is always added to the annotations.map file by some Symfony default behaviors,
76-
* and you always end up with a not found Annotation.
77-
*/
69+
} catch (\Exception $e) {
70+
$this->ignoreAutoloadException($class, $e);
7871
}
7972
}
8073

@@ -84,14 +77,32 @@ protected function doWarmUp($cacheDir, ArrayAdapter $arrayAdapter)
8477
private function readAllComponents(Reader $reader, $class)
8578
{
8679
$reflectionClass = new \ReflectionClass($class);
87-
$reader->getClassAnnotations($reflectionClass);
80+
81+
try {
82+
$reader->getClassAnnotations($reflectionClass);
83+
} catch (AnnotationException $e) {
84+
/*
85+
* Ignore any AnnotationException to not break the cache warming process if an Annotation is badly
86+
* configured or could not be found / read / etc.
87+
*
88+
* In particular cases, an Annotation in your code can be used and defined only for a specific
89+
* environment but is always added to the annotations.map file by some Symfony default behaviors,
90+
* and you always end up with a not found Annotation.
91+
*/
92+
}
8893

8994
foreach ($reflectionClass->getMethods() as $reflectionMethod) {
90-
$reader->getMethodAnnotations($reflectionMethod);
95+
try {
96+
$reader->getMethodAnnotations($reflectionMethod);
97+
} catch (AnnotationException $e) {
98+
}
9199
}
92100

93101
foreach ($reflectionClass->getProperties() as $reflectionProperty) {
94-
$reader->getPropertyAnnotations($reflectionProperty);
102+
try {
103+
$reader->getPropertyAnnotations($reflectionProperty);
104+
} catch (AnnotationException $e) {
105+
}
95106
}
96107
}
97108
}

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

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/CacheWarmer/SerializerCacheWarmer.php
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ protected function doWarmUp($cacheDir, ArrayAdapter $arrayAdapter)
6060
// ignore failing reflection
6161
} catch (AnnotationException $e) {
6262
// ignore failing annotations
63+
} catch (\Exception $e) {
64+
$this->ignoreAutoloadException($mappedClass, $e);
6365
}
6466
}
6567
}

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

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ValidatorCacheWarmer.php
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ protected function doWarmUp($cacheDir, ArrayAdapter $arrayAdapter)
6565
// ignore failing reflection
6666
} catch (AnnotationException $e) {
6767
// ignore failing annotations
68+
} catch (\Exception $e) {
69+
$this->ignoreAutoloadException($mappedClass, $e);
6870
}
6971
}
7072
}

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

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/AnnotationsCacheWarmerTest.php
+48Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,54 @@ public function testAnnotationsCacheWarmerWithDebugEnabled()
8585
$reader->getPropertyAnnotations($refClass->getProperty('cacheDir'));
8686
}
8787

88+
/**
89+
* Test that the cache warming process is not broken if a class loader
90+
* throws an exception (on class / file not found for example).
91+
*/
92+
public function testClassAutoloadException()
93+
{
94+
$this->assertFalse(class_exists($annotatedClass = 'C\C\C', false));
95+
96+
file_put_contents($this->cacheDir.'/annotations.map', sprintf('<?php return %s;', var_export([$annotatedClass], true)));
97+
$warmer = new AnnotationsCacheWarmer(new AnnotationReader(), tempnam($this->cacheDir, __FUNCTION__), new ArrayAdapter());
98+
99+
spl_autoload_register($classLoader = function ($class) use ($annotatedClass) {
100+
if ($class === $annotatedClass) {
101+
throw new \DomainException('This exception should be caught by the warmer.');
102+
}
103+
}, true, true);
104+
105+
$warmer->warmUp($this->cacheDir);
106+
107+
spl_autoload_unregister($classLoader);
108+
}
109+
110+
/**
111+
* Test that the cache warming process is broken if a class loader throws an
112+
* exception but that is unrelated to the class load.
113+
*
114+
* @expectedException \DomainException
115+
* @expectedExceptionMessage This exception should not be caught by the warmer.
116+
*/
117+
public function testClassAutoloadExceptionWithUnrelatedException()
118+
{
119+
$this->assertFalse(class_exists($annotatedClass = 'AClassThatDoesNotExist_FWB_CacheWarmer_AnnotationsCacheWarmerTest', false));
120+
121+
file_put_contents($this->cacheDir.'/annotations.map', sprintf('<?php return %s;', var_export([$annotatedClass], true)));
122+
$warmer = new AnnotationsCacheWarmer(new AnnotationReader(), tempnam($this->cacheDir, __FUNCTION__), new ArrayAdapter());
123+
124+
spl_autoload_register($classLoader = function ($class) use ($annotatedClass) {
125+
if ($class === $annotatedClass) {
126+
eval('class '.$annotatedClass.'{}');
127+
throw new \DomainException('This exception should not be caught by the warmer.');
128+
}
129+
}, true, true);
130+
131+
$warmer->warmUp($this->cacheDir);
132+
133+
spl_autoload_unregister($classLoader);
134+
}
135+
88136
/**
89137
* @return \PHPUnit_Framework_MockObject_MockObject|Reader
90138
*/

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

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/SerializerCacheWarmerTest.php
+54Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,58 @@ public function testWarmUpWithoutLoader()
7777
$this->assertInternalType('array', $values);
7878
$this->assertCount(0, $values);
7979
}
80+
81+
/**
82+
* Test that the cache warming process is not broken if a class loader
83+
* throws an exception (on class / file not found for example).
84+
*/
85+
public function testClassAutoloadException()
86+
{
87+
if (!class_exists(CacheClassMetadataFactory::class) || !method_exists(XmlFileLoader::class, 'getMappedClasses') || !method_exists(YamlFileLoader::class, 'getMappedClasses')) {
88+
$this->markTestSkipped('The Serializer default cache warmer has been introduced in the Serializer Component version 3.2.');
89+
}
90+
91+
$this->assertFalse(class_exists($mappedClass = 'AClassThatDoesNotExist_FWB_CacheWarmer_SerializerCacheWarmerTest', false));
92+
93+
$warmer = new SerializerCacheWarmer([new YamlFileLoader(__DIR__.'/../Fixtures/Serialization/Resources/does_not_exist.yaml')], tempnam(sys_get_temp_dir(), __FUNCTION__), new ArrayAdapter());
94+
95+
spl_autoload_register($classLoader = function ($class) use ($mappedClass) {
96+
if ($class === $mappedClass) {
97+
throw new \DomainException('This exception should be caught by the warmer.');
98+
}
99+
}, true, true);
100+
101+
$warmer->warmUp('foo');
102+
103+
spl_autoload_unregister($classLoader);
104+
}
105+
106+
/**
107+
* Test that the cache warming process is broken if a class loader throws an
108+
* exception but that is unrelated to the class load.
109+
*
110+
* @expectedException \DomainException
111+
* @expectedExceptionMessage This exception should not be caught by the warmer.
112+
*/
113+
public function testClassAutoloadExceptionWithUnrelatedException()
114+
{
115+
if (!class_exists(CacheClassMetadataFactory::class) || !method_exists(XmlFileLoader::class, 'getMappedClasses') || !method_exists(YamlFileLoader::class, 'getMappedClasses')) {
116+
$this->markTestSkipped('The Serializer default cache warmer has been introduced in the Serializer Component version 3.2.');
117+
}
118+
119+
$this->assertFalse(class_exists($mappedClass = 'AClassThatDoesNotExist_FWB_CacheWarmer_SerializerCacheWarmerTest', false));
120+
121+
$warmer = new SerializerCacheWarmer([new YamlFileLoader(__DIR__.'/../Fixtures/Serialization/Resources/does_not_exist.yaml')], tempnam(sys_get_temp_dir(), __FUNCTION__), new ArrayAdapter());
122+
123+
spl_autoload_register($classLoader = function ($class) use ($mappedClass) {
124+
if ($class === $mappedClass) {
125+
eval('class '.$mappedClass.'{}');
126+
throw new \DomainException('This exception should not be caught by the warmer.');
127+
}
128+
}, true, true);
129+
130+
$warmer->warmUp('foo');
131+
132+
spl_autoload_unregister($classLoader);
133+
}
80134
}

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

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/ValidatorCacheWarmerTest.php
+50Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,54 @@ public function testWarmUpWithoutLoader()
102102
$this->assertInternalType('array', $values);
103103
$this->assertCount(0, $values);
104104
}
105+
106+
/**
107+
* Test that the cache warming process is not broken if a class loader
108+
* throws an exception (on class / file not found for example).
109+
*/
110+
public function testClassAutoloadException()
111+
{
112+
$this->assertFalse(class_exists($mappedClass = 'AClassThatDoesNotExist_FWB_CacheWarmer_ValidatorCacheWarmerTest', false));
113+
114+
$validatorBuilder = new ValidatorBuilder();
115+
$validatorBuilder->addYamlMapping(__DIR__.'/../Fixtures/Validation/Resources/does_not_exist.yaml');
116+
$warmer = new ValidatorCacheWarmer($validatorBuilder, tempnam(sys_get_temp_dir(), __FUNCTION__), new ArrayAdapter());
117+
118+
spl_autoload_register($classloader = function ($class) use ($mappedClass) {
119+
if ($class === $mappedClass) {
120+
throw new \DomainException('This exception should be caught by the warmer.');
121+
}
122+
}, true, true);
123+
124+
$warmer->warmUp('foo');
125+
126+
spl_autoload_unregister($classloader);
127+
}
128+
129+
/**
130+
* Test that the cache warming process is broken if a class loader throws an
131+
* exception but that is unrelated to the class load.
132+
*
133+
* @expectedException \DomainException
134+
* @expectedExceptionMessage This exception should not be caught by the warmer.
135+
*/
136+
public function testClassAutoloadExceptionWithUnrelatedException()
137+
{
138+
$this->assertFalse(class_exists($mappedClass = 'AClassThatDoesNotExist_FWB_CacheWarmer_ValidatorCacheWarmerTest', false));
139+
140+
$validatorBuilder = new ValidatorBuilder();
141+
$validatorBuilder->addYamlMapping(__DIR__.'/../Fixtures/Validation/Resources/does_not_exist.yaml');
142+
$warmer = new ValidatorCacheWarmer($validatorBuilder, tempnam(sys_get_temp_dir(), __FUNCTION__), new ArrayAdapter());
143+
144+
spl_autoload_register($classLoader = function ($class) use ($mappedClass) {
145+
if ($class === $mappedClass) {
146+
eval('class '.$mappedClass.'{}');
147+
throw new \DomainException('This exception should not be caught by the warmer.');
148+
}
149+
}, true, true);
150+
151+
$warmer->warmUp('foo');
152+
153+
spl_autoload_unregister($classLoader);
154+
}
105155
}
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
AClassThatDoesNotExist_FWB_CacheWarmer_SerializerCacheWarmerTest: ~
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
AClassThatDoesNotExist_FWB_CacheWarmer_ValidatorCacheWarmerTest: ~

‎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
@@ -21,7 +21,7 @@
2121
"symfony/cache": "~3.4|~4.0",
2222
"symfony/class-loader": "~3.2",
2323
"symfony/dependency-injection": "^3.4.24|^4.2.5",
24-
"symfony/config": "~3.4|~4.0",
24+
"symfony/config": "^3.4.30|~4.2.11|^4.3.3",
2525
"symfony/debug": "~2.8|~3.0|~4.0",
2626
"symfony/event-dispatcher": "~3.4|~4.0",
2727
"symfony/http-foundation": "^3.3.11|~4.0",

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ private function generateItems(array $keys)
266266
/**
267267
* @throws \ReflectionException When $class is not found and is required
268268
*
269-
* @internal
269+
* @internal to be removed in Symfony 5.0
270270
*/
271271
public static function throwOnRequiredClass($class)
272272
{

0 commit comments

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