-
-
Notifications
You must be signed in to change notification settings - Fork 9.7k
Description
Symfony version(s) affected: 4.1.6 (but probably back to 3.4)
Description
Hey guys!
I found a very deep bug related to autowiring & the container resources. Steps to reproduce are below, but here is a description of the issue. Also, this seems to only affect the debug:config
and related commands where the container is rebuilt manually. The normal container does not seem to suffer from this problem. The key part is 3 - I believe that's where the bug actually exists.
-
In
AutowirePass
, a type somewhere in the system cannot be guessed. And so,AutowirePass:: populateAvailableTypes()
is called to try to determine a good error message. This is already slightly flawed, as the error message may ultimately be "hidden" because the definition in question is removed... and so we're doing work unnecessarily. But, that's not the bug - just a little performance thing. -
The
AutowirePass::populateAvailableTypes()
eventually calls:$this->container->getReflectionClass($definition->getClass(), false)
on each definition. -
Here is the important part: IF the class in question exists (e.g.
DoctrineOrmTypeGuesser
was the culprit for me) but some of the interfaces that it implements do NOT exist, then theContainerBuilder::getReflectionClass()
method will create and use aClassExistenceResource
for that class where$exists = false
. -
The next time the container checks to see if its cache is fresh, it will always return false because the class above (e.g.
DoctrineOrmTypeGuesser
) DOES exist, but itsClassExistenceResource
expects it to not exist.
How to reproduce
Reproducer: https://github.com/weaverryan/autowiring-class-existence-reproducer
Steps:
-
Install
form
(because it has a good example -DoctrineOrmTypeGuesser
) of a class that will be registered as a service, even though some of its parent interfaces do not exist in the app -
Create an "autowiring failure" situation that will ultimately be silent. Easy way: add a controller and type-hint it with an entity.
-
Install
security
. Not needed for the bug - it's just an easy way to "see" the bug... because the bad behavior causes a weird situation. -
Run
rm -rf var/cache/* && php bin/console debug:config framework
. You'll see this exception:
The service "debug.security.firewall" has a dependency on a non-existent service ".security.
request_matcher.zfHj2lW".
This is not really the bug - it's just a "symptom" of the fact that debug:config
will build the container multiple times, because after building it, it immediately looks "stale".
Possible Solution
Make ContainerBuilder::getReflectionClass()
a bit smarter: only add the class existence resource if the class really does not exist?