P
P
Paulus2016-08-16 16:53:59
Yii
Paulus, 2016-08-16 16:53:59

Is the approach to implementing DI in Yii2 projects correct or not?

Hello.
UPD: I'll just leave it here
stackoverflow.com/questions/24381708/default-value...
In my Yii2 projects, I use the following construction quite actively:

use app\models\Dependency;

class Model extends yii\base\Model
{
    public $dependencyClass;
    public function __construct($config = [])
    {
        if (!isset($config['dependencyClass'])) {
            $this->dependencyClass = new Dependency();
        }
        parent::__construct($config);
    }
}

here Model is a model, and Dependency is some kind of dependency, such as an associated class.
Further in the class, if you need to use a dependency, then I refer to $this->dependencyClass, for example:
public function getDependencies()
{
    return $this->hasMany($this->dependencyClass->className(), ['modelId' => 'id']);
}

The habit of using such a construction appeared quite a long time ago, and in general the idea was to:
a) collect all dependencies in one place (class constructor), and not scatter calls throughout the class;
b) have a "default" dependency that would be included if the dependency was not explicitly passed to the constructor;
c) to be able to inject dependencies, which helps a lot, for example, in unit tests (where I make dependencies mocks).
I just wanted to ask for advice, perhaps in such an implementation there are some anti-patterns and in general a smell and the listed approaches can be implemented somehow more differently?
Thank you.

Answer the question

In order to leave comments, you need to log in

2 answer(s)
I
Ivan Koryukov, 2016-08-16
@MadridianFox

Some one-sided solution:

if (!isset($config['dependencyClass'])) {
    $this->dependencyClass = new Dependency();
}

It seems like dependency injection, but still there is a hard connection.
Why didn’t you like the native Yii service locator through the config?
It would be possible to configure the dependency as a yii component like this:
//config/web.php
"components"=>[
    //...
    "model_deps"=>[
          "class"=>"app\components\ModelDependenciesService",
          "default_dependency"=>"app\model\model_2",
          "dependencies"=>[
                 "app\model\model_1"=>[
                        "dep_1"=>"app\model\model_3",
                        //....
                  ]
           ]
     ]
    //...
]
// в базовом классе модели
public function getDepClass($dep_name){
    retrn Yii::$app->model_deps->depClass(static,$dep_name); // не помню точно как текущий класс брать
}
// где-то в модели
public function getDependencies()
{
    return $this->hasMany($this->getDepClass($dep_name), ['modelId' => 'id']);
}

In the ModelDependenciesService class, of course, you need to implement the depClass method, which will return the dependency class or the default class if the dependency is not defined.

E
Elena Stepanova, 2016-08-16
@Insolita

What's wrong with the classic version?
Declare the interface that the dependent model needs and directly into its constructor, you can inherit from ActiveRecordInterface
Let your model be Post with Dependency Comments

interface PostCommentModelInterface // можно extends ActiveRecordInterface
     {
        /**
         * @return ActiveRecord[]|Comment[]
        **/
            public function findForPost();

    }

     class Model extends yii\base\Model
     {
           protected $commentModel;
           public function __construct(PostCommentModelInterface $commentModel, $config = [])
          {
                $this->commentModel = $commentModel;
                parent::__construct($config);
           }
    ]

And the dependencies are registered at the beginning of the application after running the config, in the bootstrap.php file
like Yii::$container->set('\app\modules\posts\PostCommentModelInterface','\app\modules\comments\CommenModel')
only create a model it will be necessary not new Post(), but Yii::createObject(['class'=>'\app\module\Post']) then the dependency will automatically be connected ... well, or manually new Post(new Comment())
or alternative but less beautiful option
...
     protected $commentModel;

      public function __construct(\yii\container\Container $container, $config = [])
      {
         $this->commentModel = $container->get('\app\modules\posts\PostCommentModelInterface'');
          parent::__construct($config);
       }
   ...

really confuses your $this->hasMany ... with extends yii\base\Model ...
look here about patterns, especially in the comments
https://habrahabr.ru/post/183658/#comment_6392902

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question