Yii – Dependency Injection

  • Post author:
  • Post category:Yii
  • Post comments:0 Comments

A DI(dependency injection) container is an object that knows how to instantiate and configure objects. Yii provides the DI container via the yii\di\Container class.

It supports the following kinds of DI βˆ’

  • Setter and property injection
  • PHP callable injection
  • Constructor injection
  • Controller action injection

The DI container supports constructor injection with the help of type hints βˆ’

class Object1 {
   public function __construct(Object2 $object2) {

   }
}
$object1 = $container->get('Object1');
// which is equivalent to the following:
$object2 = new Object2;
$object1 = new Object1($object2);

Property and setter injections are supported through configurations βˆ’

<?php
   use yii\base\Object;
   class MyObject extends Object {
      public $var1;
      private $_var2;
      public function getVar2() {
         return $this->_var2;
      }
      public function setVar2(MyObject2 $var2) {
         $this->_var2 = $var2;
      }
   }
   $container->get('MyObject', [], [
      'var1' => $container->get('MyOtherObject'),
      'var2' => $container->get('MyObject2'),
   ]);
?>

In case of the PHP callable injection, the container will use a registered PHP callback to build new instances of a class βˆ’

$container->set('Object1', function () {
   $object1 = new Object1(new Object2);
   return $object1;
});
$object1 = $container->get('Object1');

Controller action injection is a type of DI where dependencies are declared using the type hints. It is useful for keeping the MVC controllers slim light-weighted and slim βˆ’

public function actionSendToAdmin(EmailValidator $validator, $email) {
   if ($validator->validate($email)) {
      // sending email
   }
}

You can use the yii\db\Container::set() method to register dependencies βˆ’

<?php
   $container = new \yii\di\Container;
   // register a class name as is. This can be skipped.
   $container->set('yii\db\Connection');
   // register an alias name. You can use $container->get('MyObject')
   // to create an instance of Connection
   $container->set('MyObject', 'yii\db\Connection');
   // register an interface
   // When a class depends on the interface, the corresponding class
   // will be instantiated as the dependent object
   $container->set('yii\mail\MailInterface', 'yii\swiftmailer\Mailer');
   // register an alias name with class configuration
   // In this case, a "class" element is required to specify the class
   $container->set('db', [
      'class' => 'yii\db\Connection',
      'dsn' => 'mysql:host=127.0.0.1;dbname = helloworld',
      'username' => 'vladimir',
      'password' => '12345',
      'charset' => 'utf8',
   ]);
   // register a class with configuration. The configuration
   // will be applied when the class is instantiated by get()
   $container->set('yii\db\Connection', [
      'dsn' => 'mysql:host=127.0.0.1;dbname = helloworld',
      'username' => 'vladimir',
      'password' => '12345',
      'charset' => 'utf8',
   ]);
   // register a PHP callable
   // The callable will be executed each time when $container->get('db') is called
   $container->set('db', function ($container, $params, $config) {
      return new \yii\db\Connection($config);
   });
   // register a component instance
   // $container->get('pageCache') will return the same instance each time when it 
      //is called
   $container->set('pageCache', new FileCache);
?>

Using the DI

Step 1 βˆ’ Inside the components folder create a file called MyInterface.php with the following code.

<?php
   namespace app\components;
   interface MyInterface {
      public function test();
   }
?>

Step 2 βˆ’ Inside the components folder, create two files.

First.php βˆ’

<?php
   namespace app\components;
   use app\components\MyInterface;
   class First implements MyInterface {
      public function test() {
         echo "First class <br>";
      }
   }
?>

Second.php βˆ’

<?php
   app\components;
   use app\components\MyInterface;
      class Second implements MyInterface {
      public function test() {
         echo "Second class <br>";
      }
   }
?>

Step 3 βˆ’ Now, add an actionTestInterface to the SiteController.

public function actionTestInterface() {
   $container = new \yii\di\Container();
   $container->set
      ("\app\components\MyInterface","\app\components\First");
   $obj = $container->get("\app\components\MyInterface");
   $obj->test(); // print "First class"
   $container->set
      ("\app\components\MyInterface","\app\components\Second");
   $obj = $container->get("\app\components\MyInterface");
   $obj->test(); // print "Second class"
}

Step 4Β βˆ’ Go toΒ http://localhost:8080/index.php?r=site/test-interfaceΒ you should see the following.

Leave a Reply