Hi there,
In some circumstances, for some reason, container is having problem with resolving services.
If a service (concrete) implements an interface (abstract) and this service (concrete) requires additional service provider (e.g. when value from config is injected to class), you may end up with Unresolvable dependency resolving error. It happens when both binding abstract interface to concrete class and injecting dependencies is split between two deferred service providers.
Interesting part: automatic injection of such interface works for console commands, but does not work for controllers (not sure, but there might be more contexts affected)
composer installphp artisan command:test # It should work finephp artisan serve do a request to "/test" endpoint # Ends up with HTTP 500; logs contain "Unresolvable dependency resolving" error Hey there,
Can you first please try one of the support channels below? If you can actually identify this as a bug, feel free to report back and I'll gladly help you out and re-open this issue.
Thanks!
@driesvints i went to IRC channel and asked for advice, as you suggested, just in case. We could not find a working solution and someone even mentioned:
looks like changing this Container::make() override to override Container::getConcrete() instead and do the deferred loading there would work better https://github.com/laravel/framework/blob/6.x/src/Illuminate/Foundation/Application.php#L768-L777
I think it might be worthwhile to look into this issue. Please let me know what you think.
Thanks!
You're not binding the scalar dependency here with binding a primitive: https://github.com/rkazaniszyn/laravel-deferred-providers-bug/blob/master/app/Providers/SampleInterfaceProvider.php#L19
Yes i know, i did it on purpose to illustrate the problem. Primitive binding isn't there, because this provider only provides SampleInterface, not the concrete implementation of this interface.
I know how to work around this problem, but i wanted to provide an example.
Reasons why i reported this and got back to you:
Looks like this change might be the case: https://github.com/laravel/framework/commit/d0a7adb751009fbc4e3af4fa88bfd8e438bab767#diff-52441e04e14c52275cd5d09e8f958981L264
I think it is indeed a bug. It also worked for me in 5.7 and stopped working in 5.8.
Moreover, if you try to inject implementation first and then interface, it works. If you switch order and want to inject something by interface first, it does not work. Containter behaves different depending on order of resolved classes, which is even more dangerous, because it "sometimes" works and could be easily missed while testing.
The problem is probably caused by this line:
https://github.com/illuminate/container/blob/b42e5ef939144b77f78130918da0ce2d9ee16574/Container.php#L264
In 5.7 it used $container->make() (https://github.com/illuminate/container/blob/8c3a75e464d59509ae88db152cab61a3f115b9ec/Container.php#L264) which executes method from Illuminate\Foundation\Application and therefore loads deferred providers. Changing it to $container->resolve() executes method from Illuminate\Container\Container, which does not know anything about deferred providers.
Reverting this line to state from 5.7 ($container->make()) seems to fix the issue.
Something that worked till 5.7 and stoped worked on 5.8 (without mention anywhere) looks like bug to me.
Submit a PR with a failing test to prove it is a bug in the container.
Most helpful comment
I think it is indeed a bug. It also worked for me in 5.7 and stopped working in 5.8.
Moreover, if you try to inject implementation first and then interface, it works. If you switch order and want to inject something by interface first, it does not work. Containter behaves different depending on order of resolved classes, which is even more dangerous, because it "sometimes" works and could be easily missed while testing.
The problem is probably caused by this line:
https://github.com/illuminate/container/blob/b42e5ef939144b77f78130918da0ce2d9ee16574/Container.php#L264
In 5.7 it used
$container->make()(https://github.com/illuminate/container/blob/8c3a75e464d59509ae88db152cab61a3f115b9ec/Container.php#L264) which executes method fromIlluminate\Foundation\Applicationand therefore loads deferred providers. Changing it to$container->resolve()executes method fromIlluminate\Container\Container, which does not know anything about deferred providers.Reverting this line to state from 5.7 (
$container->make()) seems to fix the issue.