Phalcon学习笔记(6)分发器和事件管理器

Phalcon启动之后,会通过router路由器将URL解析,然后传递给dispatcher分发器,分发器会找到对应的Module/Controller/Action并执行,执行中会输出到view视图发送给客户端。


简单情况下分发器不需要特殊的配置,router的解析已经足够,一般来讲,只有在判断用户权限的时候才需要特殊处理

$di->set('dispatcher', function () {
            $dispatcher = new \Phalcon\Mvc\Dispatcher();

            //Attach a event listener to the dispatcher
            $eventManager = new \Phalcon\Events\Manager();
            $eventManager->attach('dispatch:beforeDispatch', new \SecurityPlugin(__CLASS__));

            $dispatcher->setEventsManager($eventManager);
            $dispatcher->setDefaultNamespace('Multiple\Entrance\Controllers\\');
            return $dispatcher;
        });

实际上Phalcon内建有事件机制,在Phalcon的很多类中都有事件接口,通过对事件接口的重新定义并挂载事件管理器,可以让个各类针对不同的情况在程序执行的特殊阶段做出不同的反映,比如跳转回主页之类。


\Phalcon\Events\Manager类通过attach函数的第一个参数定义流程控制类的某个特殊事件,通过第二个参数定义对应的行为,然后在流程控制对象中使用setEventsManager函数挂上这个事件控制器类,就可以在特定的事件发生时,调用事件控制器定义的行为,如果行为执行正常会返回程序主线,如果行为执行之后跳出了流程,就不会返回了。


常见的被视为跳出流程的标志有:1)返回false;2)重定向;3)强行中止;4)抛出异常


如果返回null或者true则会返回主线继续执行。


也就是说attach函数的第2个参数其实才是主要问题。实际上笔者的习惯是把用户权限判定放在那里。


对于分发器而言,内建有一些事件定义。对于其他的类,也有事件定义,可以参考各个类的官方手册。

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


来看一个稍微复杂点的事件管理器,它可以在找不到对应的Controller/Action时,做出合适的处理,不让用户看到难看的404错误

$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;
});



分发器的另外一个用途是让我们从一个Controller/Action跳转到另一个Controller/Action

dispatcher->forward(array(
            "controller" => "post",
            "action" => "index"
        ));
    }

}

请记住,forward和HTTP重定向不一样,虽然他们显示了相同的结果。forward不刷新当前页面,所有的重定向都发生在一个单一的请求中,而HTTP重定向则需要完成两个请求。


另外在多Module程序中,forward不能跳到另一个Module,而HTTP重定向可以。这个时候使用下面的代码实现跳转

$this->response->redirect('entrance/index/login');


forward还有一些用法

// 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)
));

另外还可以通过getParam函数获取一些URL的信息

// 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");

这些信息可以让程序做出针对性的反应



你可能感兴趣的:(Phalcon,Phalcon)