How to use dependency injection in Zend Framework?

前端 未结 5 760
攒了一身酷
攒了一身酷 2021-02-02 14:52

Currently I am trying to learn the Zend Framework and therefore I bought the book \"Zend Framework in Action\".

In chapter 3, a basic model and controller is introduced

5条回答
  •  一生所求
    2021-02-02 15:17

    Logic to models

    First of all, it's worth to mention, that controllers should need only functional tests, though all the logic belongs to models.

    My implementation

    Here is an excerpt from my Action Controller implementation, which solves the following problems:

    • allows inject any dependency to actions
    • validates the action parameters, e.g. you may not pass array in $_GET when integer is expected

    My full code allows also to generate canonical URL (for SEO or unique page hash for stats) based or required or handled action params. For this, I use this abstract Action Controller and custom Request object, but this is not the case we discuss here.

    Obviously, I use Reflections to automatically determine action parameters and dependency objects.

    This is a huge advantage and simplifies the code, but also has an impact in performance (minimal and not important in case of my app and server), but you may implement some caching to speed it up. Calculate the benefits and the drawbacks, then decide.

    DocBlock annotations are becoming a pretty well known industry standard, and parsing it for evaluation purposes becomes more popular (e.g. Doctrine 2). I used this technique for many apps and it worked nicely.

    Writing this class I was inspired by Actions, now with params! and Jani Hartikainen's blog post.

    So, here is the code:

    getInvokeArg('useCaseSensitiveActions')) {
                trigger_error(
                        'Using case sensitive actions without word separators' .
                        'is deprecated; please do not rely on this "feature"'
                );
    
                return true;
            }
    
            if (method_exists($this, $action)) {
    
                return true;
            }
    
            return false;
        }
    
        /**
         *
         * @param string $action
         * @return array of Zend_Reflection_Parameter objects
         */
        protected function _actionReflectionParams($action)
        {
            $reflMethod = new Zend_Reflection_Method($this, $action);
            $parameters = $reflMethod->getParameters();
    
            return $parameters;
        }
    
        /**
         *
         * @param Zend_Reflection_Parameter $parameter
         * @return string
         * @throws Your_Controller_Action_Exception when required @param is missing
         */
        protected function _getParameterType(Zend_Reflection_Parameter $parameter)
        {
            // get parameter type
            $reflClass = $parameter->getClass();
    
            if ($reflClass instanceof Zend_Reflection_Class) {
                $type = $reflClass->getName();
            } else if ($parameter->isArray()) {
                $type = 'array';
            } else {
                $type = $parameter->getType();
            }
    
            if (null === $type) {
                throw new Your_Controller_Action_Exception(
                        sprintf(
                                "Required @param DocBlock not found for '%s'", $parameter->getName()
                        )
                );
            }
    
            return $type;
        }
    
        /**
         *
         * @param Zend_Reflection_Parameter $parameter 
         * @return mixed
         * @throws Your_Controller_Action_Exception when required argument is missing
         */
        protected function _getParameterValue(Zend_Reflection_Parameter $parameter)
        {
            $name = $parameter->getName();
            $requestValue = $this->getRequest()->getParam($name);
    
            if (null !== $requestValue) {
                $value = $requestValue;
            } else if ($parameter->isDefaultValueAvailable()) {
                $value = $parameter->getDefaultValue();
            } else {
                if (!$parameter->isOptional()) {
                    throw new Your_Controller_Action_Exception(
                            sprintf("Missing required value for argument: '%s'", $name));
                }
    
                $value = null;
            }
    
            return $value;
        }
    
        /**
         *
         * @param mixed $value 
         */
        protected function _fixValueType($value, $type)
        {
            if (in_array($type, $this->_basicTypes)) {
                settype($value, $type);
            }
    
            return $value;
        }
    
        /**
         * Dispatch the requested action
         *
         * @param   string $action Method name of action
         * @return  void
         */
        public function dispatch($action)
        {
            $request = $this->getRequest();
    
            // Notify helpers of action preDispatch state
            $this->_helper->notifyPreDispatch();
    
            $this->preDispatch();
            if ($request->isDispatched()) {
                // preDispatch() didn't change the action, so we can continue
                if ($this->_hasAction($action)) {
    
                    $requestArgs = array();
                    $dependencyObjects = array();
                    $requiredArgs = array();
    
                    foreach ($this->_actionReflectionParams($action) as $parameter) {
                        $type = $this->_getParameterType($parameter);
                        $name = $parameter->getName();
                        $value = $this->_getParameterValue($parameter);
    
                        if (!in_array($type, $this->_basicTypes)) {
                            if (!is_object($value)) {
                                $value = new $type($value);
                            }
                            $dependencyObjects[$name] = $value;
                        } else {
                            $value = $this->_fixValueType($value, $type);
                            $requestArgs[$name] = $value;
                        }
    
                        if (!$parameter->isOptional()) {
                            $requiredArgs[$name] = $value;
                        }
                    }
    
                    // handle canonical URLs here
    
                    $allArgs = array_merge($requestArgs, $dependencyObjects);
                    // dispatch the action with arguments
                    call_user_func_array(array($this, $action), $allArgs);
                } else {
                    $this->__call($action, array());
                }
                $this->postDispatch();
            }
    
            $this->_helper->notifyPostDispatch();
        }
    
    }
    

    To use this, just:

    Your_FineController extends Your_Controller_Action {}
    

    and provide annotations to actions, as usual (at least you already should ;).

    e.g.

    /**
     * @param int $id Mandatory parameter
     * @param string $sorting Not required parameter
     * @param Your_Model_Name $model Optional dependency object 
     */
    public function indexAction($id, $sorting = null, Your_Model_Name $model = null) 
    {
        // model has been already automatically instantiated if null
        $entry = $model->getOneById($id, $sorting);
    }
    

    (DocBlock is required, however I use Netbeans IDE, so the DocBlock is automatically generated based on action arguments)

提交回复
热议问题