一个自动渲染带布局的hello word为例。
在配置文件中设置布局文件的存放路径resources.layout.layoutPath = APPLICATION_PATH "/layouts/",引导程序会注册布局组件Zend_Layout。
显示结果为
2、在前端控制执行dispatch()的时候,在默认情况会通过动作助手经理人注册自动渲染插件 Zend_Controller_Action_Helper_ViewRenderer,
3、前端控制获取分发器进行分发,分发器定位到控制执行相应的动作,动作控制器Zend_Controller_Action::dispatch($action)。Zend_Controller_Action是控制器的基类,它控制请求返回对象,视图助手,视图渲染等。在每个动作执行前后会预留助手和该动作的钩子方法。
5、再回到Zend_Controller_Front::dispatch()中, $this->_plugins->postDispatch($this->_request)调用前端控制器插件栈中的Zend_Layout_Controller_Plugin_Layout插件,通过布局助手把第四步渲染好的视图内容以默认为content变量传到layout视图中。
6、Zend_Controller_Front::dispatch()最后面,如果不是设置返回内容,响应对象直接输出内容。
在配置文件中设置布局文件的存放路径resources.layout.layoutPath = APPLICATION_PATH "/layouts/",引导程序会注册布局组件Zend_Layout。
- //控制器
- <?php
- class IndexController extends Zend_Controller_Action
- {
- public function init()
- {
- }
- public function indexAction()
- {
- }
- }
- //视图
- <h2>hello word</h2>
- //布局
- <?php
- echo $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?>
- </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();
- }
- 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();
- }
- 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();
- }
- /**
- * 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;
- }
- }