Yii - Injection de dépendance

Un conteneur DI (injection de dépendances) est un objet qui sait comment instancier et configurer des objets. Yii fournit le conteneur DI via leyii\di\Container class.

Il prend en charge les types suivants de DI -

  • Setter et injection de propriété
  • Injection appelable PHP
  • Injection de constructeur
  • Injection d'action du contrôleur

Le conteneur DI prend en charge l'injection de constructeur à l'aide d'indices de type -

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

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

Les injections de propriété et de setter sont prises en charge via des 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'),
   ]);
?>

Dans le cas de l'injection appelable PHP, le conteneur utilisera un rappel PHP enregistré pour construire de nouvelles instances d'une classe -

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

L'injection d'action de contrôleur est un type de DI où les dépendances sont déclarées à l'aide des indicateurs de type. Il est utile pour garder les contrôleurs MVC minces, légers et minces -

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

Vous pouvez utiliser le yii\db\Container::set() méthode pour enregistrer les dépendances -

<?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);
?>

Utilisation du DI

Step 1 - À l'intérieur du components dossier créer un fichier appelé MyInterface.php avec le code suivant.

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

Step 2 - Dans le dossier des composants, créez deux fichiers.

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 - Maintenant, ajoutez un actionTestInterface au 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 - Aller à http://localhost:8080/index.php?r=site/test-interface vous devriez voir ce qui suit.

Cette approche est pratique car nous pouvons définir des classes à un endroit et un autre code utilisera automatiquement de nouvelles classes.