zendFramework分析3:控制器与视图

来源:互联网 发布:百词斩扇贝知米哪个好 编辑:程序博客网 时间:2024/05/16 15:43
一个自动渲染带布局的hello word为例。
在配置文件中设置布局文件的存放路径resources.layout.layoutPath = APPLICATION_PATH "/layouts/",引导程序会注册布局组件Zend_Layout。
//控制器<?phpclass IndexController extends Zend_Controller_Action{    public function init()    {    }    public function indexAction()    {    }}//视图<h2>hello word</h2>//布局<?phpecho $this->doctype();?><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><?php echo $this->headTitle();echo $this->headLink()->appendStylesheet("css/layout.css");?></head><body><div id="pageWrapper"><div id="header"><h1>This is layout</h1></div><div id="main"><?php echo $this->layout()->content?>&nbsp;</div><div id="footer"><p><em>Powered by the qiangge</em></p></div></div></body></html>
显示结果为



下面分析一下是如何得到这个页面的:


1、在实例化Zend_Layout的时候,通过其构造方法在注册了一个Zend_Layout_Controller_Plugin_Layout插件和Zend_Layout_Controller_Action_Helper_Layout动作助手。

protected function _initMvc(){    $this->_initPlugin();    $this->_initHelper();}
2、在前端控制执行dispatch()的时候,在默认情况会通过动作助手经理人注册自动渲染插件 Zend_Controller_Action_Helper_ViewRenderer,

public function dispatch(Zend_Controller_Request_Abstract $request = null, Zend_Controller_Response_Abstract $response = null){    if (!$this->getParam('noErrorHandler') && !$this->_plugins->hasPlugin('Zend_Controller_Plugin_ErrorHandler')) {        // Register with stack index of 100        require_once 'Zend/Controller/Plugin/ErrorHandler.php';        $this->_plugins->registerPlugin(new Zend_Controller_Plugin_ErrorHandler(), 100);    }    if (!$this->getParam('noViewRenderer') && !Zend_Controller_Action_HelperBroker::hasHelper('viewRenderer')) {        require_once 'Zend/Controller/Action/Helper/ViewRenderer.php';        Zend_Controller_Action_HelperBroker::getStack()->offsetSet(-80, new Zend_Controller_Action_Helper_ViewRenderer());    }    /**        * Instantiate default request object (HTTP version) if none provided        */    if (null !== $request) {        $this->setRequest($request);    } elseif ((null === $request) && (null === ($request = $this->getRequest()))) {        require_once 'Zend/Controller/Request/Http.php';        $request = new Zend_Controller_Request_Http();        $this->setRequest($request);    }    /**        * Set base URL of request object, if available        */    if (is_callable(array($this->_request, 'setBaseUrl'))) {        if (null !== $this->_baseUrl) {            $this->_request->setBaseUrl($this->_baseUrl);        }    }    /**        * Instantiate default response object (HTTP version) if none provided        */    if (null !== $response) {        $this->setResponse($response);    } elseif ((null === $this->_response) && (null === ($this->_response = $this->getResponse()))) {        require_once 'Zend/Controller/Response/Http.php';        $response = new Zend_Controller_Response_Http();        $this->setResponse($response);    }    /**        * Register request and response objects with plugin broker        */    $this->_plugins            ->setRequest($this->_request)            ->setResponse($this->_response);    /**        * Initialize router        */    $router = $this->getRouter();    $router->setParams($this->getParams());    /**        * Initialize dispatcher        */    $dispatcher = $this->getDispatcher();    $dispatcher->setParams($this->getParams())                ->setResponse($this->_response);    // Begin dispatch    try {        /**            * Route request to controller/action, if a router is provided            */        /**        * Notify plugins of router startup        */        $this->_plugins->routeStartup($this->_request);        try {            $router->route($this->_request);        }  catch (Exception $e) {            if ($this->throwExceptions()) {                throw $e;            }            $this->_response->setException($e);        }        /**        * Notify plugins of router completion        */        $this->_plugins->routeShutdown($this->_request);        /**            * Notify plugins of dispatch loop startup            */        $this->_plugins->dispatchLoopStartup($this->_request);        /**            *  Attempt to dispatch the controller/action. If the $this->_request            *  indicates that it needs to be dispatched, move to the next            *  action in the request.            */        do {            $this->_request->setDispatched(true);            /**                * Notify plugins of dispatch startup                */            $this->_plugins->preDispatch($this->_request);            /**                * Skip requested action if preDispatch() has reset it                */            if (!$this->_request->isDispatched()) {                continue;            }            /**                * Dispatch request                */            try {                $dispatcher->dispatch($this->_request, $this->_response);            } catch (Exception $e) {                if ($this->throwExceptions()) {                    throw $e;                }                $this->_response->setException($e);            }            /**                * Notify plugins of dispatch completion                */            $this->_plugins->postDispatch($this->_request);        } while (!$this->_request->isDispatched());    } catch (Exception $e) {        if ($this->throwExceptions()) {            throw $e;        }        $this->_response->setException($e);    }    /**        * Notify plugins of dispatch loop completion        */    try {        $this->_plugins->dispatchLoopShutdown();    } catch (Exception $e) {        if ($this->throwExceptions()) {            throw $e;        }        $this->_response->setException($e);    }    if ($this->returnResponse()) {        return $this->_response;    }    $this->_response->sendResponse();}
3、前端控制获取分发器进行分发,分发器定位到控制执行相应的动作,动作控制器Zend_Controller_Action::dispatch($action)。Zend_Controller_Action是控制器的基类,它控制请求返回对象,视图助手,视图渲染等。在每个动作执行前后会预留助手和该动作的钩子方法。
public function dispatch($action){    // Notify helpers of action preDispatch state    $this->_helper->notifyPreDispatch();    $this->preDispatch();    if ($this->getRequest()->isDispatched()) {        if (null === $this->_classMethods) {            $this->_classMethods = get_class_methods($this);        }        // preDispatch() didn't change the action, so we can continue        if ($this->getInvokeArg('useCaseSensitiveActions') || in_array($action, $this->_classMethods)) {            if ($this->getInvokeArg('useCaseSensitiveActions')) {                trigger_error('Using case sensitive actions without word separators is deprecated; please do not rely on this "feature"');            }            $this->$action();        } else {            $this->__call($action, array());        }        $this->postDispatch();    }    // whats actually important here is that this action controller is    // shutting down, regardless of dispatching; notify the helpers of this    // state    $this->_helper->notifyPostDispatch();}

4、 执行完动作后,$this->_helper->notifyPostDispatch();调用视图经理人栈中的视图渲染助手进行视图渲染,将得到的结果存入响应对象中,默认放在属性_body['default']中。

public function postDispatch(){    if ($this->_shouldRender()) {        $this->render();    }}...public function renderScript($script, $name = null){    if (null === $name) {        $name = $this->getResponseSegment();    }    $this->getResponse()->appendBody(        $this->view->render($script),        $name    );    $this->setNoRender();}
5、再回到Zend_Controller_Front::dispatch()中, $this->_plugins->postDispatch($this->_request)调用前端控制器插件栈中的Zend_Layout_Controller_Plugin_Layout插件,通过布局助手把第四步渲染好的视图内容以默认为content变量传到layout视图中。
/**    * postDispatch() plugin hook -- render layout    *    * @param  Zend_Controller_Request_Abstract $request    * @return void    */public function postDispatch(Zend_Controller_Request_Abstract $request){    $layout = $this->getLayout();    $helper = $this->getLayoutActionHelper();    // Return early if forward detected    if (!$request->isDispatched()        || $this->getResponse()->isRedirect()        || ($layout->getMvcSuccessfulActionOnly()            && (!empty($helper) && !$helper->isActionControllerSuccessful())))    {        return;    }    // Return early if layout has been disabled    if (!$layout->isEnabled()) {        return;    }    $response   = $this->getResponse();    $content    = $response->getBody(true);    $contentKey = $layout->getContentKey();    if (isset($content['default'])) {        $content[$contentKey] = $content['default'];    }    if ('default' != $contentKey) {        unset($content['default']);    }    $layout->assign($content);    $fullContent = null;    $obStartLevel = ob_get_level();    try {        $fullContent = $layout->render();        $response->setBody($fullContent);    } catch (Exception $e) {        while (ob_get_level() > $obStartLevel) {            $fullContent .= ob_get_clean();        }        $request->setParam('layoutFullContent', $fullContent);        $request->setParam('layoutContent', $layout->content);        $response->setBody(null);        throw $e;    }}
6、Zend_Controller_Front::dispatch()最后面,如果不是设置返回内容,响应对象直接输出内容。



原创粉丝点击