Skip to content

Commit a956a76

Browse files
committed
bug symfony#25932 Don't stop PSR-4 service discovery if a parent class is missing (derrabus)
This PR was merged into the 3.4 branch. Discussion ---------- Don't stop PSR-4 service discovery if a parent class is missing | Q | A | ------------- | --- | Branch? | 3.4 | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | symfony#25929 | License | MIT | Doc PR | N/A Commits ------- 3d6c3ba Don't stop PSR-4 service discovery if a parent class is missing.
2 parents d5ff094 + 3d6c3ba commit a956a76

File tree

6 files changed

+52
-7
lines changed

6 files changed

+52
-7
lines changed

src/Symfony/Component/DependencyInjection/Loader/FileLoader.php

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,16 @@ public function registerClasses(Definition $prototype, $namespace, $resource, $e
6060
$interfaces = array();
6161
$singlyImplemented = array();
6262

63-
foreach ($classes as $class) {
63+
foreach ($classes as $class => $errorMessage) {
6464
if (interface_exists($class, false)) {
6565
$interfaces[] = $class;
6666
} else {
67-
$this->setDefinition($class, unserialize($serializedPrototype));
67+
$this->setDefinition($class, $definition = unserialize($serializedPrototype));
68+
if (null !== $errorMessage) {
69+
$definition->addError($errorMessage);
70+
71+
continue;
72+
}
6873
foreach (class_implements($class, false) as $interface) {
6974
$singlyImplemented[$interface] = isset($singlyImplemented[$interface]) ? false : $class;
7075
}
@@ -139,13 +144,25 @@ private function findClasses($namespace, $pattern, $excludePattern)
139144
if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\\\\[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)*+$/', $class)) {
140145
continue;
141146
}
147+
148+
try {
149+
$r = $this->container->getReflectionClass($class);
150+
} catch (\ReflectionException $e) {
151+
$classes[$class] = sprintf(
152+
'While discovering services from namespace "%s", an error was thrown when processing the class "%s": "%s".',
153+
$namespace,
154+
$class,
155+
$e->getMessage()
156+
);
157+
continue;
158+
}
142159
// check to make sure the expected class exists
143-
if (!$r = $this->container->getReflectionClass($class)) {
160+
if (!$r) {
144161
throw new InvalidArgumentException(sprintf('Expected to find class "%s" in file "%s" while importing services from resource "%s", but it was not found! Check the namespace prefix used with the resource.', $class, $path, $pattern));
145162
}
146163

147164
if ($r->isInstantiable() || $r->isInterface()) {
148-
$classes[] = $class;
165+
$classes[$class] = null;
149166
}
150167
}
151168

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\BadClasses;
4+
5+
class MissingParent extends MissingClass
6+
{
7+
}

src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/prototype.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
->tag('baz');
1010
$di->load(Prototype::class.'\\', '../Prototype')
1111
->autoconfigure()
12-
->exclude('../Prototype/{OtherDir}')
12+
->exclude('../Prototype/{OtherDir,BadClasses}')
1313
->factory('f')
1414
->deprecate('%service_id%')
1515
->args(array(0))
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
33
<services>
4-
<prototype namespace="Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\" resource="../Prototype/*" exclude="../Prototype/{OtherDir}" />
4+
<prototype namespace="Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\" resource="../Prototype/*" exclude="../Prototype/{OtherDir,BadClasses}" />
55
</services>
66
</container>
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
services:
22
Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\:
33
resource: ../Prototype
4-
exclude: '../Prototype/{OtherDir}'
4+
exclude: '../Prototype/{OtherDir,BadClasses}'

src/Symfony/Component/DependencyInjection/Tests/Loader/FileLoaderTest.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
2626
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
2727
use Symfony\Component\DependencyInjection\Reference;
28+
use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\BadClasses\MissingParent;
2829
use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\OtherDir\AnotherSub\DeeperBaz;
2930
use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\OtherDir\Baz;
3031
use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Foo;
@@ -163,6 +164,26 @@ public function testNestedRegisterClasses()
163164
$this->assertFalse($alias->isPrivate());
164165
}
165166

167+
public function testMissingParentClass()
168+
{
169+
$container = new ContainerBuilder();
170+
$container->setParameter('bad_classes_dir', 'BadClasses');
171+
$loader = new TestFileLoader($container, new FileLocator(self::$fixturesPath.'/Fixtures'));
172+
173+
$loader->registerClasses(
174+
(new Definition())->setPublic(false),
175+
'Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\BadClasses\\',
176+
'Prototype/%bad_classes_dir%/*'
177+
);
178+
179+
$this->assertTrue($container->has(MissingParent::class));
180+
181+
$this->assertSame(
182+
array('While discovering services from namespace "Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\BadClasses\", an error was thrown when processing the class "Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\BadClasses\MissingParent": "Class Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\BadClasses\MissingClass not found".'),
183+
$container->getDefinition(MissingParent::class)->getErrors()
184+
);
185+
}
186+
166187
/**
167188
* @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
168189
* @expectedExceptionMessageRegExp /Expected to find class "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\Prototype\\Bar" in file ".+" while importing services from resource "Prototype\/Sub\/\*", but it was not found\! Check the namespace prefix used with the resource/

0 commit comments

Comments
 (0)