Events are the new hooks. But what is an event really? How can you best describe an event in your code? What types of events are there, and how do you decide whether or not to implement something as an event?
In this talk we take a look at how events are essential to processing a Request and producing a Response. We take a look at the Symfony EventDispatcher and related classes that you need when you want to hook into this process. When you know all about the event system and how you can implement your own events, we discuss some situations which may or may not be good use cases for events. You will learn to decide if using events is the right solution for your problem.
16. Observer pattern
Notify other parts of the application
when a change occurs
class PostService
{
function newCommentAdded()
{
foreach ($this>
observers as $observer) {
$observer>
notify();
}
}
}
17. Observer contract
Subject knows nothing about its
observers, except their very simple
interface
interface Observer
{
function notify();
}
18. Concrete observers
class LoggingObserver implements Observer
{
function __construct(Logger $logger)
{
$this>
logger = $logger;
}
function notify()
{
$this>
logger>
info('New comment');
}
}
19. Concrete observers
class NotificationMailObserver implements Observer
{
function __construct(Mailer $mailer)
{
$this>
mailer = $mailer;
}
function notify()
{
$this>
mailer>
send('New comment');
}
}
20. Configuration
class PostService
{
function __construct(array $observers)
{
$this>
observers = $observers;
}
}
$postService = new PostService(
array(
new LoggingObserver($logger),
new NotificationMailObserver($mailer)
)
);
25. Single responsibility
● PostService:
“add comments to posts”
● LoggingObserver:
“write a line to the log”
● NotificationMailObserver:
“send a notification mail”
26. Single responsibility
When a change is required, it can be
isolated to just a small part of the
application
27. Single responsibility
● “Capitalize the comment!”:
PostService
● “Use a different logger!”:
LoggerObserver
● “Add a timestamp to the notification mail!”:
NotificationMailObserver
39. Event data
Mr. Boddy was murdered!
● By Mrs. Peacock
● In the dining room
● With a candle stick
40. Currently missing!
class LogNewCommentObserver implements Observer
{
function notify()
{
// we'd like to be more specific
$this>
logger>
info('New comment');
}
}
41. Event object
class CommentAddedEvent
{
public function __construct($postId, $comment)
{
$this>
postId = $postId;
$this>
comment = $comment;
}
function comment()
{
return $this>
comment;
}
function postId()
{
return $this>
postId;
}
}
42. Event object
We use the event object
to store the context of the event
53. In code
class PostService
{
function __construct(EventDispatcherInterface $dispatcher)
{
$this>
dispatcher = $dispatcher;
}
function newCommentAdded($postId, $comment)
{
$event = new CommentAddedEvent($postId, $comment);
$this>
dispatcher>
dispatch(
'comment_added',
$event
);
}
}
54. Event class
Custom event classes should extend
Symfony Event class:
use SymfonyComponentEventDispatcherEvent;
class CommentAddedEvent extends Event
{
...
}
55. Configuration
use SymfonyComponentEventDispatcherEvent;
$dispatcher = new EventDispatcher();
$loggingEventHandler = new LoggingEventHandler($logger);
$dispatcher>
addListener(
'comment_added',
array($loggingEventHandler, 'handle')
);
...
$postService = new PostService($dispatcher);
56. Symfony2 - and Drupal8!
● An event dispatcher is available as the
event_dispatcher service
● You can register event listeners using
service tags
59. Events and application flow
Symfony2 uses events to generate
response for any given HTTP request
60. The HttpKernel
$request = Request::createFromGlobals();
// $kernel is in an instance of HttpKernelInterface
$response = $kernel>
handle($request);
$response>
send();
67. Special types of events
● Kernel events are not merely
notifications
● They allow other parts of the
application to step in and modify or
override behavior
68. Chain of responsibility
Some sort
of request
Handler 1 Handler 2 Handler 3
Some sort
of request
Some sort
of request
Response
69. Symfony example
I've got an exception!
What should I tell the user?
Listener 1 Listener 2 Listener 3
Exception! Exception!
Response
70. Propagation
class HandleExceptionListener
{
function onKernelException(
GetResponseForExceptionEvent $event
) {
$event>
setResponse(new Response('Error!'));
// this is the best response ever, don't let
// other spoil it!
$event>
stopPropagation();
}
}
89. Just like...
● A router determines the right controller
● The service container injects the right
constructor arguments
● And when you die, someone will bury your
body for you