Где регистрировать слушателей событий - программирование
Подтвердить что ты не робот

Где регистрировать слушателей событий

Я пытаюсь использовать систему событий в 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 event manager
$statistics = new UserStatistic();
$this->Order->getEventManager()->attach($statistics);

Но он не говорит, где должен находиться этот код. Внутри конкретного контроллера? Внутри контроллера приложения?

В случае, если это имеет значение, слушатель будет частью плагина, который я пишу.

Update: Это звучит как популярный способ сделать это, поместив регистрационный код слушателя в файл 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');

Я не уверен, почему, но я не могу получить ошибки, когда я пытаюсь объединить два App::uses() в одну строку.

4b9b3361

Ответ 1

События

События - это обратные вызовы, связанные с строкой. Объект, подобный Модели, вызывает событие, используя строку, даже если ничто не слушает это событие.

CakePHP поставляется с встроенными событиями для таких вещей, как модели. Вы можете присоединить прослушиватель событий к модели и ответить на событие Model.beforeSave.

EventManager

Каждая модель в торте имеет собственный EventManager, плюс есть gobal singleton EventManager. Это не все тот же экземпляр EventManager, и они работают несколько иначе.

Когда модель запускает событие, она делает это, используя имеющуюся ссылку EventManager. Это означает, что вы можете присоединить прослушиватель событий к определенной модели. Преимущества в том, что ваш слушатель будет получать события только от этой модели.

Глобальные слушатели - это те, которые привязаны к экземпляру Singleton EventManager. Который можно получить в любом месте вашего кода. Когда вы присоединяете слушателя там, он вызывает каждое событие, которое происходит независимо от того, кто его запускает.

Когда вы присоединяете прослушиватель событий в bootstrap.php приложения или плагина, вы можете использовать глобальный менеджер, иначе вам нужно получить ссылку на требуемую модель с помощью ClassRegistry.

Какой EventManager использовать?

Если событие, которое вы хотите обработать, предназначено для конкретной модели, затем присоедините слушателя к этому EventManager модели. Чтобы получить ссылку на модель, вы можете вызвать ClassRegistry::init(...).

Если событие, которое вы хотите обработать, может быть запущено в любом месте, затем присоедините слушателя к глобальному EventManager.

Только вы знаете, как следует использовать ваш слушатель.

Внутри прослушивателя

Как правило, вы вводите свою бизнес-логику в модели. Вам не нужно получать доступ к контроллеру из прослушивателя событий. Модели намного легче получить доступ и использовать в 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.

Присоединение EventListeners

Опять же, это зависит от того, какие события вам нужно слушать. Первое, что вам нужно понять, это то, что объект должен быть создан для запуска события.

Например:

Невозможно, чтобы модель Document запускала событие Model.beforeSave, когда контроллер Calendar отображает индекс, потому что контроллер Calendar никогда не использует модель Document. Вам нужно добавить слушателя в Document в bootstrap.php, чтобы поймать, когда он сэкономит? Нет, если модель Document используется только от контроллера Documents, вам нужно только прикрепить туда слушателя.

С другой стороны, модель 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->getEventManager()->attach(new MyListener());

Если модель User используется во многих разных местах. Возможно, вам придется сделать это в bootstrap.php, но если он используется только одним контроллером. Вы можете разместить этот код в beforeFilter или в верхней части файла PHP.

Что такое глобальный EventManager?

Предполагая, что нам нужно слушать общие события. Как когда-либо любая вещь сохраняется. Мы хотели бы подключиться к глобальному EventManager. Он будет выглядеть примерно так и помещаться в bootstrap.php.

App::uses('MyListener','Lib');
CakeEventManager::instance()->attach(new MyListener());

Ответ 2

Если вы хотите подключить прослушиватель событий в файле bootstrap.php вашего плагина, все должно работать нормально, используя подсказки, указанные в ответах. Вот мой код (который работает правильно):

MyPlugin/Config/bootstrap.php:

App::uses('CakeEventManager', 'Event');
App::uses('MyEventListener', 'MyPlugin.Lib/Event');
CakeEventManager::instance()->attach(new MyEventListener());

MyPlugin/Lib/Событие/MyEventListener.php:

App::uses('CakeEventListener', 'Event');
class MyEventListener implements CakeEventListener {
    ...
}

Слушатели событий, связанные с MyPlugin, регистрируются только при загрузке плагина. Если я не хочу использовать плагин, прослушиватели событий не подключены. Я думаю, что это чистое решение, если вы хотите добавить некоторые функции в различных местах вашего приложения, используя плагин.

Ответ 3

Это не важно, где находится код. Просто убедитесь, что он выполнен и ваши события зарегистрированы и подключены.

Мы используем один файл, в котором все события подключены и включают его из bootstrap.php, это гарантирует, что все события доступны из всех мест в приложении.

Магия происходит, когда вы отправляете событие, например, из действия контроллера.

$event = new CakeEvent('Model.Order.afterPlace', $this, array('some'=>'data') ));
$this->getEventManager()->dispatch($event);

Однако вы можете отправлять события из любого места, где вы можете добраться до EventManager (в моделях, контроллерах и представлениях по умолчанию)