在哪里注册事件监听器

eme*_*his 16 php events cakephp cakephp-2.0 cakephp-2.1

我正在尝试使用CakePHP v2.1 +中的事件系统

它看起来非常强大,但文档有些模糊.触发事件看起来很简单,但我不知道如何注册相应的监听器来监听事件.相关部分在这里,它提供以下示例代码:

App::uses('CakeEventListener', 'Event');
class UserStatistic implements CakeEventListener {

    public function implementedEvents() {
        return array(
            'Model.Order.afterPlace' => 'updateBuyStatistic',
        );
    }

    public function updateBuyStatistic($event) {
        // Code to update statistics
    }
}

// Attach the UserStatistic object to the Order's event manager
$statistics = new UserStatistic();
$this->Order->getEventManager()->attach($statistics);
Run Code Online (Sandbox Code Playgroud)

但它没有说明这个代码应该驻留在哪里.在特定的控制器内?在app控制器里面?

如果它是相关的,那么监听器将成为我正在编写的插件的一部分.

更新: 这听起来像一种流行的方法是将监听器注册码放在插件的bootstrap.php文件中.但是,我无法弄清楚如何从那里调用getEventManager(),因为应用程序的控制器类等不可用.

更新2: 我还被告知听众可以住在模特里面.

更新3: 最后一些牵引力!以下代码将在MyPlugin/Config/bootstrap.php中成功记录事件

App::uses('CakeEventManager', 'Event'); 
App::uses('CakeEventListener', 'Event');
class LegacyWsatListener implements CakeEventListener {

    public function implementedEvents() {
        return array(
            'Controller.Attempt.complete' => 'handleLegacyWsat',
        );
    }

    public static function handleLegacyWsat($event) { //method must be static if used by global EventManager
        // Code to update statistics
        error_log('event from bootstrap');
    }
}
 CakeEventManager::instance()->attach(array('LegacyWsatListener', 'handleLegacyWsat'), 'Controller.Attempt.complete');
Run Code Online (Sandbox Code Playgroud)

我不确定为什么,但是当我尝试将两者App::uses()合并为一行时,我不会出错.

Rea*_*lar 24

活动

事件是与字符串关联的回调.对象(如Model)将使用字符串触发事件,即使没有任何内容正在侦听该事件.

CakePHP预先构建了与模型之类的内容事件.您可以将事件侦听器附加到模型并响应Model.beforeSave事件.

EventManager

Cake中的每个Model都有自己的EventManager,还有一个gobal singleton EventManager.这些并不是EventManager的所有实例,它们的工作方式略有不同.

当模型触发事件时,它使用它具有的EventManager引用.这意味着,您可以将事件侦听器附加到特定模型.优点是您的监听器只接收来自该模型的事件.

全局侦听器是附加到EventManager的单例实例的侦听器.可以在代码中的任何位置访问.当你在那里附加一个监听器时,无论是谁触发它,都会调用每个发生的事件.

当您在bootstrap.php应用程序或插件中附加事件侦听器时,您可以使用全局管理器,否则您必须获得对所需模型的引用ClassRegistry.

EventManager要使用什么?

如果要处理的事件是针对特定模型的,则将侦听器附加到该模型的EventManager.要获得模型的参考,您可以调用ClassRegistry::init(...).

如果您想要处理的事件可以在任何地方触发,则将侦听器附加到全局EventManager.

只有你知道应该如何使用你的听众.

在听众中

通常,您将业务逻辑放入模型中.您不需要从事件侦听器访问Controller.模型在Cake中更容易访问和使用.

这是一个用于创建CakeEventListener的模板.监听器负责监视何时发生事件,然后将该信息传递给另一个模型.您应该放置业务逻辑以在模型中处理事件.

<?php

App::uses('CakeEventListener', 'Event');

class MyListener implements CakeEventListener
{
    /**
     *
     * @var Document The model.
     */
    protected $Document;

    /**
     * Constructor
     */
    public function __construct()
    {
        // get a reference to a Model that we'll use
        $this->Document = ClassRegistry::init('Agg.Document');
    }

    /**
     * Register the handlers.
     *
     * @see CakeEventListener::implementedEvents()
     */
    public function implementedEvents()
    {
        return array(
            'Model.User.afterSave'=>'UserChanged'
        );
    }

    /**
     * Use the Event to dispatch the work to a Model.
     *
     * @param CakeEvent $event
     *          The event object and data.
     */
    public function UserChanged(CakeEvent $event)
    {
        $data = $event->data;
        $subject = $event->subject();

        $this->Document->SomethingImportantHappened($data,$subject);
    }
}
Run Code Online (Sandbox Code Playgroud)

我喜欢做的是将所有事件放入Lib文件夹中.这使得从源代码中的任何位置访问都非常容易.上面的代码将进入App/Lib/Event/MyListener.php.

附加EventListeners

同样,这取决于您需要监听的事件.您必须要了解的第一件事是必须创建一个对象才能触发事件.

例如;

这是不可能的Document模型火灾Model.beforeSave时,事件Calendar控制器显示的索引,因为日历控制器从不使用的Document模型.你需要Documentbootstrap.php保存时添加一个监听器吗?不,如果Document仅从Documents控制器使用模型,那么您只需要在那里附加监听器.

另一方面,UserAuth组件几乎每个都使用该模型.如果要处理User被删除的内容.您可能必须附加一个事件监听器,bootstrap.php以确保您没有删除.

在上面的例子中,我们可以User像这样直接附加到模型.

App::uses('MyListener','Lib');
$user = ClassRegistry::init('App.User');
$user->getEventManager()->attach(new MyListener());
Run Code Online (Sandbox Code Playgroud)

该行将导入您的侦听器类.

App::uses('MyListener','Lib');
Run Code Online (Sandbox Code Playgroud)

该行将获得用户模型的实例.

$user = ClassRegistry::init('App.User');
Run Code Online (Sandbox Code Playgroud)

此行创建一个侦听器,并将其附加到User模型.

$user->getEventManager()->attach(new MyListener());
Run Code Online (Sandbox Code Playgroud)

如果User模型用于许多不同的地方.您可能必须在此中执行此操作bootstrap.php,但如果它仅由一个控制器使用.您可以将该代码放在beforeFilterPHP文件的顶部或顶部.

全球EventManager怎么样?

假设我们需要倾听一般事件.就像什么东西都得救了.我们希望附加到全局EventManager.它会像这样,放在bootstrap.php.

App::uses('MyListener','Lib');
CakeEventManager::instance()->attach(new MyListener());
Run Code Online (Sandbox Code Playgroud)