php - 在哪里注册事件监听器

标签 php events cakephp cakephp-2.0 cakephp-2.1

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

它看起来很强大,但文档有点模糊。触发事件似乎很简单,但我不确定如何注册相应的监听器来监听事件。相关栏目是here它提供了以下示例代码:

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

但它并没有说明该代码应该驻留在何处。在特定的 Controller 内?在应用程序 Controller 内部?

如果相关,监听器将成为我正在编写的插件的一部分。

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

更新 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');

我不知道为什么,但是当我尝试将两者结合起来时我不会出错 App::uses()成一行。

最佳答案

事件
事件是与字符串关联的回调。像模型这样的对象将使用字符串触发事件,即使没有任何东西在监听该事件。
CakePHP 预先构建了诸如模型之类的内部事件。您可以将事件监听器附加到模型并响应 Model.beforeSave事件。
事件管理器
Cake 中的每个模型都有自己的 EventManager,另外还有一个全局单例 EventManager。这些不是 EventManager 的所有相同实例,它们的工作方式略有不同。
当模型触发事件时,它使用它拥有的 EventManager 引用来触发。这意味着,您可以将事件监听器附加到特定模型。优点是您的监听器只会接收来自该模型的事件。
全局监听器是附加到 EventManager 的单例实例的监听器。可以在代码中的任何位置访问。当您在那里附加一个监听器时,无论是谁触发它,都会为发生的每个事件调用它。
当您在 bootstrap.php 中附加事件监听器时应用程序或插件,然后您可以使用全局管理器,否则您必须使用 ClassRegistry 获得对所需模型的引用.
使用什么事件管理器?
如果您要处理的事件是针对特定模型的,则将监听器附加到该模型的 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);
    }
}
我喜欢做的是将我所有的事件放入 Lib文件夹。这使得从源代码的任何地方访问都非常容易。上面的代码会进入App/Lib/Event/MyListener.php .
附加事件监听器
同样,这取决于您需要监听哪些事件。您必须了解的第一件事是必须创建一个对象才能触发事件。
例如;Document 不可能火模型Model.beforeSave事件时Calendar Controller 正在显示一个索引,因为日历 Controller 从不使用 Document模型。是否需要为Document添加监听器?在 bootstrap.php当它保存时捕捉?不,如果 Document模型仅用于 Documents Controller ,那么你只需要在那里附加监听器。
另一方面,User模型由 Auth 使用几乎每个组件。如果你想处理一个 User被删除。您可能需要在 bootstrap.php 中附加一个事件监听器。以确保您不会偷偷删除。
在上面的例子中,我们可以直接附加到 User像这样的模型。
App::uses('MyListener','Lib');
$user = ClassRegistry::init('App.User');
$user->getEventManager()->attach(new MyListener());
这一行将导入您的监听器类。
App::uses('MyListener','Lib');
这一行将获得用户模型的一个实例。
$user = ClassRegistry::init('App.User');
此行创建一个监听器,并将其附加到 User 模型。
$user->getEventManager()->attach(new MyListener());
如果User模型用于许多不同的地方。您可能必须在 bootstrap.php 中执行此操作,但如果它只被一个 Controller 使用。您可以将该代码放在 beforeFilter 中或在 PHP 文件的顶部。
全局事件管理器怎么样?
假设我们需要监听一般事件。就像以前一样任何 东西被保存了。我们希望附加到全局 EventManager。它会像这样,并被放置在 bootstrap.php 中。 .
App::uses('MyListener','Lib');
CakeEventManager::instance()->attach(new MyListener());

关于php - 在哪里注册事件监听器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16923246/

相关文章:

javascript - 针对 JavaScript 代码的 CakePHP 表单验证

javascript - 使用基于 Codeigniter 的 Jquery Java 刷新 html 表

php - 从 mysql 返回多个结果以分离 jQuery 模态

php - php返回的数据为空,iOS

c# - 访问派生类中事件的选项有限?

php - CakePHP 中的 requestAction 性能

php - 我们如何读取laravel中views文件夹中存储的html文件的内容?

c# - 如何通过反射获取事件目标方法

c# - 有没有类似于 Silverlight 的 AutomationFactory for .NET 的类?

CakePHP 用相同的模型更新记录 ID 的多行