Dispatching Controllers ======================= :doc:`Phalcon\\Mvc\\Dispatcher <../api/Phalcon_Mvc_Dispatcher>` 组件负责在MVC应用程åºä¸è´Ÿè´£å®žä¾‹åŒ–æŽ§åˆ¶å™¨ä»¥åŠæ‰§è¡Œæ‰€éœ€æ“作的。了解它的具体è¿ä½œæ–¹æ³•能很好的帮助我们了解整个框架æä¾›çš„æœåŠ¡ã€‚ The Dispatch Loop ----------------- 很多é‡è¦çš„过程å‘生在MVCå·¥ä½œæµæœ¬èº«ï¼Œå°¤å…¶æ˜¯åœ¨æŽ§åˆ¶å™¨éƒ¨åˆ†ã€‚这些工作å‘生在控制调度度期间,控制器文件的读å–ï¼ŒåŠ è½½ï¼Œåˆå§‹åŒ–ï¼Œä»¥åŠæ“作的执行。如果一个actionä¸çš„æµç¨‹è·³è½¬åˆ°å¦ä¸€ä¸ªæŽ§åˆ¶å™¨çš„controller/actionä¸Šï¼ŒæŽ§åˆ¶è°ƒåº¦å™¨å†æ¬¡å¯åŠ¨ï¼Œä¸ºäº†æ›´å¥½çš„è¯´æ˜Žè¿™ä¸€ç‚¹ï¼Œä¸‹é¢çš„例å将展示 :doc:`Phalcon\\Mvc\\Dispatcher <../api/Phalcon_Mvc_Dispatcher>` 内部执行的过程: .. code-block:: php <?php //Dispatch loop while (!$finished) { $finished = true; $controllerClass = $controllerName."Controller"; //Instantiating the controller class via autoloaders $controller = new $controllerClass(); // Execute the action call_user_func_array(array($controller, $actionName . "Action"), $params); // Finished should be reloaded to check if the flow was forwarded to another controller // $finished = false; } 上é¢çš„ä»£ç æ²¡æœ‰æ·»åŠ éªŒè¯å™¨ï¼Œè¿‡æ»¤å™¨ä»¥åŠé¢å¤–的检查,但它很好的展示了分å‘器在æ£å¸¸çš„调度程åºä¸çš„æ“ä½œæµç¨‹ã€‚ 分å‘器事件(Dispatch Loop Events) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :doc:`Phalcon\\Mvc\\Dispatcher <../api/Phalcon_Mvc_Dispatcher>` 也能够å‘é€äº‹ä»¶åˆ° :doc:`EventsManager <events>` 。事件被触å‘的类型å称为 "dispatch"。其ä¸çš„一些事件,返回布尔值false时,å¯ä»¥åœæ¢äº‹ä»¶çš„è¿ä½œã€‚ä¸»è¦æ”¯æŒä»¥ä¸‹äº‹ä»¶ï¼š +----------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+ | Event Name | Triggered | Can stop operation? | +======================+=============================================================================================================================================================================================================+=====================+ | beforeDispatchLoop | Triggered before enter in the dispatch loop. At this point the dispatcher don't know if the controller or the actions to be executed exist. The Dispatcher only knows the information passed by the Router. | Yes | +----------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+ | beforeDispatch | Triggered after enter in the dispatch loop. At this point the dispatcher don't know if the controller or the actions to be executed exist. The Dispatcher only knows the information passed by the Router. | Yes | +----------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+ | beforeExecuteRoute | Triggered before execute the controller/action method. At this point the dispatcher has been initialized the controller and know if the action exist. | Yes | +----------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+ | afterExecuteRoute | Triggered after execute the controller/action method. As operation cannot be stopped, only use this event to make clean up after execute the action | No | +----------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+ | beforeNotFoundAction | Triggered when the action was not found in the controller | Yes | +----------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+ | beforeException | Triggered before the dispatcher throws any exception | Yes | +----------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+ | afterDispatch | Triggered after execute the controller/action method. As operation cannot be stopped, only use this event to make clean up after execute the action | Yes | +----------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+ | afterDispatchLoop | Triggered after exit the dispatch loop | No | +----------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+ :doc:`INVO <tutorial-invo>` æ•™ç¨‹ä¸æ¼”示了如何使用分å‘器é…åˆ :doc:`Acl <acl>` 实现安全认è¯ã€‚ 下é¢çš„示例将演示如何在分å‘器上注册监å¬å™¨äº‹ä»¶ï¼š .. code-block:: php <?php $di->set('dispatcher', function(){ //Create an event manager $eventsManager = new Phalcon\Events\Manager(); //Attach a listener for type "dispatch" $eventsManager->attach("dispatch", function($event, $dispatcher) { //... }); $dispatcher = new \Phalcon\Mvc\Dispatcher(); //Bind the eventsManager to the view component $dispatcher->setEventsManager($eventsManager); return $dispatcher; }); Instantiated controllers act automatically as listeners for dispatch events, so you can implement methods as callbacks: .. code-block:: php <?php class PostsController extends \Phalcon\Mvc\Controller { public function beforeExecuteRoute($dispatcher) { // Executed before every found action } public function afterExecuteRoute($dispatcher) { // Executed after every found action } } Forwarding to other actions --------------------------- 分å‘器å…许我们从一个controller/action跳转到å¦ä¸€ä¸ªcontroller/action。这是éžå¸¸æœ‰ç”¨çš„,如果我们需è¦åœ¨ä»£ç ä¸è¿›è¡Œç”¨æˆ·æ£€æŸ¥ç‰äº‹é¡¹ï¼Œå¯ä»¥å°†ç”¨æˆ·é‡å®šå‘到其他页é¢ã€‚ .. code-block:: php <?php class PostsController extends \Phalcon\Mvc\Controller { public function indexAction() { } public function saveAction($year, $postTitle) { // .. store some product and forward the user // Forward flow to the index action $this->dispatcher->forward(array( "controller" => "post", "action" => "index" )); } } 请记ä½ï¼Œ"forward"å’ŒHTTPé‡å®šå‘ä¸ä¸€æ ·ï¼Œè™½ç„¶ä»–们显示了相åŒçš„结果。"forward"ä¸åˆ·æ–°å½“å‰é¡µé¢ï¼Œæ‰€æœ‰çš„é‡å®šå‘都å‘生在一个å•一的请求ä¸ï¼Œè€ŒHTTPé‡å®šå‘则需è¦å®Œæˆä¸¤ä¸ªè¯·æ±‚。 更多关于forward的例å: .. code-block:: php <?php // Forward flow to another action in the current controller $this->dispatcher->forward(array( "action" => "search" )); // Forward flow to another action in the current controller // passing parameters $this->dispatcher->forward(array( "action" => "search", "params" => array(1, 2, 3) )); // Forward flow to another action in the current controller // passing parameters $this->dispatcher->forward(array( "action" => "search", "params" => array(1, 2, 3) )); 跳转动作按å—ä»¥ä¸‹ä¸€äº›å‚æ•°ï¼š +----------------+--------------------------------------------------------+ | Parameter | Triggered | +================+========================================================+ | controller | A valid controller name to forward to. | +----------------+--------------------------------------------------------+ | action | A valid action name to forward to. | +----------------+--------------------------------------------------------+ | params | An array of parameters for the action | +----------------+--------------------------------------------------------+ | namespace | A valid namespace name where the controller is part of | +----------------+--------------------------------------------------------+ 获å–傿•°(Getting Parameters) ----------------------------------------- 当一æ¡è·¯ç”±æä¾›äº†å‘½å傿•°ï¼Œä½ å¯ä»¥åœ¨æŽ§åˆ¶å™¨ï¼Œè§†å›¾æ–‡ä»¶æˆ–者其他任何继承了 :doc:`Phalcon\\DI\\Injectable <../api/Phalcon_DI_Injectable>` 的组件ä¸èŽ·å–值。 .. code-block:: php <?php class PostsController extends \Phalcon\Mvc\Controller { public function indexAction() { } public function saveAction() { // Get the post's title passed in the URL as parameter $title = $this->dispatcher->getParam("title"); // Get the post's year passed in the URL as parameter // also filtering it $year = $this->dispatcher->getParam("year", "int"); } } Handling Not-Found Exceptions ----------------------------- 使用 :doc:`EventsManager <events>` ,æ’入一个挂钩点,以使在controller/actionä¸å˜åœ¨çš„æ—¶å€™ï¼ŒæŠ›å‡ºä¸€ä¸ªå¼‚常信æ¯ã€‚ .. code-block:: php <?php $di->setShared('dispatcher', function() { //Create/Get an EventManager $eventsManager = new Phalcon\Events\Manager(); //Attach a listener $eventsManager->attach("dispatch", function($event, $dispatcher, $exception) { //The controller exists but the action not if ($event->getType() == 'beforeNotFoundAction') { $dispatcher->forward(array( 'controller' => 'index', 'action' => 'show404' )); return false; } //Alternative way, controller or action doesn't exist if ($event->getType() == 'beforeException') { switch ($exception->getCode()) { case Phalcon\Dispatcher::EXCEPTION_HANDLER_NOT_FOUND: case Phalcon\Dispatcher::EXCEPTION_ACTION_NOT_FOUND: $dispatcher->forward(array( 'controller' => 'index', 'action' => 'show404' )); return false; } } }); $dispatcher = new Phalcon\Mvc\Dispatcher(); //Bind the EventsManager to the dispatcher $dispatcher->setEventsManager($eventsManager); return $dispatcher; }); 实现自定义分å‘器(Implementing your own Dispatcher) ------------------------------------------------------------------ 通过实现 :doc:`Phalcon\\Mvc\\DispatcherInterface <../api/Phalcon_Mvc_DispatcherInterface>` æŽ¥å£æ–‡ä»¶å¯ä»¥åœ¨Phalconä¸åˆ›å»ºä¸€ä¸ªè‡ªå®šä¹‰çš„分å‘器。