yii2: 2.0.36 breaks Codeception tests
What steps will reproduce the problem?
After install 2.0.36 update all our codeception tests became broken. Reason: https://github.com/yiisoft/yii2/pull/18127. If I remove
elseif (is_array($dependency)) {
$dependencies[$index] = $this->resolveDependencies($dependency, $reflection);
}
from \yii\di\Container::resolveDependencies, tests become OK.
First of all, it IS breaking change a-priory because of Container::resolveDependencies behaviour change.
Problem starts here: vendor/codeception/codeception/src/Codeception/Lib/Connector/Yii2.php:75. Connector use Yii::createObject (and therefore dependency container) for Application creation. We have application config like this:
return [
...
'container' => [
'definitions' => [
common\interfaces\NewsletterEmailGeneratorInterface::class => [
['class' => common\components\newsletter\NewsletterEmailGenerator::class],
[
di\Instance::of(web\View::class),
di\Instance::of('internalFilesystem'),
]
...
Recursive resolveDependencies call try get ‘internalFilesystem’ component, but it’s not configured in DI Container on this stage! We got:
[yii\base\InvalidConfigException] Failed to instantiate component or class "internalFilesystem".
Example of stack trace:
Test unit/commands/news/news_domain/NewsBorrowCommandTest.php:testInvalidData
[yii\base\InvalidConfigException] Failed to instantiate component or class "internalFilesystem".
.../vendor/yiisoft/yii2/di/Container.php:449
.../vendor/yiisoft/yii2/di/Container.php:447
.../vendor/yiisoft/yii2/di/Container.php:374
.../vendor/yiisoft/yii2/di/Container.php:159
.../vendor/yiisoft/yii2/di/Container.php:484
.../vendor/yiisoft/yii2/di/Container.php:491
.../vendor/yiisoft/yii2/di/Container.php:491
.../vendor/yiisoft/yii2/di/Container.php:491
.../vendor/yiisoft/yii2/di/Container.php:491
.../vendor/yiisoft/yii2/di/Container.php:395
.../vendor/yiisoft/yii2/di/Container.php:159
.../vendor/yiisoft/yii2/BaseYii.php:365
.../vendor/codeception/codeception/src/Codeception/Lib/Connector/Yii2.php:75
.../vendor/codeception/codeception/src/Codeception/Lib/Connector/Yii2.php:53
.../vendor/codeception/codeception/src/Codeception/Module/Yii2.php:185
.../vendor/codeception/codeception/src/Codeception/Subscriber/Module.php:56
| Q | A |
|---|---|
| Yii version | 2.0.36 |
| PHP version | 7.4 |
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Comments: 38 (33 by maintainers)
Commits related to this issue
- WIP: Fix #18245 — committed to hiqsol/yii2 by hiqsol 4 years ago
- Bug #18245: Make resolving DI references inside of arrays in dependencies optional Co-authored-by: Alexander Makarov <sam@rmcreative.ru> Co-authored-by: Andrii Vasyliev <sol@hiqdev.com> — committed to yiisoft/yii2 by SamMousa 4 years ago
It would break for people who have subclassed the application object…
I need to take a closer look. I hope to fix the issue without making the feature optional. Is it ok?
Yeah, I’m aware of the pros and cons from our discussion regarding Yii3 DI package 😉
Anyway, for Yii2 it is a breaking change which to me means we shouldn’t have applied it and therefore should revert it as soon as possible.
If you want to have your use case in a BC way, why not add support to arrays for
Instance::of()? Like this could be done in a subclass even:So we would get:
This makes it more explicit, while keeping the usability you mention.
@SamMousa I agree with your statement above:
for these advanced cases just relying on a \Closure. In our applications we stick with this approach. I even think thatis redundant. But it’s outside of this ticket.
First of all: #18127 seems to be bad regardless of this specific issue:
Then there is the Yii2 issue of attempting to have everything in the configuration array. Things like the logger, errorhandlers and possibly the container get populated from the application config, but they are not part of the application instance.
The application in the codeception module is recreated for every test, but the container is not. As @DmLapin correctly notes, the module uses the container to ask for an application object given a configuration array. If this array refers to objects that are not yet configured, because they are configured by the application at some later stage this will cause issues.
I see several options to remedy the situation:
I think 3 is the worst solution; the whole point of the module is to NOT know how the configuration format works, it is not relevant if we let Yii’s own code figure that out. I believe 2 is a bad thing to ask from a user even if it (subjectively, in my view) improves their code; especially considering Yii2 should not be releasing BC breaking versions.
The option 1 is best in my opinion, since we have only had the feature for a very short while there will not be a lot of applications that are not under active development that use it. Apps under active development that use such a new feature will likely be able to step away from it. Upon further inspection, I think the
resolveDependenciescall should also be more secure in things like forwarding the$reflectionvariable, since it makes no sense to use that for nested array dependencies…In conclusion, I propose reverting #18127 and for these advanced cases just relying on a
\Closurefor configuration of the DI container. It is cleaner and more readable for all PHP users instead of using some secret array language understood only by Yii developers. The array config should be limited to simple cases in all other cases it imo more sensible to use a (static) closure.