[Config] Make ClassExistenceResource throw on invalid parents
This commit is contained in:
parent
4917b30718
commit
53b01903ce
@ -25,6 +25,7 @@ class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializ
|
|||||||
private $exists;
|
private $exists;
|
||||||
|
|
||||||
private static $autoloadLevel = 0;
|
private static $autoloadLevel = 0;
|
||||||
|
private static $autoloadedClass;
|
||||||
private static $existsCache = array();
|
private static $existsCache = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -57,6 +58,8 @@ class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializ
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @throws \ReflectionException when a parent class/interface/trait is not found
|
||||||
*/
|
*/
|
||||||
public function isFresh($timestamp)
|
public function isFresh($timestamp)
|
||||||
{
|
{
|
||||||
@ -68,12 +71,13 @@ class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializ
|
|||||||
if (!self::$autoloadLevel++) {
|
if (!self::$autoloadLevel++) {
|
||||||
spl_autoload_register(__CLASS__.'::throwOnRequiredClass');
|
spl_autoload_register(__CLASS__.'::throwOnRequiredClass');
|
||||||
}
|
}
|
||||||
|
$autoloadedClass = self::$autoloadedClass;
|
||||||
|
self::$autoloadedClass = $this->resource;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$exists = class_exists($this->resource) || interface_exists($this->resource, false) || trait_exists($this->resource, false);
|
$exists = class_exists($this->resource) || interface_exists($this->resource, false) || trait_exists($this->resource, false);
|
||||||
} catch (\ReflectionException $e) {
|
|
||||||
$exists = false;
|
|
||||||
} finally {
|
} finally {
|
||||||
|
self::$autoloadedClass = $autoloadedClass;
|
||||||
if (!--self::$autoloadLevel) {
|
if (!--self::$autoloadLevel) {
|
||||||
spl_autoload_unregister(__CLASS__.'::throwOnRequiredClass');
|
spl_autoload_unregister(__CLASS__.'::throwOnRequiredClass');
|
||||||
}
|
}
|
||||||
@ -112,7 +116,10 @@ class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializ
|
|||||||
*/
|
*/
|
||||||
private static function throwOnRequiredClass($class)
|
private static function throwOnRequiredClass($class)
|
||||||
{
|
{
|
||||||
$e = new \ReflectionException("Class $class does not exist");
|
if (self::$autoloadedClass === $class) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$e = new \ReflectionException("Class $class not found");
|
||||||
$trace = $e->getTrace();
|
$trace = $e->getTrace();
|
||||||
$autoloadFrame = array(
|
$autoloadFrame = array(
|
||||||
'function' => 'spl_autoload_call',
|
'function' => 'spl_autoload_call',
|
||||||
@ -138,6 +145,18 @@ class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializ
|
|||||||
case 'is_callable':
|
case 'is_callable':
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$props = array(
|
||||||
|
'file' => $trace[$i]['file'],
|
||||||
|
'line' => $trace[$i]['line'],
|
||||||
|
'trace' => array_slice($trace, 0, 1 + $i),
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($props as $p => $v) {
|
||||||
|
$r = new \ReflectionProperty('Exception', $p);
|
||||||
|
$r->setAccessible(true);
|
||||||
|
$r->setValue($e, $v);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw $e;
|
throw $e;
|
||||||
|
@ -124,8 +124,8 @@ class AutowirePass extends AbstractRecursivePass
|
|||||||
if (!$value instanceof Definition || !$value->isAutowired() || $value->isAbstract() || !$value->getClass()) {
|
if (!$value instanceof Definition || !$value->isAutowired() || $value->isAbstract() || !$value->getClass()) {
|
||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
if (!$reflectionClass = $this->container->getReflectionClass($value->getClass())) {
|
if (!$reflectionClass = $this->container->getReflectionClass($value->getClass(), false)) {
|
||||||
$this->container->log($this, sprintf('Skipping service "%s": Class or interface "%s" does not exist.', $this->currentId, $value->getClass()));
|
$this->container->log($this, sprintf('Skipping service "%s": Class or interface "%s" cannot be loaded.', $this->currentId, $value->getClass()));
|
||||||
|
|
||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
@ -388,7 +388,7 @@ class AutowirePass extends AbstractRecursivePass
|
|||||||
unset($this->ambiguousServiceTypes[$type]);
|
unset($this->ambiguousServiceTypes[$type]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($definition->isDeprecated() || !$reflectionClass = $this->container->getReflectionClass($definition->getClass())) {
|
if ($definition->isDeprecated() || !$reflectionClass = $this->container->getReflectionClass($definition->getClass(), false)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -444,7 +444,7 @@ class AutowirePass extends AbstractRecursivePass
|
|||||||
*/
|
*/
|
||||||
private function createAutowiredDefinition($type)
|
private function createAutowiredDefinition($type)
|
||||||
{
|
{
|
||||||
if (!($typeHint = $this->container->getReflectionClass($type)) || !$typeHint->isInstantiable()) {
|
if (!($typeHint = $this->container->getReflectionClass($type, false)) || !$typeHint->isInstantiable()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -478,8 +478,8 @@ class AutowirePass extends AbstractRecursivePass
|
|||||||
|
|
||||||
private function createTypeNotFoundMessage(TypedReference $reference, $label)
|
private function createTypeNotFoundMessage(TypedReference $reference, $label)
|
||||||
{
|
{
|
||||||
if (!$r = $this->container->getReflectionClass($type = $reference->getType())) {
|
if (!$r = $this->container->getReflectionClass($type = $reference->getType(), false)) {
|
||||||
$message = sprintf('has type "%s" but this class does not exist.', $type);
|
$message = sprintf('has type "%s" but this class cannot be loaded.', $type);
|
||||||
} else {
|
} else {
|
||||||
$message = $this->container->has($type) ? 'this service is abstract' : 'no such service exists';
|
$message = $this->container->has($type) ? 'this service is abstract' : 'no such service exists';
|
||||||
$message = sprintf('references %s "%s" but %s.%s', $r->isInterface() ? 'interface' : 'class', $type, $message, $this->createTypeAlternatives($reference));
|
$message = sprintf('references %s "%s" but %s.%s', $r->isInterface() ? 'interface' : 'class', $type, $message, $this->createTypeAlternatives($reference));
|
||||||
|
@ -81,7 +81,7 @@ class FactoryReturnTypePass implements CompilerPassInterface
|
|||||||
$class = $factory[0];
|
$class = $factory[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$m = $container->getReflectionClass($class)) {
|
if (!$m = $container->getReflectionClass($class, false)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
@ -66,7 +66,7 @@ class ResolveInstanceofConditionalsPass implements CompilerPassInterface
|
|||||||
$instanceofTags = array();
|
$instanceofTags = array();
|
||||||
|
|
||||||
foreach ($conditionals as $interface => $instanceofDefs) {
|
foreach ($conditionals as $interface => $instanceofDefs) {
|
||||||
if ($interface !== $class && (!$container->getReflectionClass($class))) {
|
if ($interface !== $class && (!$container->getReflectionClass($class, false))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -337,12 +337,15 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
|
|||||||
* Retrieves the requested reflection class and registers it for resource tracking.
|
* Retrieves the requested reflection class and registers it for resource tracking.
|
||||||
*
|
*
|
||||||
* @param string $class
|
* @param string $class
|
||||||
|
* @param bool $throw
|
||||||
*
|
*
|
||||||
* @return \ReflectionClass|null
|
* @return \ReflectionClass|null
|
||||||
*
|
*
|
||||||
|
* @throws \ReflectionException when a parent class/interface/trait is not found and $throw is true
|
||||||
|
*
|
||||||
* @final
|
* @final
|
||||||
*/
|
*/
|
||||||
public function getReflectionClass($class)
|
public function getReflectionClass($class, $throw = true)
|
||||||
{
|
{
|
||||||
if (!$class = $this->getParameterBag()->resolveValue($class)) {
|
if (!$class = $this->getParameterBag()->resolveValue($class)) {
|
||||||
return;
|
return;
|
||||||
@ -357,6 +360,9 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
|
|||||||
$classReflector = $resource->isFresh(0) ? false : new \ReflectionClass($class);
|
$classReflector = $resource->isFresh(0) ? false : new \ReflectionClass($class);
|
||||||
}
|
}
|
||||||
} catch (\ReflectionException $e) {
|
} catch (\ReflectionException $e) {
|
||||||
|
if ($throw) {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
$classReflector = false;
|
$classReflector = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -359,7 +359,7 @@ class AutowirePassTest extends TestCase
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
|
* @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
|
||||||
* @expectedExceptionMessage Cannot autowire service "a": argument "$r" of method "Symfony\Component\DependencyInjection\Tests\Compiler\BadTypeHintedArgument::__construct()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\NotARealClass" but this class does not exist.
|
* @expectedExceptionMessage Cannot autowire service "a": argument "$r" of method "Symfony\Component\DependencyInjection\Tests\Compiler\BadTypeHintedArgument::__construct()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\NotARealClass" but this class cannot be loaded.
|
||||||
*/
|
*/
|
||||||
public function testClassNotFoundThrowsException()
|
public function testClassNotFoundThrowsException()
|
||||||
{
|
{
|
||||||
@ -374,7 +374,7 @@ class AutowirePassTest extends TestCase
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
|
* @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
|
||||||
* @expectedExceptionMessage Cannot autowire service "a": argument "$r" of method "Symfony\Component\DependencyInjection\Tests\Compiler\BadParentTypeHintedArgument::__construct()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\OptionalServiceClass" but this class does not exist.
|
* @expectedExceptionMessage Cannot autowire service "a": argument "$r" of method "Symfony\Component\DependencyInjection\Tests\Compiler\BadParentTypeHintedArgument::__construct()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\OptionalServiceClass" but this class cannot be loaded.
|
||||||
*/
|
*/
|
||||||
public function testParentClassNotFoundThrowsException()
|
public function testParentClassNotFoundThrowsException()
|
||||||
{
|
{
|
||||||
@ -744,7 +744,7 @@ class AutowirePassTest extends TestCase
|
|||||||
public function provideNotWireableCalls()
|
public function provideNotWireableCalls()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
array('setNotAutowireable', 'Cannot autowire service "foo": argument "$n" of method "Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setNotAutowireable()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\NotARealClass" but this class does not exist.'),
|
array('setNotAutowireable', 'Cannot autowire service "foo": argument "$n" of method "Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setNotAutowireable()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\NotARealClass" but this class cannot be loaded.'),
|
||||||
array('setDifferentNamespace', 'Cannot autowire service "foo": argument "$n" of method "Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setDifferentNamespace()" references class "stdClass" but no such service exists. It cannot be auto-registered because it is from a different root namespace.'),
|
array('setDifferentNamespace', 'Cannot autowire service "foo": argument "$n" of method "Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setDifferentNamespace()" references class "stdClass" but no such service exists. It cannot be auto-registered because it is from a different root namespace.'),
|
||||||
array(null, 'Cannot autowire service "foo": method "Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setProtectedMethod()" must be public.'),
|
array(null, 'Cannot autowire service "foo": method "Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setProtectedMethod()" must be public.'),
|
||||||
);
|
);
|
||||||
|
Reference in New Issue
Block a user