Первым делом - EventDispatcher это реализация паттерна Диспетчер (можете представить себе телефонного диспетчера или диспетчера в аэропорту).
| Описание | Один системный компонент назначается диспетчером и управляет запуском и завершением других процессов системы и координирует эти процессы. Процессы могут протекать параллельно (в нашем случае последовадтельно, т.к. PHP). |
| Рекомендации | Применяется в системах, в которых необходимо организовать параллельные процессы, но может использоваться также и для последовательных систем, в которых- управляющая программа вызывает отдельные подсистемы в зависимости от значений некоторых переменных состояния. |
| Пример | Можно использовать в системах реального времени, где нет чересчур строгих временных ограничений (в так называемых "мягких" системах реального времени). |
Давайте посмотрим, каким классом реализуется диспетчер событий:
$ app/console container:debug | grep dispatcher debug.event_dispatcher Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher event_dispatcher alias for "debug.event_dispatcher"
Ага, значит диспетчер событий это реализация TraceableEventDispatcher.
Мы знаем, что для оптимизации, Symfony не работает с классами напрямую, и поэтому кэширует многие классы в кэш-директории. Диспетчер событий тоже кэшируется, в файле app/cache/dev/appDevDebugProjectContainer.php, в методе \appDevDebugProjectContainer::getDebug_EventDispatcherService:
$this->services['debug.event_dispatcher'] = new \Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher(
new \Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher($this),// диспетчер событий
$this->get('debug.stopwatch'),//
$this->get('monolog.logger.event', ContainerInterface::NULL_ON_INVALID_REFERENCE)// логгер
);
Как видите TraceableEventDispatcher по сути не является диспетчером событий, а является оберткой над диспетчером ContainerAwareEventDispatcher. Зачем так сделано? Официальный ответ - чтобы узнать какие слушатели были вызваны при наступлении событий (так сказать, для дебага).
ContainerAwareEventDispatcher является потомком класса EventDispatcher.
Компонент EventDispatcher пытается нас запутать используя термины Listener и Subscriber, но по факту это является одной сущностью - слушателем.
И прежде чем продолжить, хочу определить понятие:
ID сервиса - то имя, которое Вы объявляете в app/config/config.yml в секции services.
В ContainerAwareEventDispatcher есть 2 способа добавления слушателей:
addListenerService($eventName, $callback, $priority = 0) где:
$eventName - имя события, на которое подписываем
$callback - кого подписать - массив вида: [
0 => ID сервиса,
1 => метод, который должен быть вызван
]
$priority - приоритет вызова.
Пример использования:
$eventDispatcher = new Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher($container);
$eventDispatcher->addListenerService(
'kernel.request',
array(0 => 'assetic.request_listener', 1 => 'onKernelRequest'),
0
);
таким образом, при срабатывании события kernel.request произойдет вызов:
$listener = new \Symfony\Bundle\AsseticBundle\EventListener\RequestListener();
$listener->onKernelRequest($event);
addSubscriberService($serviceId, $class) где:
$serviceId - кого подписать (ID сервиса)
$class - класс, в котором eventDispatcher возьмет настройки подписки. У данного класса должен существует статичный метод getSubscribedEvents(), данный метод должен отдать массив вида:
[
$eventName - имя события, на которое подписываем выше указанный сервис => [
0 => имя метода, который должен быть вызван для срабатывании события $eventName
1 => приоритет вызова
],
$eventName2 => ...
]
Пример использования:
$eventDispatcher = new Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher($container);
$eventDispatcher->addSubscriberService(
'debug.debug_handlers_listener',
'Symfony\\Component\\HttpKernel\\EventListener\\DebugHandlersListener'
);
таким образом Symfony\Component\HttpKernel\EventListener\DebugHandlersListener::getSubscribedEvents() знает на какие события нужно подписать сервис debug.debug_handlers_listener.
Запутано - да, но что поделать, как мы видим Symfony-программисты не ищут легких путей
Еще есть события, которые просто называются именами классов, например:
$ bin/console debug:event --dispatcher=security.event_dispatcher.main
Registered Listeners of Event Dispatcher "security.event_dispatcher.main" Grouped by Event
==========================================================================================
"Symfony\Component\Security\Http\Event\CheckPassportEvent" event
----------------------------------------------------------------
------- ------------------------------------------------------------------------------------------ ----------
Order Callable Priority
------- ------------------------------------------------------------------------------------------ ----------
#1 Symfony\Component\Security\Http\EventListener\UserProviderListener::checkPassport() 1024
#2 Symfony\Component\Security\Http\EventListener\UserCheckerListener::preCheckCredentials() 256
#3 Symfony\Component\Security\Http\EventListener\CheckCredentialsListener::checkPassport() 0
------- ------------------------------------------------------------------------------------------ ----------
"Symfony\Component\Security\Http\Event\LoginSuccessEvent" event
---------------------------------------------------------------
------- -------------------------------------------------------------------------------------------- ----------
Order Callable Priority
------- -------------------------------------------------------------------------------------------- ----------
#1 Symfony\Component\Security\Http\EventListener\SessionStrategyListener::onSuccessfulLogin() 0
#2 Symfony\Component\Security\Http\EventListener\PasswordMigratingListener::onLoginSuccess() 0
------- -------------------------------------------------------------------------------------------- ----------
"security.authentication.success" event
---------------------------------------
------- ------------------------------------------------------------------------------------------- ----------
Order Callable Priority
------- ------------------------------------------------------------------------------------------- ----------
#1 Symfony\Component\Security\Http\EventListener\UserCheckerListener::postCheckCredentials() 256
------- ------------------------------------------------------------------------------------------- ---------- как видите, здесь например есть событие с названием "Symfony\Component\Security\Http\Event\LoginSuccessEvent" на которое можно подписаться например так:
App\Event\LoginSuccessEventListener:
arguments:
$properties:
'google_key': 'google_value'
'yandex_key': 'yandex_value'
tags:
- { name: kernel.event_listener, event: Symfony\Component\Security\Http\Event\LoginSuccessEvent, priority: 1, method: onLoginSuccess }Зачем это происходит, я пока не разобрался, может быть отпишусь позже.
Всем удачки.
Комментарии
Комментариев пока нет.