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

[Config] Make ClassExistenceResource throw on invalid parents #23573

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 19, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
[Config] Make ClassExistenceResource throw on invalid parents
  • Loading branch information
nicolas-grekas committed Jul 18, 2017
commit 53b01903ceb91e1b0fb17c0f1a66faae3d68c51d
25 changes: 22 additions & 3 deletions 25 src/Symfony/Component/Config/Resource/ClassExistenceResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializ
private $exists;

private static $autoloadLevel = 0;
private static $autoloadedClass;
private static $existsCache = array();

/**
Expand Down Expand Up @@ -57,6 +58,8 @@ public function getResource()

/**
* {@inheritdoc}
*
* @throws \ReflectionException when a parent class/interface/trait is not found
*/
public function isFresh($timestamp)
{
Expand All @@ -68,12 +71,13 @@ public function isFresh($timestamp)
if (!self::$autoloadLevel++) {
spl_autoload_register(__CLASS__.'::throwOnRequiredClass');
}
$autoloadedClass = self::$autoloadedClass;
self::$autoloadedClass = $this->resource;

try {
$exists = class_exists($this->resource) || interface_exists($this->resource, false) || trait_exists($this->resource, false);
} catch (\ReflectionException $e) {
$exists = false;
} finally {
self::$autoloadedClass = $autoloadedClass;
if (!--self::$autoloadLevel) {
spl_autoload_unregister(__CLASS__.'::throwOnRequiredClass');
}
Expand Down Expand Up @@ -112,7 +116,10 @@ public function unserialize($serialized)
*/
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();
$autoloadFrame = array(
'function' => 'spl_autoload_call',
Expand All @@ -138,6 +145,18 @@ private static function throwOnRequiredClass($class)
case 'is_callable':
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,8 @@ private function doProcessValue($value, $isRoot = false)
if (!$value instanceof Definition || !$value->isAutowired() || $value->isAbstract() || !$value->getClass()) {
return $value;
}
if (!$reflectionClass = $this->container->getReflectionClass($value->getClass())) {
$this->container->log($this, sprintf('Skipping service "%s": Class or interface "%s" does not exist.', $this->currentId, $value->getClass()));
if (!$reflectionClass = $this->container->getReflectionClass($value->getClass(), false)) {
$this->container->log($this, sprintf('Skipping service "%s": Class or interface "%s" cannot be loaded.', $this->currentId, $value->getClass()));

return $value;
}
Expand Down Expand Up @@ -388,7 +388,7 @@ private function populateAvailableType($id, Definition $definition)
unset($this->ambiguousServiceTypes[$type]);
}

if ($definition->isDeprecated() || !$reflectionClass = $this->container->getReflectionClass($definition->getClass())) {
if ($definition->isDeprecated() || !$reflectionClass = $this->container->getReflectionClass($definition->getClass(), false)) {
return;
}

Expand Down Expand Up @@ -444,7 +444,7 @@ private function set($type, $id)
*/
private function createAutowiredDefinition($type)
{
if (!($typeHint = $this->container->getReflectionClass($type)) || !$typeHint->isInstantiable()) {
if (!($typeHint = $this->container->getReflectionClass($type, false)) || !$typeHint->isInstantiable()) {
return;
}

Expand Down Expand Up @@ -478,8 +478,8 @@ private function createAutowiredDefinition($type)

private function createTypeNotFoundMessage(TypedReference $reference, $label)
{
if (!$r = $this->container->getReflectionClass($type = $reference->getType())) {
$message = sprintf('has type "%s" but this class does not exist.', $type);
if (!$r = $this->container->getReflectionClass($type = $reference->getType(), false)) {
$message = sprintf('has type "%s" but this class cannot be loaded.', $type);
} else {
$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));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ private function updateDefinition(ContainerBuilder $container, $id, Definition $
$class = $factory[0];
}

if (!$m = $container->getReflectionClass($class)) {
if (!$m = $container->getReflectionClass($class, false)) {
return;
}
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ private function processDefinition(ContainerBuilder $container, $id, Definition
$instanceofTags = array();

foreach ($conditionals as $interface => $instanceofDefs) {
if ($interface !== $class && (!$container->getReflectionClass($class))) {
if ($interface !== $class && (!$container->getReflectionClass($class, false))) {
continue;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -337,12 +337,15 @@ public function addClassResource(\ReflectionClass $class)
* Retrieves the requested reflection class and registers it for resource tracking.
*
* @param string $class
* @param bool $throw
*
* @return \ReflectionClass|null
*
* @throws \ReflectionException when a parent class/interface/trait is not found and $throw is true
*
* @final
*/
public function getReflectionClass($class)
public function getReflectionClass($class, $throw = true)
{
if (!$class = $this->getParameterBag()->resolveValue($class)) {
return;
Expand All @@ -357,6 +360,9 @@ public function getReflectionClass($class)
$classReflector = $resource->isFresh(0) ? false : new \ReflectionClass($class);
}
} catch (\ReflectionException $e) {
if ($throw) {
throw $e;
}
$classReflector = false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ public function testDontTriggerAutowiring()

/**
* @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()
{
Expand All @@ -374,7 +374,7 @@ public function testClassNotFoundThrowsException()

/**
* @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()
{
Expand Down Expand Up @@ -744,7 +744,7 @@ public function testNotWireableCalls($method, $expectedMsg)
public function provideNotWireableCalls()
{
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(null, 'Cannot autowire service "foo": method "Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setProtectedMethod()" must be public.'),
);
Expand Down
Morty Proxy This is a proxified and sanitized view of the page, visit original site.