-
-
Notifications
You must be signed in to change notification settings - Fork 45
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
[WIP] Proposal: DI configuration for application #61
Comments
Looking at the first code sample:
IMHO these 2 things simplify configuration a lot. The goal you want to achieve (module specific DI configurations) can be achieved in 2 ways. First, simply by merging configs. Every package (extension) provides own configuration that is merged by config plugin in a way that allows to have default configuration in package and tune (override) it in user project. Unfortunately, there is no good documentation for this practice but you can look A second way, with a configuration like this: return [
'app' => [
'modules' => [
'mymodule' => [
'__class' => My\Module::class,
'container' => Reference::to('mycontainer'),
],
],
],
'mycontainer' => [
'__class' => \yii\di\Container::class,
'__construct()' => [
'definitions' => [
'specificEngine' => EngineMarkOne::class,
],
'parent' => Reference::to('container'),
],
],
]; This configuration can work right now only Personally, I prefer config merging. And it works right now out of the 3.0 box. |
I don't think this necessarily makes sense (even though it is what I already use in some production apps).
Why? What does this improve? This means that anything configured in DI is available via the application. The application then becomes a global service locator containing anything in the application.
The approach that I propose is more flexible and doesn't require the extension to use a Yii DI container, any PSR-11 container with delegated lookup will work.
Modules can be nested, the suggested configuration forces users to repeat configuration for every module. Instead a module should always get a DI container injected since it needs a DI container to instantiate its stuff; this proposal gives a module a scoped container that will resolve the things a module needs transparently.
Configuration merging is effective, but not necessarily easy to use. From a performance perspective I think the scoped approach will have better performance and will be more practical. Consider a nested structure like this: The example configuration you linked to is really verbose; it for some reason defines an alias for every class, giving me the fear that the application then uses that alias to get the actual implementation from the DI container. This is exactly the opposite of where we need to go; this is just using the service locator pattern again. I think there are lots of use cases that the configuration merging approach does not yet support; and when it does, it will become more messy and complex. Putting all definitions in a DI container and flattening the tree doesn't improve things, it makes them worse! |
I've been reading a bit more about the config plugin you created @hiqsol (https://hiqdev.com/pages/articles/app-organization) I think the idea breaks encapsulation in a big way. <?php
return [
'components' => [
'i18n' => [
'translations' => [
'my-category' => [
'class' => \yii\i18n\PhpMessageSource::class,
'basePath' => '@myvendor/myplugin/messages',
],
],
],
],
]; What if I my i18n component / service is not called i18n; or what if it doesn't have a translations property? |
Looking at your first example again: $appConfig = [
'id' => 'app1',
'di' => [
EngineInterface::class => EngineMarkOne::class,
'specificEngine' => EngineMarkTwo::class
],
]; Where are you going to process 'di' config option? In application? |
Yes definitely. The idea is as follows:
The fact is that you cannot do pure DI if you do not know what code will run (it's not feasible or desirable to instantiate all modules / controllers / actions). In my example the |
We have eliminated "components" concept in regards to config because components are essentially any classes registered as singletons. Usually these are called services. We want no difference between Yii components and third party services. There should be no need to write as many wrapper extensions as we did for 1.1 and 2.0. |
While composite container is theoretically quite cool, there hardly ever be a third party container involved along with native container. That makes little sense for the application to do it. For extensions and modules it makes perfect sense though. |
Using container as service locator isn't necessary. |
Then you won't have a getter on the application? |
Actually during transitional phases this can be quite common. Note that there is no overhead in supporting it since we are coding to the PSR-11 interface.
How do we solve this for things like AR? yiisoft/active-record#16 |
I didn't say that we should get rid of it. I said it's not necessary. At least for majority of cases because of reflection-based injection.
Transitional phases?
Probably we should not. |
This is a proposal for how we could configure DI in a Yii application.
The module then interprets the configuration;
This will allow us to have module specific DI configurations; provide default configurations from extensions.
As in Yii2 the getters on module essentially implement the service locator pattern when used directly. In this case we use the DI container to back them.
The text was updated successfully, but these errors were encountered: