A Series of Fortunate Events - Symfony Camp Sweden 2014
-
Upload
matthiasnoback -
Category
Technology
-
view
1.111 -
download
1
description
Transcript of A Series of Fortunate Events - Symfony Camp Sweden 2014
![Page 1: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/1.jpg)
Twitter: @matthiasnoback
Matthias Noback
A Series of Fortunate Events
![Page 2: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/2.jpg)
What are events, really?
Things that happen
![Page 3: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/3.jpg)
They trigger actions
![Page 4: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/4.jpg)
Just now...Attendees arrived,
triggered me to turn on microphone,
which triggered you to stop talking,
which triggered me to start talking
![Page 5: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/5.jpg)
Events in software Events model what happened in a system
![Page 6: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/6.jpg)
Other parts of the system can respond to what happened
![Page 7: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/7.jpg)
Imperative programmingOnly commands
doThis();
doThat();
updateSomething($something);
return $something;
![Page 8: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/8.jpg)
Extracting eventsdoThis();// this was done
doThat();// that was done
updateSomething($something)// something was updated
return $something;
![Page 9: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/9.jpg)
Starting positionclass PostService{ ... function addComment($postId, $comment) { $post = $this->fetchPost($postId); $post->addComment($comment); $this->save($post);
$this->logger->info('New comment'); $this->mailer->send('New comment'); }}
![Page 10: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/10.jpg)
Starting positionclass PostService { function __construct( Mailer $mailer, Logger $logger ) { $this->mailer = $mailer; $this->logger = $logger; }
function addComment($postId, $comment) { ... }}
![Page 11: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/11.jpg)
Making events explicitclass PostService { function addComment($postId, $comment) { ... $this->newCommentAdded(); }
function newCommentAdded() { $this->logger->info('New comment'); $this->mailer->send('New comment'); }}
![Page 12: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/12.jpg)
Dependency graph
PostServicePostService
Mailer
Logger
![Page 13: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/13.jpg)
Design issues (1)I don't think the PostService should know how to use a Mailer and a Logger
![Page 14: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/14.jpg)
Design issues (2)I want to change the behavior of PostService without modifying the class itself
![Page 15: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/15.jpg)
Fix the problems
By introducing events!(later)
![Page 16: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/16.jpg)
Observer patternNotify other parts of the application when a change occurs
class PostService { function newCommentAdded() { foreach ($this->observers as $observer) { $observer->notify(); } }}
![Page 17: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/17.jpg)
Observer contract
interface Observer{ function notify();}
Subject knows nothing about its observers, except their very simple interface
![Page 18: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/18.jpg)
Concrete observersclass LoggingObserver implements Observer{ function __construct(Logger $logger) { $this->logger = $logger; }
function notify() { $this->logger->info('New comment'); }}
![Page 19: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/19.jpg)
Concrete observers
class NotificationMailObserver implements Observer{ function __construct(Mailer $mailer) { $this->mailer = $mailer; }
function notify() { $this->mailer->send('New comment'); }}
![Page 20: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/20.jpg)
Configurationclass PostService{ function __construct(array $observers) { $this->observers = $observers; }}
$postService = new PostService( array( new LoggingObserver($logger), new NotificationMailObserver($mailer) ));
![Page 21: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/21.jpg)
Before
PostServicePostService
Mailer
Logger
![Page 22: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/22.jpg)
After
NotificationMailObserver
Observer
Observer
LoggingObserver
Mailer
Logger
PostService
![Page 23: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/23.jpg)
Design Principles Party
![Page 24: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/24.jpg)
Single responsibilityEach class has one small,
well-defined responsibility
![Page 25: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/25.jpg)
Single responsibility● PostService:
“add comments to posts”
● LoggingObserver: “write a line to the log”
● NotificationMailObserver: “send a notification mail”
![Page 26: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/26.jpg)
Single responsibilityWhen a change is required, it can be isolated to just a small part of the application
![Page 27: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/27.jpg)
Single responsibility● “Capitalize the comment!”: PostService
● “Use a different logger!”: LoggerObserver
● “Add a timestamp to the notification mail!”: NotificationMailObserver
![Page 28: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/28.jpg)
Dependency inversionDepend on abstractions, not on concretions
![Page 29: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/29.jpg)
Dependency inversionFirst PostService depended on something concrete: the Mailer, the Logger.
![Page 30: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/30.jpg)
Mailer
LoggerPostService
![Page 31: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/31.jpg)
Dependency inversionNow it depends on something abstract: an Observer
![Page 32: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/32.jpg)
Observer
Observer
PostService
![Page 33: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/33.jpg)
Dependency inversionOnly the concrete observers depend on concrete things like Mailer and Logger
![Page 34: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/34.jpg)
NotificationMailObserver
LoggingObserver
Mailer
Logger
![Page 35: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/35.jpg)
Open/closedA class should be open for extension and closed for modification
![Page 36: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/36.jpg)
Open/closedYou don't need to modify the class to change its behavior
![Page 37: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/37.jpg)
Observer
Observer Observer
PostService
![Page 38: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/38.jpg)
Open/closedWe made it closed for modification,
open for extension
![Page 39: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/39.jpg)
Event data
Mr. Boddy was murdered!● By Mrs. Peacock
● In the dining room
● With a candle stick
![Page 40: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/40.jpg)
Currently missing!
class LogNewCommentObserver implements Observer{ function notify() { // we'd like to be more specific $this->logger->info('New comment'); }}
![Page 41: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/41.jpg)
Event objectclass CommentAddedEvent { public function __construct($postId, $comment) { $this->postId = $postId; $this->comment = $comment; }
function comment() { return $this->comment; }
function postId() { return $this->postId; }}
![Page 42: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/42.jpg)
Event object
We use the event object to store the context of the event
![Page 43: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/43.jpg)
From observer...
interface Observer{ function notify();}
![Page 44: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/44.jpg)
… to event handler
interface CommentAddedEventHandler{ function handle(CommentAddedEvent $event);}
![Page 45: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/45.jpg)
Event handlersclass LoggingEventHandler implements CommentAddedEventHandler{ function __construct(Logger $logger) { $this->logger = $logger; }
public function handle(CommentAddedEvent $event) { $this->logger->info( 'New comment' . $event->comment() ); }}
![Page 46: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/46.jpg)
Event handlers
class NotificationMailEventHandler implements CommentAddedEventHandler{ function __construct(Mailer $mailer) { $this->mailer = $mailer; }
public function handle(CommentAddedEvent $event) { $this->mailer->send( 'New comment: ' . $event->comment(); ); }}
![Page 47: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/47.jpg)
Configuration
class PostService{ function __construct(array $eventHandlers) { $this->eventHandlers = $eventHandlers; }}
$postService = new PostService( array( new LoggingEventHandler($logger), new NotificationMailEventHandler($mailer) ));
![Page 48: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/48.jpg)
Looping over event handlersclass PostService{ public function addComment($postId, $comment) { $this->newCommentAdded($postId, $comment); }
function newCommentAdded($postId, $comment) { $event = new CommentAddedEvent( $postId, $comment );
foreach ($this->eventHandlers as $eventHandler) { $eventHandler->handle($event); } }}
![Page 49: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/49.jpg)
Introducing a MediatorInstead of talking to the event handlers
Let's leave the talking to a mediator
![Page 50: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/50.jpg)
Mediators for events● Doctrine, Zend: Event manager
● The PHP League: Event emitter
● Symfony: Event dispatcher
![Page 51: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/51.jpg)
Before
LoggingEventHandler::handle()
NotificationMailEventHandler::handle()
PostService
![Page 52: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/52.jpg)
After
LoggingEventHandler::handle()
NotificationMailEventHandler::handle()
EventDispatcherPostService
![Page 53: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/53.jpg)
In codeclass PostService{ function __construct(EventDispatcherInterface $dispatcher) { $this->dispatcher = $dispatcher; }
function newCommentAdded($postId, $comment) { $event = new CommentAddedEvent($postId, $comment);
$this->dispatcher->dispatch( 'comment_added', $event ); }}
![Page 54: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/54.jpg)
Event class
use Symfony\Component\EventDispatcher\Event;
class CommentAddedEvent extends Event{ ...}
Custom event classes should extend Symfony Event class:
![Page 55: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/55.jpg)
Configurationuse Symfony\Component\EventDispatcher\Event;
$dispatcher = new EventDispatcher();
$loggingEventHandler = new LoggingEventHandler($logger);
$dispatcher->addListener( 'comment_added', array($loggingEventHandler, 'handle'));...
$postService = new PostService($dispatcher);
![Page 56: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/56.jpg)
Symfony2● An event dispatcher is available as the event_dispatcher service
● You can register event listeners using service tags
![Page 57: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/57.jpg)
Inject the event dispatcher# services.yml
services:
post_service:class: PostServicearguments: [@event_dispatcher]
![Page 58: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/58.jpg)
Register your listeners# services.yml
services: ...
logging_event_handler:class: LoggingEventHandlerarguments: [@logger]tags:
- { name: kernel.event_listenerevent: comment_addedmethod: handle
}
![Page 59: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/59.jpg)
Events and application flowSymfony2 uses events to generate response for any given HTTP request
![Page 60: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/60.jpg)
The HttpKernel$request = Request::createFromGlobals();
// $kernel is in an instance of HttpKernelInterface
$response = $kernel->handle($request);
$response->send();
![Page 61: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/61.jpg)
Kernel events
![Page 62: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/62.jpg)
kernel.request● Route matching
● Authentication
![Page 63: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/63.jpg)
kernel.controller
● Replace the controller
● Do some access checks
![Page 64: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/64.jpg)
kernel.view
● Render a template
![Page 65: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/65.jpg)
kernel.response
● Modify the response
● E.g. inject the Symfony toolbar
![Page 66: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/66.jpg)
kernel.exception
● Generate a response
● Render a nice page with the stack trace
![Page 67: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/67.jpg)
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
![Page 68: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/68.jpg)
Chain of responsibility
Handler 3Handler 1 Handler 2
Some sort of request
Some sort of request
Response
Some sort of request
![Page 69: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/69.jpg)
Symfony example
Listener 3Listener 1 Listener 2
Exception! Exception!
Response
I've got an exception! What should I tell the user?
![Page 70: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/70.jpg)
Propagationclass HandleExceptionListener{
function onKernelException(GetResponseForExceptionEvent $event
) {$event->setResponse(new Response('Error!'));
// this is the best response ever, don't let// other spoil it!
$event->stopPropagation();}
}
![Page 71: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/71.jpg)
Priorities$dispatcher = new EventDispatcher();
$dispatcher->addListener( 'comment_added', array($object, $method), // priority 100);
![Page 72: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/72.jpg)
Concerns
![Page 73: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/73.jpg)
Concern 1: Hard to understand“Click-through understanding” impossible
$event = new CommentAddedEvent($postId, $comment);
$this->dispatcher->dispatch('comment_added',$event
);
![Page 74: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/74.jpg)
interface EventDispatcherInterface{ function dispatch($eventName, Event $event = null);
...}
![Page 76: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/76.jpg)
Concern 2: Out-of-domain concepts● “Comment”
● “PostId”
● “Add comment to post”
● “Dispatcher” (?!)
![Page 77: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/77.jpg)
We did a good thing
We fixed coupling issues
![Page 78: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/78.jpg)
She's called Cohesion
But this guy, Coupling, has a sister
![Page 79: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/79.jpg)
Cohesion● Belonging together
● Concepts like “dispatcher”, “event listener”, even “event”, don't belong in your code
![Page 80: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/80.jpg)
Solutions (1)Descriptive, explicit naming:
● NotificationMailEventListener becomes SendNotificationMailWhenCommentAdded
● CommentAddedEvent becomes CommentAdded
● onCommentAdded becomes whenCommentAdded
![Page 81: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/81.jpg)
Solutions (1)
This also hides implementation details!
![Page 82: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/82.jpg)
Solutions (2)Use an event dispatcher for things
that are not naturally cohesive anyway
![Page 83: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/83.jpg)
Solutions (2)Use something else
when an event dispatcher causes low cohesion
![Page 84: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/84.jpg)
Example: resolving the controller
$event = new GetResponseEvent($request);
$dispatcher->dispatch('kernel.request', $event);
$controller = $request->attributes->get('_controller');
$controller = $controllerResolver->resolve($request);
![Page 85: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/85.jpg)
Concern 3: Loss of control● You rely on event listeners to do some really
important work● How do you know if they are in place
and do their job?
![Page 86: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/86.jpg)
Solution● “Won't fix”
● You have to learn to live with it
![Page 87: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/87.jpg)
It's good
![Page 88: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/88.jpg)
Inversion of control
exercise control
give up control!
![Page 89: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/89.jpg)
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
![Page 90: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/90.jpg)
I admit, inversion of control can be scary
![Page 91: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/91.jpg)
But it will● lead to better design
● require less change
● make maintenance easier
![Page 92: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/92.jpg)
PresentationFinishedAskQuestionsWhenPresentationFinished
SayThankYouWhenNoMoreQuestions
![Page 93: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/93.jpg)
Symfony, service definitions, kernel events
http://leanpub.com/a-year-with-symfony/c/symfony-camp
Pay even less ;)
![Page 94: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/94.jpg)
Class and package design principles
http://leanpub.com/principles-of-php-package-design/c/symfony-camp
Get a $10 discount!
![Page 95: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/95.jpg)
Design patterns● Observer
● Mediator
● Chain of responsibility
● ...
Design Patterns by “The Gang of Four”
![Page 96: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/96.jpg)
SOLID principles● Single responsibility
● Open/closed
● Dependency inversion
● ...
Agile Software Development by Robert C. Martin
![Page 97: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/97.jpg)
Images● www.ohiseered.com/2011_11_01_archive.html
● Mrs. Peacock, Candlestick:www.cluecult.com
● Leonardo DiCaprio: screenrant.com/leonardo-dicaprio-defends-wolf-wall-street-controversy/
● Book covers:Amazon
● Party:todesignoffsite.com/events-2/to-do-closing-party-with-love-design/
● Russell Crowe: malinaelena.wordpress.com/2014/04/18/top-8-filme-cu-russell-crowe/
![Page 98: A Series of Fortunate Events - Symfony Camp Sweden 2014](https://reader038.fdocuments.us/reader038/viewer/2022102816/559446a01a28aba37f8b45cd/html5/thumbnails/98.jpg)
Twitter: @matthiasnoback
joind.in/12541
What did you think?