Использование обратного вызова жизненного цикла Doctrine для внедрения зависимостей во время гидратации

#php #dependency-injection #doctrine-orm

#php #внедрение зависимостей #doctrine-orm

Вопрос:

Я разрабатываю php-приложение с Doctrine (без symfony) и, следовательно, без контейнера DI. Я использую внедрение зависимостей в одной из моих сущностей, которой нужен сервис.

     Class A implements Ia
    {

        public function __constructor( requiredServiceClass $requiredService = NULL )
        {
            if ($requiredService === NULL) {
                $this->requiredService = new requiredServiceClass();
            {
                $this->requiredService = $requiredService;
            }
        }

    }
  

Все работает нормально, но при гидратации Doctrine не вызывает __constructor, в результате зависимость не вводится.
Каков наилучший способ решить эту проблему?

В настоящее время я использую события жизненного цикла Doctrine для обратного вызова метода для установки зависимости. Итак, сначала я добавляю обратные вызовы жизненного цикла в файл сопоставления объекта

    <lifecycle-callbacks>
       <lifecycle-callback type="postLoad" method="setRequiredService"/>
   </lifecycle-callbacks>
  

И затем в вызываемом методе вводите зависимость, применяя внедрение установщика зависимостей.

 public function setRequiredService()
{
   $this->requiredService = new requiredServiceClass();
}
  

Мои вопросы:
Это лучший способ решить проблему внедрения зависимостей во время гидратации в Doctrine?
И нормально ли передавать параметр DI с значением по умолчанию NULL?

Спасибо, Абхинит Рави

Ответ №1:

Хранит ли он какую-либо информацию в базе данных для этого «Сервиса», я не уверен, что это такое.

Если это так, вы могли бы определить его как пользовательский тип данных. Вот ссылка на doctrine docs по этой теме.

http://doctrine-orm.readthedocs.org/en/latest/cookbook/custom-mapping-types.html

http://docs.doctrine-project.org/en/2.0.x/cookbook/mysql-enums.html

Я не вижу никаких проблем, если это просто какой-то класс, который вам нужен, не уверен, не зная, что такое service, и было бы лучше реструктурировать код, чтобы он не нуждался в этом, но я не могу сказать, не зная, что это делает.

Я бы сказал, что способ, которым вы это делаете, в порядке, не уверен, запускается ли onLoad только при извлечении из базы данных или нет, но вы можете захотеть проверить, есть ли там null вместо этого.

Я бы, возможно, написал класс таким образом

 Class A implements Ia
    {

        protected $requiredService; //null by default

        public function __constructor( requiredServiceClass $requiredService = NULL )
        {
            $this->setRequiredService($requiredService);
        }

       public function postLoad(){
          $this->setRequiredService();
       }

        public function setRequiredService(requiredServiceClass $requiredService = NULL)
        {
            if(NULL === $this->requiredService){
                //check if class has service - assuming you never want to set it again once it is set.
                if(NULL === $requiredService){
                    $this->requiredService = new requiredServiceClass();
                }else{
                    $this->requiredService = $requiredService;
                }
            }
        }

    }


 <lifecycle-callbacks>
       <lifecycle-callback type="postLoad" method="postLoad"/>
   </lifecycle-callbacks>
  

Мои причины таковы.

  1. Таким образом, все ваши проверки выполняются прямо перед внедрением сервиса в класс.
  2. Из кода ясно, что используется обратный вызов жизненного цикла.
  3. Лучше следует за разделением проблем, т. Е. конструктор не должен заниматься проверкой статуса requiredService, он просто передает его дальше. То же самое с обратным вызовом.
  4. Если вам потребуется перезагрузить службу ( удалить внешнее if в setRequiredService ), вам не нужно будет изменять логику в конструкторе и т.д..