深入了解cakephp之 - cake事件处理

来源:互联网 发布:淘宝卫生巾假货 编辑:程序博客网 时间:2024/05/21 16:12
大家接触cakephp首先想到的就是MVC框架,网络上的很多课程也都是从MVC入手开始学习使用cakephp. 我也想和大家一起来探讨一下 cakephp 2.x 的开发,但我选择开始的地方是cakephp的路由,因为这里是一切访问开始的地方。说到cakephp的路由又不得不从事件机制说起。原谅我绕来绕去,如果纯粹用MVC,市面上一堆框架,要学cakephp,我们就一起来看看最核心的东西,我敢保证,对你帮助是最大的。

说到CakeEvent,我们又来说说WordPress的机制. Wordpress很多站长都用过,这可是快速建站的利器,模板资源海了去了,而且要写一个插件也很容易。比如我们想改写博文的标题,我们可以这么干

add_filter('the_title', function($title) { return rewrite($title); });

这条语句往'the_title'的事件链条里插入了一个hook函数,wordpress在获取title的地方会调用 apply_filters('the_title', $title), 这个函数会依优先级调用所有事件链条里和the_title关联的函数,这样你自定义的函数也会有幸被执行到。cakephp也是通过类似的机制来实现框架内调用链的问题,这个管理类就是 CakeEventManager. 我们来看一个需求,我想在所有的页面最后加一行文字。我们用CakeEvent实现的代码是

app/Config/bootstrap.php 文件最后添加下面的代码


App::uses('CakeEventManager', 'Event');CakeEventManager::instance()->attach(function($event) {    $event->data['response']->body($event->data['response']->body() . "<!-- from jameshu@live.com -->");}, 'Dispatcher.afterDispatch');



这段代码往Dispatcher.afterDispatch的事件链表里加入自定义函数,改写response的内容。大家可以试试。'Dispatcher.afterDispatch'在哪儿使用的呢?大家看 app/webroot/index.php的最后几行,再看看 lib\Cake\Routing\Dispatcher.php:dispatch函数最后几行就明白了. CakeEvent的使用可以帮助我们松耦合程序的逻辑,使特定的功能逻辑更加简洁。比如我们想实现用户登录的安全检测,防止过于频繁的访问。

class UsersController extends AppController {...    public function login() {        $this->_checkLoginAttempts();        if($this->request->is('post')) {            ..        }    }...}


这是一种实现的方法,把逻辑封装在_checkLoginAttempts里,将来加入新的逻辑,改_checkLoginAttempts代码即可。随着逻辑的增加,UsersController.php也会越来越大。现在我们用CakeEvent来实现类似功能

class UsersController extends AppController {       public function implementedEvents() {        return $this->implementedEvents() + array(            'Controller.Users.beforeLogin' => 'onBeforeLogin',            'Controller.Users.afterLoginSuccessful' => 'onLoginSuccessful',            'Controller.Users.afterLoginFailure' => 'onLoginFailure',        );    }    public function onBeforeLogin($event) {        // check login attempts    }    public function login() {        $this->getEventManager()->dispatch('Controller.Users.beforeLogin', $this);        if($this->request->is('post')) {            if($this->Auth->login()) {                $this->getEventManager()->dispatch('Controller.Users.afterLoginSuccessful', $this);                ...            } else {                $this->getEventManager()->dispatch('Controller.Users.afterLoginFailure', $this);                ...            }        }    }}


implementedEvents()函数告诉系统,我这个类监听了哪些事件,当然,你也可以直接在__construct里面直接给CakeEventManager attach一些事件。这么写了以后程序的逻辑就很清晰了,login之前调用一圈关注了Controller.Users.beforeLogin的函数,大家都一致通过了,咱就继续往下走。你可以在UsersController里面定义你的回调函数,你也可以在别的地方追加,比如之前的例子,在bootstrap.php里。大部分网站在用户注册以后要发送确认邮件,你就可以用CakeEvent来实现,将来可以很灵活地追加更加功能来跟踪用户注册成功的事件。具体系统有哪些事件可以侦听,可以参见 lib/Cake/Model/Model.php lib/Cake/Controller/Controller.php lib/Cake/View/HelperCollection.php 里的implementedEvents函数。官方的文档在 http://book.cakephp.org/2.0/en/core-libraries/events.html。我的微博 "James胡建",QQ号码 914244905,欢迎关注我。下一讲,cakephp的路由。