douxiezha9319 2014-07-03 19:23
浏览 36
已采纳

使用Doctrine Lifecycle回调进行依赖注入,同时进行干燥

I'm developing php application with Doctrine (no symfony) and hence no DI container. I'm using dependency Injection in one of my entities, which needs a service.

    Class A implements Ia
    {

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

    }

Every thing works fine but while hydrating Doctrine doesn't call the __constructor as a result the dependency is not injected. What's the best way to solve this?

Currently I use Doctrine lifecycle events to callback a method to set the dependency. So first I add the lifecycle-callbacks in the mapping file of the entity

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

And then in the called method inject the dependency applying the setter dependency Injection.

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

My Questions: Is this the best way to solve dependency Injection while hyderation in Doctrine? And is it fine to pass DI param with default as NULL?

Thanks, Abhinit Ravi

  • 写回答

1条回答 默认 最新

  • douying3251 2014-07-03 20:24
    关注

    Does it store any information in the database for this "Service" I am not sure what that is.

    If so you could define it as a custom data type. Here is a link to the doctrine docs on that topic.

    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

    I don't see any issues if it is just some class you need, not sure without know what service is and it could be better to restructure the code so it doesn't need this, but I cant tell without know what that does.

    Id say the way you are doing it is fine, not sure if onLoad is fired only when pulling from the database or not but you might want to check if is null there instead.

    I would possible write the class in this way

    Class A implements Ia
        {
    
            protected $requiredService; //null by default
    
            public function __constructor( equiredServiceClass $requiredService = NULL )
            {
                $this->setRequiredService($requiredService);
            }
    
           public function postLoad(){
              $this->setRequiredService();
           }
    
            public function setRequiredService(equiredServiceClass $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 equiredServiceClass();
                    }else{
                        $this->requiredService = $requiredService;
                    }
                }
            }
    
        }
    
    
     <lifecycle-callbacks>
           <lifecycle-callback type="postLoad" method="postLoad"/>
       </lifecycle-callbacks>
    

    My reasons are.

    1. This way all your check are right before injecting the service into the class.
    2. Its clear looking at the code that a lifecycle callback is used.
    3. Follows better with separation of concerns, ie. the constructor shouldn't be concerned with checking the status of requiredService, it just passes it on. Same with the callback.
    4. Should you need to reset the service ( remove the outer if in setRequiredService ) you wont need to change the logic in the constructor etc..
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?