The EventDispatcher component provides tools that allow your application components to communicate with each other by dispatching events and listening to them.
an event is an action or an occurrence recognised by software that may be handled by software.
The idea is to be able to run random code at given places in the engine. This random code should then be able to do whatever needed to enhance the functionality. The places where code can be executed are called “hooks” and are defined by a fixed interface.
~ Dries Buytaert.
composer require symfony/event-dispatcher
Using version ^3.2 for symfony/event-dispatcher
./composer.json has been created
Loading composer repositories with package information
Updating dependencies (including require-dev)
- Installing symfony/event-dispatcher (v3.2.6)
Loading from cache
symfony/event-dispatcher suggests installing symfony/dependency-injection ()
symfony/event-dispatcher suggests installing symfony/http-kernel ()
Writing lock file
Generating autoload files
Text
Text
// create an EventDispatcher instance.
$dispatcher = new EventDispatcher();
// the order is somehow created or retrieved
$order = new Order();
// ...
// create the OrderPlacedEvent and dispatch it
$event = new OrderPlacedEvent($order);
// dispatch the event.
$dispatcher->dispatch(OrderPlacedEvent::NAME, $event);
// or $dispatcher->dispatch(order.placed, $event);
/**
* The order.placed event is dispatched each time an order is created
* in the system.
*/
class OrderPlacedEvent extends Event {
const NAME = 'order.placed';
protected $order;
public function __construct(Order $order) {
$this->order = $order;
}
public function getOrder() {
return $this->order;
}
}
/**
* Event is the base class for classes containing event data.
* This class contains no event data. It is used by events that do not pass
* state information to an event handler when an event is raised.
*/
class Event
{
/**
* @var bool Whether no further event listeners should be triggered
*/
private $propagationStopped = false;
/**
* Returns whether further event listeners should be triggered.
*/
public function isPropagationStopped()
{
return $this->propagationStopped;
}
/**
* Stops the propagation of the event to further event listeners.
*/
public function stopPropagation()
{
$this->propagationStopped = true;
}
}
The base Event class provided by the EventDispatcher component is deliberately sparse to allow the creation of API specific event objects by inheritance using OOP. This allows for elegant and readable code in complex applications.
class StoreSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return array(
KernelEvents::RESPONSE => array(
array('onKernelResponsePre', 10),
array('onKernelResponsePost', -10),
),
OrderPlacedEvent::NAME => 'onStoreOrder',
);
}
public function onKernelResponsePre(FilterResponseEvent $event)
{
// do something.
}
public function onKernelResponsePost(FilterResponseEvent $event)
{
// do something.
}
public function onStoreOrder(OrderPlacedEvent $event)
{
// do something.
}
}
class AcmeListener
{
// ...
public function onFooAction(Event $event)
{
// ... do something
}
}
// This is very similar to a subscriber class,
// except that the class itself cant tell the dispatcher which events it should listen to.
// create an EventDispatcher instance.
$dispatcher = new EventDispatcher();
$subscriber = new StoreSubscriber();
// Register subscriber
$dispatcher->addSubscriber($subscriber);
// add a listener
$listener = new AcmeListener();
$dispatcher->addListener('acme.foo.action', array($listener, 'onFooAction'));
// create the OrderPlacedEvent and dispatch it
$event = new OrderPlacedEvent($order);
// dispatch the event.
$dispatcher->dispatch(OrderPlacedEvent::NAME, $event);
// or $dispatcher->dispatch(order.placed, $event);
# app/config/services.yml
services:
kernel.listener.your_listener_name:
class: AppBundle\EventListener\AcmeExceptionListener
tags:
- { name: kernel.event_listener, event: kernel.exception, method:
onKernelException }
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher;
$container = new ContainerBuilder();
$dispatcher = new ContainerAwareEventDispatcher($container);
// Add the listener and subscriber services
$dispatcher->addListenerService($eventName, array('foo', 'logListener'));
$dispatcher->addSubscriberService(
'kernel.store_subscriber',
'StoreSubscriber'
);
// the event dispatcher to debug
$eventDispatcher = ...;
$traceableEventDispatcher = new TraceableEventDispatcher( $eventDispatcher, new Stopwatch()
);
$traceableEventDispatcher->addListener(
'event.the_name',
$eventListener,
$priority
);
// dispatch an event
$traceableEventDispatcher->dispatch('event.the_name', $event);
$calledListeners = $traceableEventDispatcher->getCalledListeners();
$notCalledListeners = $traceableEventDispatcher->getNotCalledListeners();
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\EventDispatcher\ImmutableEventDispatcher;
$dispatcher = new EventDispatcher();
$dispatcher->addListener('foo.action', function ($event) {
// ...
});
// ...
// ...
$immutableDispatcher = new ImmutableEventDispatcher($dispatcher);
class ConfigFactory implements ConfigFactoryInterface, EventSubscriberInterface {
static function getSubscribedEvents() {
$events[ConfigEvents::SAVE][] = array('onConfigSave', 255);
$events[ConfigEvents::DELETE][] = array('onConfigDelete', 255);
return $events;
}
}
// services.yml
config.factory:
class: Drupal\Core\Config\ConfigFactory
tags:
- { name: event_subscriber }
- { name: service_collector, tag: 'config.factory.override', call: addOverride }
arguments: ['@config.storage', '@event_dispatcher', ‘@config.typed']
services:
event_demo.alter_response:
class: Drupal\event_demo\EventSubscriber\AlterResponse
arguments: [ '@logger.factory' ]
tags:
- { name: event_subscriber }
$dispatcher = \Drupal::service('event_dispatcher');
// or inject as a dependency
$event = new EventDemo($config);
$event = $dispatcher->dispatch(EVENT_NAME, $event);