Я пытаюсь использовать систему событий в 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);
Но он не говорит, где должен находиться этот код. Внутри конкретного контроллера? Внутри контроллера приложения?
В случае, если это имеет значение, слушатель будет частью плагина, который я пишу.
Обновление. Это звучит как популярный способ сделать это, поместив регистрационный код слушателя в файл 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()
в одну строку.
События – это обратные вызовы, связанные с строкой. Объект, подобный Модели, вызывает событие, использующее строку, даже если ничто не слушает это событие.
CakePHP поставляется с встроенными событиями для таких вещей, как модели. Вы можете присоединить прослушиватель событий к модели и ответить на событие Model.beforeSave
.
Каждая модель в торте имеет собственный EventManager, плюс есть gobal singleton EventManager. Это не все тот же экземпляр EventManager, и они работают несколько иначе.
Когда модель запускает событие, она делает это с использованием справки EventManager. Это означает, что вы можете присоединить прослушиватель событий к определенной модели. Преимущества заключаются в том, что ваш слушатель будет получать события только от этой модели.
Глобальные слушатели – это те, которые привязаны к экземпляру Singleton EventManager. Который можно получить в любом месте вашего кода. Когда вы присоединяете слушателя там, он вызывается для каждого события, которое происходит независимо от того, кто его запускает.
Когда вы присоединяете прослушиватель событий в bootstrap.php
приложения или плагина, вы можете использовать глобальный менеджер, иначе вам нужно получить ссылку на ClassRegistry
модель, используя ClassRegistry
.
Если событие, которое вы хотите обработать, предназначено для конкретной модели, затем присоедините слушателя к 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
.
Опять же, это зависит от того, какие события вам нужно слушать. Первое, что вам нужно понять, это то, что для запуска события должен быть создан объект.
Модель Document
может Model.beforeSave
событие 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. Это будет похоже на что-то подобное и будет помещено в bootstrap.php
.
App::uses('MyListener','Lib'); CakeEventManager::instance()->attach(new MyListener());
Если вы хотите подключить прослушиватель событий в файле 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, регистрируются только при загрузке плагина. Если я не хочу использовать плагин, прослушиватели событий не подключены. Я думаю, что это чистое решение, если вы хотите добавить некоторые функции в разных местах вашего приложения, используя плагин.
Его «не важно, где находится код. Просто убедитесь, что он выполнен и ваши события зарегистрированы и подключены.
Мы используем один файл, в котором все события подключены и включают его из bootstrap.php, что гарантирует, что все события доступны из всех мест в приложении.
Магия происходит, когда вы отправляете событие, например, из действия контроллера.
$event = new CakeEvent('Model.Order.afterPlace', $this, array('some'=>'data') )); $this->getEventManager()->dispatch($event);
Однако вы можете отправлять события из любого места, куда вы можете попасть в EventManager (по умолчанию в моделях, контроллерах и представлениях)