Hello all,
first: I read the documentation any many stack overflow questions + I’ve searched in the forum for a long time and I really tried to understand how to use the DI container but I was not really able to fully gasp into it.
I use Yii2 actively every single day for 4 years now with Craft CMS. I don’t know if this is somehow important, but I wanted mention it because Craft CMS only relies on the service locator and does not use the DI.
Looking at the 2nd example in the docs below resolving-dependencies
$container = new Container;
$container->set('yii\db\Connection', [
'dsn' => '...',
]);
$container->set('app\models\UserFinderInterface', [
'class' => 'app\models\UserFinder',
]);
$container->set('userLister', 'app\models\UserLister');
$lister = $container->get('userLister');
I really don’t understand when/how dependencies are passed via $config
variable and when they are passed via attribute.
For example 'yii\db\Connection'
has no custom constructor so dns etc are passed via $config
parameter and then set via Yii::configure
but why/how does the UserFinder
receive the Connection $db
?
How can I use that actively?
I’ve made some tests, so you maybe can understand my confusion. There is no need to read this if you already see my problem.
I have a module and in this module, there are certain components defined via setComponents
. Currently all those rely only on the service locator, so they are all full of Yii::app
and I tried to change that in order to understand how DI could be used instead.
Judging from the example above my first thought was: maybe it is passed automatically like here
public function __construct(Connection $db, $config = [])
....
$container->set('app\models\UserFinderInterface', [
'class' => 'app\models\UserFinder',
]);
To debug and test it this is my Fractals component,
class Fractals extends Component
{
/**
* The DB connection
*
* @var Connection $db
*/
public $db;
/**
* Fractals constructor.
*
* @param \yii\db\Connection|null $db the dependency that should be injected
* @param null $foo just a random variable for testing
* @param array $config
*/
public function __construct(Connection $db = null, $foo = null, $config = [])
{
echo "<pre>";
var_dump($db);
var_dump($foo);
var_dump(array_keys($config));
echo "</pre>";
die();
parent::__construct($config);
}
}
So I did this in my Module (Fractals is my component)
Yii::$container->set(Fractals::class, [
'class' => Fractals::class
]);
$this->setComponents([
// ...
'fractals' => Fractals::class
]);
// later I grab those in my Controllers or other components via
Module::getInstance()->get('fractals');
The first result was
$db = null
$foo = null
$config = []
I thought maybe I have to include all the dependencies there, it’s not mentioned in the docs this way but maybe it helps. Thus I did
Yii::$container->set(Fractals::class, [
'class' => Fractals::class,
'db' => Yii::$container->get('db')
]);
The result was an exception Failed to instantiate component or class "db".
Okay… so I tested it with
Yii::$container->set(Fractals::class, [
'class' => Fractals::class,
'db' => Yii::$app->get('db')
]);
and the result was
$db = null
$foo = null
$config = [
'db' => // the correct DB connection
]
But that’s actually not what I thought, the example function in the docs was
public function __construct(Connection $db, $config = [])
So maybe I need to register the dependency first in th DI?
Yii::$container->set('db', Yii::$app->get('db'));
Yii::$container->set(Fractals::class, [
'class' => Fractals::class,
]);
But that prints the same all empty state
$db = null
$foo = null
$config = []
and a mix of the two above
Yii::$container->set('db', Yii::$app->get('db'));
Yii::$container->set(Fractals::class, [
'class' => Fractals::class,
'db' => Yii::$container->get('db')
]);
only passes the parameter via $config
array as well
$db = null
$foo = null
$config = [
'db' => // the correct DB connection
]
Of course I could just keep that and do it that way, but I would like to understand why it does not work and how it is supposed to be used. I’ve spend hours and see all those examples all over the place but they do not work for me for whatever reason.