Skip to content

Commit

Permalink
[FrameworkBundle][CacheWarmer] Ignore exeptions thrown during reflect…
Browse files Browse the repository at this point in the history
…ion classes autoload
  • Loading branch information
fancyweb committed Jul 12, 2019
1 parent ee5e5de commit 0816b13
Show file tree
Hide file tree
Showing 9 changed files with 174 additions and 0 deletions.
Expand Up @@ -82,6 +82,19 @@ protected function warmUpPhpArrayAdapter(PhpArrayAdapter $phpArrayAdapter, array
$phpArrayAdapter->warmUp($values);
}

protected function ignoreAutoloadException($class, \Exception $exception)
{
if (false === array_search([
'function' => 'spl_autoload_call',
'args' => [$class],
], $exception->getTrace(), true) ||
class_exists($class, false) ||
interface_exists($class, false) ||
trait_exists($class, false)) {
throw $exception;
}
}

/**
* @param string $cacheDir
* @param ArrayAdapter $arrayAdapter
Expand Down
Expand Up @@ -75,6 +75,8 @@ protected function doWarmUp($cacheDir, ArrayAdapter $arrayAdapter)
* environment but is always added to the annotations.map file by some Symfony default behaviors,
* and you always end up with a not found Annotation.
*/
} catch (\Exception $e) {
$this->ignoreAutoloadException($class, $e);
}
}

Expand Down
Expand Up @@ -60,6 +60,8 @@ protected function doWarmUp($cacheDir, ArrayAdapter $arrayAdapter)
// ignore failing reflection
} catch (AnnotationException $e) {
// ignore failing annotations
} catch (\Exception $e) {
$this->ignoreAutoloadException($mappedClass, $e);
}
}
}
Expand Down
Expand Up @@ -65,6 +65,8 @@ protected function doWarmUp($cacheDir, ArrayAdapter $arrayAdapter)
// ignore failing reflection
} catch (AnnotationException $e) {
// ignore failing annotations
} catch (\Exception $e) {
$this->ignoreAutoloadException($mappedClass, $e);
}
}
}
Expand Down
Expand Up @@ -85,6 +85,54 @@ public function testAnnotationsCacheWarmerWithDebugEnabled()
$reader->getPropertyAnnotations($refClass->getProperty('cacheDir'));
}

/**
* Test that the cache warming process is not broken if a class loader
* throws an exception (on class / file not found for example).
*/
public function testClassAutoloadException()
{
$this->assertFalse(class_exists($annotatedClass = 'C\C\C', false));

file_put_contents($this->cacheDir.'/annotations.map', sprintf('<?php return %s;', var_export([$annotatedClass], true)));
$warmer = new AnnotationsCacheWarmer(new AnnotationReader(), tempnam($this->cacheDir, __FUNCTION__), new ArrayAdapter());

spl_autoload_register($classloader = function ($class) use ($annotatedClass) {
if ($class === $annotatedClass) {
throw new \DomainException('This exception should be caught by the warmer.');
}
}, true, true);

$warmer->warmUp($this->cacheDir);

spl_autoload_unregister($classloader);
}

/**
* Test that the cache warming process is broken if a class loader throws an
* exception but that is unrelated to the class load.
*/
public function testClassAutoloadExceptionWithUnrelatedException()
{
$this->assertFalse(class_exists($annotatedClass = 'AClassThatDoesNotExist_FWB_CacheWarmer_AnnotationsCacheWarmerTest', false));

file_put_contents($this->cacheDir.'/annotations.map', sprintf('<?php return %s;', var_export([$annotatedClass], true)));
$warmer = new AnnotationsCacheWarmer(new AnnotationReader(), tempnam($this->cacheDir, __FUNCTION__), new ArrayAdapter());

$this->expectException(\DomainException::class);
$this->expectExceptionMessage('This exception should not be caught by the warmer.');

spl_autoload_register($classloader = function ($class) use ($annotatedClass) {
if ($class === $annotatedClass) {
eval(sprintf('class '.$annotatedClass.'{}'));
throw new \DomainException('This exception should not be caught by the warmer.');
}
}, true, true);

$warmer->warmUp($this->cacheDir);

spl_autoload_unregister($classloader);
}

/**
* @return \PHPUnit_Framework_MockObject_MockObject|Reader
*/
Expand Down
Expand Up @@ -77,4 +77,58 @@ public function testWarmUpWithoutLoader()
$this->assertInternalType('array', $values);
$this->assertCount(0, $values);
}

/**
* Test that the cache warming process is not broken if a class loader
* throws an exception (on class / file not found for example).
*/
public function testClassAutoloadException()
{
if (!class_exists(CacheClassMetadataFactory::class) || !method_exists(XmlFileLoader::class, 'getMappedClasses') || !method_exists(YamlFileLoader::class, 'getMappedClasses')) {
$this->markTestSkipped('The Serializer default cache warmer has been introduced in the Serializer Component version 3.2.');
}

$this->assertFalse(class_exists($mappedClass = 'AClassThatDoesNotExist_FWB_CacheWarmer_SerializerCacheWarmerTest', false));

$warmer = new SerializerCacheWarmer([new YamlFileLoader(__DIR__.'/../Fixtures/Serialization/Resources/does_not_exist.yaml')], tempnam(sys_get_temp_dir(), __FUNCTION__), new ArrayAdapter());

spl_autoload_register($classloader = function ($class) use ($mappedClass) {
if ($class === $mappedClass) {
throw new \DomainException('This exception should be caught by the warmer.');
}
}, true, true);

$warmer->warmUp('foo');

spl_autoload_unregister($classloader);
}

/**
* Test that the cache warming process is broken if a class loader throws an
* exception but that is unrelated to the class load.
*/
public function testClassAutoloadExceptionWithUnrelatedException()
{
if (!class_exists(CacheClassMetadataFactory::class) || !method_exists(XmlFileLoader::class, 'getMappedClasses') || !method_exists(YamlFileLoader::class, 'getMappedClasses')) {
$this->markTestSkipped('The Serializer default cache warmer has been introduced in the Serializer Component version 3.2.');
}

$this->assertFalse(class_exists($mappedClass = 'AClassThatDoesNotExist_FWB_CacheWarmer_SerializerCacheWarmerTest', false));

$warmer = new SerializerCacheWarmer([new YamlFileLoader(__DIR__.'/../Fixtures/Serialization/Resources/does_not_exist.yaml')], tempnam(sys_get_temp_dir(), __FUNCTION__), new ArrayAdapter());

$this->expectException(\DomainException::class);
$this->expectExceptionMessage('This exception should not be caught by the warmer.');

spl_autoload_register($classloader = function ($class) use ($mappedClass) {
if ($class === $mappedClass) {
eval(sprintf('class '.$mappedClass.'{}'));
throw new \DomainException('This exception should not be caught by the warmer.');
}
}, true, true);

$warmer->warmUp('foo');

spl_autoload_unregister($classloader);
}
}
Expand Up @@ -102,4 +102,55 @@ public function testWarmUpWithoutLoader()
$this->assertInternalType('array', $values);
$this->assertCount(0, $values);
}

/**
* Test that the cache warming process is not broken if a class loader
* throws an exception (on class / file not found for example).
*/
public function testClassAutoloadException()
{
$this->assertFalse(class_exists($mappedClass = 'AClassThatDoesNotExist_FWB_CacheWarmer_ValidatorCacheWarmerTest', false));

$validatorBuilder = new ValidatorBuilder();
$validatorBuilder->addYamlMapping(__DIR__.'/../Fixtures/Validation/Resources/does_not_exist.yaml');
$validatorBuilder->enableAnnotationMapping();
$warmer = new ValidatorCacheWarmer($validatorBuilder, tempnam(sys_get_temp_dir(), __FUNCTION__), new ArrayAdapter());

spl_autoload_register($classloader = function ($class) use ($mappedClass) {
if ($class === $mappedClass) {
throw new \DomainException('This exception should be caught by the warmer.');
}
}, true, true);

$warmer->warmUp('foo');

spl_autoload_unregister($classloader);
}

/**
* Test that the cache warming process is broken if a class loader throws an
* exception but that is unrelated to the class load.
*/
public function testClassAutoloadExceptionWithUnrelatedException()
{
$this->assertFalse(class_exists($mappedClass = 'AClassThatDoesNotExist_FWB_CacheWarmer_ValidatorCacheWarmerTest', false));

$validatorBuilder = new ValidatorBuilder();
$validatorBuilder->addYamlMapping(__DIR__.'/../Fixtures/Validation/Resources/does_not_exist.yaml');
$warmer = new ValidatorCacheWarmer($validatorBuilder, tempnam(sys_get_temp_dir(), __FUNCTION__), new ArrayAdapter());

$this->expectException(\DomainException::class);
$this->expectExceptionMessage('This exception should not be caught by the warmer.');

spl_autoload_register($classloader = function ($class) use ($mappedClass) {
if ($class === $mappedClass) {
eval(sprintf('class '.$mappedClass.'{}'));
throw new \DomainException('This exception should not be caught by the warmer.');
}
}, true, true);

$warmer->warmUp('foo');

spl_autoload_unregister($classloader);
}
}
@@ -0,0 +1 @@
AClassThatDoesNotExist_FWB_CacheWarmer_SerializerCacheWarmerTest: ~
@@ -0,0 +1 @@
AClassThatDoesNotExist_FWB_CacheWarmer_ValidatorCacheWarmerTest: ~

0 comments on commit 0816b13

Please sign in to comment.