【zendframework】控制器与视图

一个自动渲染带布局的hello word为例。
在配置文件中设置布局文件的存放路径resources.layout.layoutPath = APPLICATION_PATH "/layouts/",引导程序会注册布局组件Zend_Layout。
[plain]  view plain copy
  1. //控制器  
  2. <?php  
  3. class IndexController extends Zend_Controller_Action  
  4. {  
  5.   
  6.     public function init()  
  7.     {  
  8.     }  
  9.     public function indexAction()  
  10.     {  
  11.     }  
  12. }  
  13.   
  14. //视图  
  15. <h2>hello word</h2>  
  16.   
  17. //布局  
  18. <?php  
  19. echo $this->doctype();  
  20. ?>  
  21. <html>  
  22. <head>  
  23. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />  
  24. <?php echo $this->headTitle();  
  25. echo $this->headLink()->appendStylesheet("css/layout.css");  
  26. ?>  
  27. </head>  
  28. <body>  
  29. <div id="pageWrapper">  
  30. <div id="header">  
  31. <h1>This is layout</h1>  
  32. </div>  
  33. <div id="main">  
  34. <?php echo $this->layout()->content?>&nbsp;  
  35. </div>  
  36. <div id="footer">  
  37. <p><em>Powered by the qiangge</em></p>  
  38. </div>  
  39. </div>  
  40. </body>  
  41. </html>  
显示结果为



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


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

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

[php]  view plain copy
  1. public function dispatch(Zend_Controller_Request_Abstract $request = null, Zend_Controller_Response_Abstract $response = null)  
  2. {  
  3.     if (!$this->getParam('noErrorHandler') && !$this->_plugins->hasPlugin('Zend_Controller_Plugin_ErrorHandler')) {  
  4.         // Register with stack index of 100  
  5.         require_once 'Zend/Controller/Plugin/ErrorHandler.php';  
  6.         $this->_plugins->registerPlugin(new Zend_Controller_Plugin_ErrorHandler(), 100);  
  7.     }  
  8.   
  9.   
  10.     if (!$this->getParam('noViewRenderer') && !Zend_Controller_Action_HelperBroker::hasHelper('viewRenderer')) {  
  11.         require_once 'Zend/Controller/Action/Helper/ViewRenderer.php';  
  12.         Zend_Controller_Action_HelperBroker::getStack()->offsetSet(-80, new Zend_Controller_Action_Helper_ViewRenderer());  
  13.     }  
  14.   
  15.   
  16.     /** 
  17.         * Instantiate default request object (HTTP version) if none provided 
  18.         */  
  19.     if (null !== $request) {  
  20.         $this->setRequest($request);  
  21.     } elseif ((null === $request) && (null === ($request = $this->getRequest()))) {  
  22.         require_once 'Zend/Controller/Request/Http.php';  
  23.         $request = new Zend_Controller_Request_Http();  
  24.         $this->setRequest($request);  
  25.     }  
  26.   
  27.   
  28.     /** 
  29.         * Set base URL of request object, if available 
  30.         */  
  31.     if (is_callable(array($this->_request, 'setBaseUrl'))) {  
  32.         if (null !== $this->_baseUrl) {  
  33.             $this->_request->setBaseUrl($this->_baseUrl);  
  34.         }  
  35.     }  
  36.   
  37.   
  38.     /** 
  39.         * Instantiate default response object (HTTP version) if none provided 
  40.         */  
  41.     if (null !== $response) {  
  42.         $this->setResponse($response);  
  43.     } elseif ((null === $this->_response) && (null === ($this->_response = $this->getResponse()))) {  
  44.         require_once 'Zend/Controller/Response/Http.php';  
  45.         $response = new Zend_Controller_Response_Http();  
  46.         $this->setResponse($response);  
  47.     }  
  48.   
  49.   
  50.     /** 
  51.         * Register request and response objects with plugin broker 
  52.         */  
  53.     $this->_plugins  
  54.             ->setRequest($this->_request)  
  55.             ->setResponse($this->_response);  
  56.   
  57.   
  58.     /** 
  59.         * Initialize router 
  60.         */  
  61.     $router = $this->getRouter();  
  62.     $router->setParams($this->getParams());  
  63.   
  64.   
  65.     /** 
  66.         * Initialize dispatcher 
  67.         */  
  68.     $dispatcher = $this->getDispatcher();  
  69.     $dispatcher->setParams($this->getParams())  
  70.                 ->setResponse($this->_response);  
  71.   
  72.   
  73.     // Begin dispatch  
  74.     try {  
  75.         /** 
  76.             * Route request to controller/action, if a router is provided 
  77.             */  
  78.   
  79.   
  80.         /** 
  81.         * Notify plugins of router startup 
  82.         */  
  83.         $this->_plugins->routeStartup($this->_request);  
  84.   
  85.   
  86.         try {  
  87.             $router->route($this->_request);  
  88.         }  catch (Exception $e) {  
  89.             if ($this->throwExceptions()) {  
  90.                 throw $e;  
  91.             }  
  92.   
  93.   
  94.             $this->_response->setException($e);  
  95.         }  
  96.   
  97.   
  98.         /** 
  99.         * Notify plugins of router completion 
  100.         */  
  101.         $this->_plugins->routeShutdown($this->_request);  
  102.   
  103.   
  104.         /** 
  105.             * Notify plugins of dispatch loop startup 
  106.             */  
  107.         $this->_plugins->dispatchLoopStartup($this->_request);  
  108.   
  109.   
  110.         /** 
  111.             *  Attempt to dispatch the controller/action. If the $this->_request 
  112.             *  indicates that it needs to be dispatched, move to the next 
  113.             *  action in the request. 
  114.             */  
  115.         do {  
  116.             $this->_request->setDispatched(true);  
  117.   
  118.   
  119.             /** 
  120.                 * Notify plugins of dispatch startup 
  121.                 */  
  122.             $this->_plugins->preDispatch($this->_request);  
  123.   
  124.   
  125.             /** 
  126.                 * Skip requested action if preDispatch() has reset it 
  127.                 */  
  128.             if (!$this->_request->isDispatched()) {  
  129.                 continue;  
  130.             }  
  131.   
  132.   
  133.             /** 
  134.                 * Dispatch request 
  135.                 */  
  136.             try {  
  137.                 $dispatcher->dispatch($this->_request, $this->_response);  
  138.             } catch (Exception $e) {  
  139.                 if ($this->throwExceptions()) {  
  140.                     throw $e;  
  141.                 }  
  142.                 $this->_response->setException($e);  
  143.             }  
  144.   
  145.   
  146.             /** 
  147.                 * Notify plugins of dispatch completion 
  148.                 */  
  149.             $this->_plugins->postDispatch($this->_request);  
  150.         } while (!$this->_request->isDispatched());  
  151.     } catch (Exception $e) {  
  152.         if ($this->throwExceptions()) {  
  153.             throw $e;  
  154.         }  
  155.   
  156.   
  157.         $this->_response->setException($e);  
  158.     }  
  159.   
  160.   
  161.     /** 
  162.         * Notify plugins of dispatch loop completion 
  163.         */  
  164.     try {  
  165.         $this->_plugins->dispatchLoopShutdown();  
  166.     } catch (Exception $e) {  
  167.         if ($this->throwExceptions()) {  
  168.             throw $e;  
  169.         }  
  170.   
  171.   
  172.         $this->_response->setException($e);  
  173.     }  
  174.   
  175.   
  176.     if ($this->returnResponse()) {  
  177.         return $this->_response;  
  178.     }  
  179.   
  180.   
  181.     $this->_response->sendResponse();  
  182. }  
3、前端控制获取分发器进行分发,分发器定位到控制执行相应的动作,动作控制器Zend_Controller_Action::dispatch($action)。Zend_Controller_Action是控制器的基类,它控制请求返回对象,视图助手,视图渲染等。在每个动作执行前后会预留助手和该动作的钩子方法。
[php]  view plain copy
  1. public function dispatch($action)  
  2. {  
  3.     // Notify helpers of action preDispatch state  
  4.   
  5.     $this->_helper->notifyPreDispatch();  
  6.   
  7.     $this->preDispatch();  
  8.     if ($this->getRequest()->isDispatched()) {  
  9.         if (null === $this->_classMethods) {  
  10.             $this->_classMethods = get_class_methods($this);  
  11.         }  
  12.   
  13.         // preDispatch() didn't change the action, so we can continue  
  14.         if ($this->getInvokeArg('useCaseSensitiveActions') || in_array($action$this->_classMethods)) {  
  15.             if ($this->getInvokeArg('useCaseSensitiveActions')) {  
  16.                 trigger_error('Using case sensitive actions without word separators is deprecated; please do not rely on this "feature"');  
  17.             }  
  18.             $this->$action();  
  19.         } else {  
  20.             $this->__call($actionarray());  
  21.         }  
  22.         $this->postDispatch();  
  23.     }  
  24.   
  25.     // whats actually important here is that this action controller is  
  26.     // shutting down, regardless of dispatching; notify the helpers of this  
  27.     // state  
  28.     $this->_helper->notifyPostDispatch();  
  29. }  

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

[php]  view plain copy
  1. public function postDispatch()  
  2. {  
  3.     if ($this->_shouldRender()) {  
  4.         $this->render();  
  5.     }  
  6. }  
  7. ...  
  8. public function renderScript($script$name = null)  
  9. {  
  10.     if (null === $name) {  
  11.         $name = $this->getResponseSegment();  
  12.   
  13.   
  14.   
  15.   
  16.     }  
  17.   
  18.     $this->getResponse()->appendBody(  
  19.         $this->view->render($script),  
  20.         $name  
  21.     );  
  22.   
  23.   
  24.     $this->setNoRender();  
  25. }  
5、再回到Zend_Controller_Front::dispatch()中, $this->_plugins->postDispatch($this->_request)调用前端控制器插件栈中的Zend_Layout_Controller_Plugin_Layout插件,通过布局助手把第四步渲染好的视图内容以默认为content变量传到layout视图中。
[php]  view plain copy
  1. /** 
  2.     * postDispatch() plugin hook -- render layout 
  3.     * 
  4.     * @param  Zend_Controller_Request_Abstract $request 
  5.     * @return void 
  6.     */  
  7. public function postDispatch(Zend_Controller_Request_Abstract $request)  
  8. {  
  9.     $layout = $this->getLayout();  
  10.     $helper = $this->getLayoutActionHelper();  
  11.   
  12.     // Return early if forward detected  
  13.     if (!$request->isDispatched()  
  14.         || $this->getResponse()->isRedirect()  
  15.         || ($layout->getMvcSuccessfulActionOnly()  
  16.             && (!empty($helper) && !$helper->isActionControllerSuccessful())))  
  17.     {  
  18.         return;  
  19.     }  
  20.     // Return early if layout has been disabled  
  21.     if (!$layout->isEnabled()) {  
  22.         return;  
  23.     }  
  24.     $response   = $this->getResponse();  
  25.     $content    = $response->getBody(true);  
  26.   
  27.     $contentKey = $layout->getContentKey();  
  28.     if (isset($content['default'])) {  
  29.         $content[$contentKey] = $content['default'];  
  30.     }  
  31.     if ('default' != $contentKey) {  
  32.         unset($content['default']);  
  33.     }  
  34.     $layout->assign($content);  
  35.     $fullContent = null;  
  36.     $obStartLevel = ob_get_level();  
  37.   
  38.     try {  
  39.         $fullContent = $layout->render();  
  40.   
  41.         $response->setBody($fullContent);  
  42.   
  43.     } catch (Exception $e) {  
  44.         while (ob_get_level() > $obStartLevel) {  
  45.             $fullContent .= ob_get_clean();  
  46.         }  
  47.         $request->setParam('layoutFullContent'$fullContent);  
  48.         $request->setParam('layoutContent'$layout->content);  
  49.         $response->setBody(null);  
  50.         throw $e;  
  51.     }  
  52. }  
6、Zend_Controller_Front::dispatch()最后面,如果不是设置返回内容,响应对象直接输出内容。

你可能感兴趣的:(【zendframework】控制器与视图)