Writing Extensible Code Using Event Dispatcher

D3e3f4ac37c02289f5dfed115949fc88?s=47 John Kary
October 20, 2012

Writing Extensible Code Using Event Dispatcher

Demonstrate refactoring a typical Controller to using Symfony2 EventDispatcher component to make writing decoupled code easier.

D3e3f4ac37c02289f5dfed115949fc88?s=128

John Kary

October 20, 2012
Tweet

Transcript

  1. WRITING EXTENSIBLE CODE USING EVENT DISPATCHER John Kary Kansas City

    PHP User Group, October 2012
  2. ABOUT PHP since 2005 Contract PHP Developer in Lawrence Education

    & Trucking Industry Previously of University of Kansas - IT
  3. EventDispatcher http://bit.ly/sf2-event-dispatcher { "require": { "symfony/event-dispatcher": "dev-master" } } php

    composer.phar update
  4. Overview 1. Procedural PHP 2. Refactor to Object-Oriented PHP 3.

    Extensibility 4. Controllers in Model View Controller 5. EventDispatcher concept 6. Refactor to using an EventDispatcher 7. EventDispatcher caveats
  5. Maybe you know about... JavaScript Events Basics of Object-Oriented Programming

    Inheritance Polymorphism Encapsulation Abstraction Delegation Dependency Injection Single Responsibility Principle Separation of Concerns MVC
  6. None
  7. DemCrookidWigitz.com

  8. John, Customers are unhappy. Send them a “Welcome!” email after

    they register on the web site. Tell them we are glad to have them as a customer. That’ll teach ‘em. Do it now. The Boss The Boss
  9. 0Before We Begin

  10. 0Before We Begin UTION CAUTION CAUTION CAUTIO

  11. The Code In This Presentation Is Not Production-Ready

  12. 1Procedural PHP

  13. Procedural PHP $_POST = array( 'name' => 'John Kary', 'email'

    => 'john@johnkary.net', ); $to = $_POST['email']; $subject = 'New Account'; $message = "Welcome " . $_POST['name'] . "! Your new space has been created! Use this link to login: https://activate.demcrookidwidgitz.com/code/Sq9284tWBnWgpjw Thanks! DemCrookidWigitz"; $headers = array(); $headers[] = 'From: accounts@demcrookidwigitz.com'; $headers[] = 'Reply-To: contact@demcrookidwigitz.com'; $headers[] = 'X-Mailer: PHP/' . phpversion(); mail($to, $subject, $message, implode($headers, "\r\n"));
  14. 2 Object-Oriented PHP

  15. Object-Oriented PHP $_POST = array( 'name' => 'John Kary', 'email'

    => 'john@johnkary.net', ); $to = $_POST['email']; $subject = 'New Account'; $message = "Welcome " . $_POST['name'] . "! Your new space has been created! Use this link to login: https://activate.demcrookidwidgitz.com/code/Sq9284tWBnWgpjw Thanks! DemCrookidWigitz"; $headers = array(); $headers[] = 'From: accounts@demcrookidwigitz.com'; $headers[] = 'Reply-To: contact@demcrookidwigitz.com'; $headers[] = 'X-Mailer: PHP/' . phpversion(); mail($to, $subject, $message, implode($headers, "\r\n")); Customer
  16. Object-Oriented PHP class Customer { public function __construct(array $data) {

    $this->name = $data['name']; $this->email = $data['email']; } public function getName() { return $this->name; } public function getEmail() { return $this->email; } }
  17. Object-Oriented PHP $_POST = array( 'name' => 'John Kary', 'email'

    => 'john@johnkary.net', ); $to = $_POST['email']; $subject = 'New Account'; $message = "Welcome " . $_POST['name'] . "! Your new space has been created! Use this link to login: https://activate.demcrookidwidgitz.com/code/Sq9284tWBnWgpjw Thanks! DemCrookidWigitz"; $headers = array(); $headers[] = 'From: accounts@demcrookidwigitz.com'; $headers[] = 'Reply-To: contact@demcrookidwigitz.com'; $headers[] = 'X-Mailer: PHP/' . phpversion(); mail($to, $subject, $message, implode($headers, "\r\n")); Customer WelcomeEmail
  18. class WelcomeEmail { public function send($to, $name) { return mail($to,

    $this->getSubject(), $this->getMessage($name), $this->getHeaders()); } protected function getSubject() { return 'New Account'; } protected function getMessage($name) { return "Welcome " . $name . "! Your new space has been created! Use this link to login: https://activate.demcrookidwigitz.com/code/Sq9284tWBnWgpjw Thanks! DemCrookidWigitz"; } protected function getHeaders() { $headers = array(); $headers[] = 'From: accounts@demcrookidwigitz.com'; $headers[] = 'Reply-To: help@demcrookidwigitz.com'; $headers[] = 'X-Mailer: PHP/' . phpversion(); return implode($headers, "\r\n"); } }
  19. Object-Oriented PHP $_POST = array( 'name' => 'John Kary', 'email'

    => 'john@johnkary.net', ); $to = $_POST['email']; $subject = 'New Account'; $message = "Welcome " . $_POST['name'] . "! Your new space has been created! Use this link to login: https://activate.demcrookidwidgitz.com/code/Sq9284tWBnWgpjw Thanks! DemCrookidWigitz"; $headers = array(); $headers[] = 'From: accounts@demcrookidwigitz.com'; $headers[] = 'Reply-To: contact@demcrookidwigitz.com'; $headers[] = 'X-Mailer: PHP/' . phpversion(); mail($to, $subject, $message, implode($headers, "\r\n")); Customer WelcomeEmail Controller
  20. class Controller { // POST http://demcrookidwigitz.com/person public function newCustomer() {

    $customer = new Customer($_POST); $email = new WelcomeEmail(); $email->send($customer->getEmail(), $customer->getName()); } } Object-Oriented PHP
  21. John, Advertising wants to know how many new customers we’re

    getting. Setup some logging. I don’t want their grubby hands on the database. That’ll teach ‘em. Do it now. The Boss The Boss
  22. 3Disk Logging

  23. Disk Logging class Controller { public function newCustomer() { $customer

    = new Customer($_POST); $email = new WelcomeEmail(); $email->send($customer->getEmail()); $dLog = new DiskLogger('/logs/prod.log'); $msg = 'Sent welcome email to '.$customer->getName(). ' at '.$customer->getEmail(); $dLog->log($msg); } }
  24. None
  25. John, Marketing wants to run statistics on orders. Keep them

    away from the database too. Just add to that other log file we setup for Advertising. That’ll teach ‘em. Do it now. The Boss The Boss
  26. 4More Disk Logging

  27. More Disk Logging class Controller { public function newCustomer() {

    // ... $dLog = new DiskLogger('/logs/prod.log'); $msg = 'Sent welcome email to '.$customer->getName(). ' at '.$customer->getEmail(); $dLog->log($msg); } public function createOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Created order ' . $number); } public function cancelOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Cancelled order number ' . $number); } }
  28. None
  29. 5Moar Logging!

  30. class Controller { public function newCustomer() { // ... $dLog

    = new DiskLogger('/logs/prod.log'); $msg = 'Sent welcome email to '.$customer->getName(). ' at '.$customer->getEmail(); $dLog->log($msg); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' has registered!'); } public function createOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Created order ' . $number); } public function cancelOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Cancelled order number ' . $number); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' cancelled their order...'); } }
  31. class Controller { public function newCustomer() { // ... $dLog

    = new DiskLogger('/logs/prod.log'); $msg = 'Sent welcome email to '.$customer->getName(). ' at '.$customer->getEmail(); $dLog->log($msg); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' has registered!'); } public function createOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Created order ' . $number); $twitter = new Twitter('demcrookidwigitz', 'b3@tb0Xpr0$'); $twitter->tweet($customer->getName().' just ordered from us!'); } public function cancelOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Cancelled order number ' . $number); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' cancelled their order...');
  32. Your Codebase Is Growing

  33. ?

  34. class Controller { public function newCustomer() { $customer = new

    Customer($_POST); $email = new WelcomeEmail(); $email->send($customer->getEmail()); $dLog = new DiskLogger('/logs/prod.log'); $msg = 'Sent welcome email to '.$customer->getName(); $dLog->log($msg); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' has registered!'); } public function createOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Created order ' . $number); $twitter = new Twitter('demcrookidwigitz', 'b3@tb0Xpr0$'); $twitter->tweet($customer->getName() . ' just ordered from us!'); } public function cancelOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Cancelled order number ' . $number); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' cancelled their order...'); } }
  35. class Controller { public function newCustomer() { $customer = new

    Customer($_POST); $email = new WelcomeEmail(); $email->send($customer->getEmail()); $dLog = new DiskLogger('/logs/prod.log'); $msg = 'Sent welcome email to '.$customer->getName(); $dLog->log($msg); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' has registered!'); } public function createOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Created order ' . $number); $twitter = new Twitter('demcrookidwigitz', 'b3@tb0Xpr0$'); $twitter->tweet($customer->getName() . ' just ordered from us!'); } public function cancelOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Cancelled order number ' . $number); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' cancelled their order...'); } }
  36. class Controller { public function newCustomer() { $customer = new

    Customer($_POST); $email = new WelcomeEmail(); $email->send($customer->getEmail()); $dLog = new DiskLogger('/logs/prod.log'); $msg = 'Sent welcome email to '.$customer->getName(); $dLog->log($msg); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' has registered!'); } public function createOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Created order ' . $number); $twitter = new Twitter('demcrookidwigitz', 'b3@tb0Xpr0$'); $twitter->tweet($customer->getName() . ' just ordered from us!'); } public function cancelOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Cancelled order number ' . $number); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' cancelled their order...'); } }
  37. class Controller { public function newCustomer() { $customer = new

    Customer($_POST); $email = new WelcomeEmail(); $email->send($customer->getEmail()); $dLog = new DiskLogger('/logs/prod.log'); $msg = 'Sent welcome email to '.$customer->getName(); $dLog->log($msg); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' has registered!'); } public function createOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Created order ' . $number); $twitter = new Twitter('demcrookidwigitz', 'b3@tb0Xpr0$'); $twitter->tweet($customer->getName() . ' just ordered from us!'); } public function cancelOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Cancelled order number ' . $number); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' cancelled their order...'); } }
  38. Extensibility [A] system design principle where the implementation takes into

    consideration future growth. Extensibility - Wikipedia http://en.wikipedia.org/wiki/Extensibility
  39. class Controller { public function newCustomer() { $customer = new

    Customer($_POST); $email = new WelcomeEmail(); $email->send($customer->getEmail()); $dLog = new DiskLogger('/logs/prod.log'); $msg = 'Sent welcome email to '.$customer->getName(); $dLog->log($msg); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' has registered!'); } public function createOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Created order ' . $number); $twitter = new Twitter('demcrookidwigitz', 'b3@tb0Xpr0$'); $twitter->tweet($customer->getName() . ' just ordered from us!'); } public function cancelOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Cancelled order number ' . $number); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' cancelled their order...'); } }
  40. class Controller { public function newCustomer() { $customer = new

    Customer($_POST); $email = new WelcomeEmail(); $email->send($customer->getEmail()); $dLog = new DiskLogger('/logs/prod.log'); $msg = 'Sent welcome email to '.$customer->getName(); $dLog->log($msg); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' has registered!'); } public function createOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Created order ' . $number); $twitter = new Twitter('demcrookidwigitz', 'b3@tb0Xpr0$'); $twitter->tweet($customer->getName() . ' just ordered from us!'); } public function cancelOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Cancelled order number ' . $number); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' cancelled their order...'); } } NOT EXTENSIBLE!
  41. Model View Controller

  42. What is the Responsibility of a Controller?

  43. Controllers should contain LOGIC

  44. Controllers should contain LOGIC

  45. Controllers should contain LOGIC

  46. Controllers as Glue Custom Application Code Framework Controller

  47. Controllers as Glue Custom Application Code Controller

  48. Controllers as Glue Custom Application Code Controller

  49. Event Dispatcher

  50. Event Dispatcher - Concept Request Response kernel.controller kernel.request kernel.response kernel.view

  51. Event Dispatcher - Concept Request Response Your Events kernel.controller kernel.request

    kernel.response kernel.view
  52. Event Dispatcher - Concept Request Response kernel.controller kernel.request kernel.response kernel.view

    user.login
  53. Event Dispatcher - Concept Request Response kernel.controller kernel.request kernel.response kernel.view

    user.login user.register
  54. Event Dispatcher - Concept Request Response kernel.controller kernel.request kernel.response kernel.view

    user.login user.register $user
  55. Event Dispatcher - Concept Request Response kernel.controller kernel.request kernel.response kernel.view

    user.login user.register $user $user
  56. Event Dispatcher - Register Listeners EventDispatcher AListener named.eventA BListener named.eventB

    CListener named.eventC
  57. Let’s use a more concrete example

  58. Event Dispatcher - Register Listeners CartListener:: onAddToCart() EventDispatcher cart.add CustomerListener::

    onRegister() customer.register CartListener:: grantDiscount() cart.checkout
  59. Event Dispatcher - Register Listeners use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new

    EventDispatcher(); $listener = new CustomerListener(); $dispatcher->addListener('customer.register', array($listener, 'onRegister')); // Register more listeners class CustomerListener { public function onRegister(CustomerEvent $event) { // Do some work } } Any PHP Callable true === is_callable()
  60. Event Dispatcher - Register Listeners use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new

    EventDispatcher(); $dispatcher->addListener('customer.register', array('CustomerListener', 'onRegister')); // Register more listeners class CustomerListener { public static function onRegister(CustomerEvent $event) { // Do some work } }
  61. Event Dispatcher - Register Listeners use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new

    EventDispatcher(); $dispatcher->addListener('customer.register', function(CustomerEvent $event) { // Do some work });
  62. Event Dispatcher - Dispatch an Event

  63. Request Response Event Dispatcher - Dispatch an Event

  64. Request Response Event Dispatcher - Dispatch an Event EventDispatcher “customer.register”

    CustomerListener:: onRegister() “cart.add” CartListener:: onAddToCart() “cart.checkout” CartListener:: grantDiscount()
  65. Request Response CustomerEvent “customer.register” Customer Event Dispatcher - Dispatch an

    Event EventDispatcher “customer.register” CustomerListener:: onRegister() “cart.add” CartListener:: onAddToCart() “cart.checkout” CartListener:: grantDiscount()
  66. Request Response CustomerEvent “customer.register” Customer Event Dispatcher - Dispatch an

    Event EventDispatcher “customer.register” CustomerListener:: onRegister() “cart.add” CartListener:: onAddToCart() “cart.checkout” CartListener:: grantDiscount()
  67. Event Dispatcher - Dispatch an Event use Symfony\Component\EventDispatcher\EventDispatcher; class CustomerController

    { public function __construct(EventDispatcher $dispatcher) { $this->dispatcher = $dispatcher; } public function newCustomer() { $customer = new Customer(array( 'first_name' => 'Bob', 'last_name' => 'Smith', 'email' => 'bobsmith@gmail.com', )); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.register', $event); } } Customer Event Event Name
  68. Request Response CustomerEvent “customer.register” Customer Event Dispatcher - Dispatch an

    Event EventDispatcher “customer.register” CustomerListener:: onRegister() “cart.add” CartListener:: onAddToCart() “cart.checkout” CartListener:: grantDiscount()
  69. Request Response CustomerEvent “customer.register” Customer Event Dispatcher - Dispatch an

    Event EventDispatcher “customer.register” CustomerListener:: onRegister() “cart.add” CartListener:: onAddToCart() “cart.checkout” CartListener:: grantDiscount() $this->dispatcher->dispatch('customer.register', $event);
  70. Request Response CustomerEvent “customer.register” Customer Event Dispatcher - Dispatch an

    Event EventDispatcher “customer.register” CustomerListener:: onRegister() “cart.add” CartListener:: onAddToCart() “cart.checkout” CartListener:: grantDiscount()
  71. Request Response CustomerEvent “customer.register” Customer Event Dispatcher - Dispatch an

    Event EventDispatcher “customer.register” CustomerListener:: onRegister() “cart.add” CartListener:: onAddToCart() “cart.checkout” CartListener:: grantDiscount() “customer.register” CustomerListener:: onRegister()
  72. Event Dispatcher - Handle the Event class CustomerListener { public

    function onRegister(CustomerEvent $event) { $customer = $event->getCustomer(); $name = $event->getName(); $dispatcher = $event->getDispatcher(); // Do something with Customer object } } CustomerEvent “customer.register” Customer
  73. Event Dispatcher - Handle the Event class CustomerListener { public

    function onRegister(CustomerEvent $event) { $customer = $event->getCustomer(); $name = $event->getName(); $dispatcher = $event->getDispatcher(); // Do something with Customer object } }
  74. Event Dispatcher - Handle the Event use Symfony\Component\EventDispatcher\Event; class CustomerEvent

    extends Event { protected $customer; public function __construct(Customer $customer) { $this->customer = $customer; } public function getCustomer() { return $this->customer; } }
  75. Event Dispatcher - All together now!

  76. Event Dispatcher - All together now! EventDispatcher

  77. Event Dispatcher - All together now! CartListener:: onAddToCart() CustomerListener:: onRegister()

    CartListener:: grantDiscount() EventDispatcher cart.checkout cart.add customer.register
  78. Event Dispatcher - All together now! CartListener:: onAddToCart() CustomerListener:: onRegister()

    CartListener:: grantDiscount() EventDispatcher “cart.checkout” CartListener:: grantDiscount() “cart.add” CartListener:: onAddToCart() “customer.register” CustomerListener:: onRegister()
  79. CustomerEvent “customer.register” Customer Event Dispatcher - All together now! CartListener::

    onAddToCart() CustomerListener:: onRegister() CartListener:: grantDiscount() EventDispatcher “cart.checkout” CartListener:: grantDiscount() “cart.add” CartListener:: onAddToCart() “customer.register” CustomerListener:: onRegister()
  80. CustomerEvent “customer.register” Customer Event Dispatcher - All together now! CartListener::

    onAddToCart() CustomerListener:: onRegister() CartListener:: grantDiscount() EventDispatcher “cart.checkout” CartListener:: grantDiscount() “cart.add” CartListener:: onAddToCart() “customer.register” CustomerListener:: onRegister() $this->dispatcher->dispatch('customer.register', $event);
  81. CustomerEvent “customer.register” Customer Event Dispatcher - All together now! CartListener::

    onAddToCart() CustomerListener:: onRegister() CartListener:: grantDiscount() EventDispatcher “cart.checkout” CartListener:: grantDiscount() “cart.add” CartListener:: onAddToCart() “customer.register” CustomerListener:: onRegister()
  82. CustomerEvent “customer.register” Customer Event Dispatcher - All together now! CartListener::

    onAddToCart() CustomerListener:: onRegister() CartListener:: grantDiscount() EventDispatcher “cart.checkout” CartListener:: grantDiscount() “cart.add” CartListener:: onAddToCart() “customer.register” CustomerListener:: onRegister() “customer.register” CustomerListener:: onRegister()
  83. CustomerEvent “customer.register” Customer Event Dispatcher - All together now! CartListener::

    onAddToCart() CustomerListener:: onRegister() CartListener:: grantDiscount() EventDispatcher “cart.checkout” CartListener:: grantDiscount() “cart.add” CartListener:: onAddToCart() “customer.register” CustomerListener:: onRegister() “customer.register” CustomerListener:: onRegister() That’s Event Dispatcher!
  84. Let’s refactor our Controller

  85. class Controller { public function newCustomer() { $customer = new

    Customer($_POST); $email = new WelcomeEmail(); $email->send($customer->getEmail()); $dLog = new DiskLogger('/logs/prod.log'); $msg = 'Sent welcome email to '.$customer->getName(); $dLog->log($msg); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' has registered!'); } public function createOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Created order ' . $number); $twitter = new Twitter('demcrookidwigitz', 'b3@tb0Xpr0$'); $twitter->tweet($customer->getName() . ' just ordered from us!'); } public function cancelOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Cancelled order number ' . $number); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' cancelled their order...'); } } START
  86. class Controller { public function __construct(EventDispatcher $dispatcher) { $this->dispatcher =

    $dispatcher; } public function newCustomer() { $customer = new Customer($_POST); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.register', $event); } public function createOrder() { // ... $event = new OrderEvent($order); $this->dispatcher->dispatch('order.new', $event); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.order.new', $event); } public function cancelOrder() { // ... $event = new OrderEvent($order); $this->dispatcher->dispatch('order.cancel', $event); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.order.cancel', $event); } } FINISH
  87. 6 Inject the EventDispatcher

  88. class Controller { public function __construct(EventDispatcher $dispatcher) { $this->dispatcher =

    $dispatcher; } public function newCustomer() { $customer = new Customer($_POST); $email = new WelcomeEmail(); $email->send($customer->getEmail()); $dLog = new DiskLogger('/logs/prod.log'); $msg = 'Sent welcome email to '.$customer->getName(); $dLog->log($msg); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' has registered!'); } public function createOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Created order ' . $number); $twitter = new Twitter('demcrookidwigitz', 'b3@tb0Xpr0$'); $twitter->tweet($customer->getName() . ' just ordered from us!'); } public function cancelOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Cancelled order number ' . $number); $eLog = new EmailLogger('boss@demcrookidwigitz.com');
  89. 7Our First Event

  90. class Controller { public function __construct(EventDispatcher $dispatcher) { $this->dispatcher =

    $dispatcher; } public function newCustomer() { $customer = new Customer($_POST); $email = new WelcomeEmail(); $email->send($customer->getEmail()); $dLog = new DiskLogger('/logs/prod.log'); $msg = 'Sent welcome email to '.$customer->getName(); $dLog->log($msg); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' has registered!'); } public function createOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Created order ' . $number); $twitter = new Twitter('demcrookidwigitz', 'b3@tb0Xpr0$'); $twitter->tweet($customer->getName() . ' just ordered from us!'); } public function cancelOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Cancelled order number ' . $number); $eLog = new EmailLogger('boss@demcrookidwigitz.com');
  91. class Controller { public function __construct(EventDispatcher $dispatcher) { $this->dispatcher =

    $dispatcher; } public function newCustomer() { $customer = new Customer($_POST); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.register', $event); $dLog = new DiskLogger('/logs/prod.log'); $msg = 'Sent welcome email to '.$customer->getName(); $dLog->log($msg); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' has registered!'); } public function createOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Created order ' . $number); $twitter = new Twitter('demcrookidwigitz', 'b3@tb0Xpr0$'); $twitter->tweet($customer->getName() . ' just ordered from us!'); } public function cancelOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Cancelled order number ' . $number); $eLog = new EmailLogger('boss@demcrookidwigitz.com');
  92. use Symfony\Component\EventDispatcher\Event; class CustomerEvent extends Event { protected $customer; public

    function __construct(Customer $customer) { $this->customer = $customer; } public function getCustomer() { return $this->customer; } }
  93. use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); // Wire listeners $listener

    = new CustomerEmailListener(new WelcomeEmail()); $dispatcher->addListener('customer.register', array($listener, 'onRegister')); class WelcomeEmail { public function send($to, $name) { return mail($to, $this->getSubject(), $this->getMessage($name), $this->getHeaders()); } protected function getSubject() { return 'New Account'; } protected function getMessage($name) { return "Welcome " . $name . "! Your new space has been created! Use this link to login: https://activate.demcrookidwigitz.com/code/Sq9284tWBnWgpjw Thanks! DemCrookidWigitz"; } protected function getHeaders() { $headers = array(); $headers[] = 'From: accounts@demcrookidwigitz.com';
  94. use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); // Wire listeners $listener

    = new CustomerEmailListener(new WelcomeEmail()); $dispatcher->addListener('customer.register', array($listener, 'onRegister'));
  95. use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); // Wire listeners $listener

    = new CustomerEmailListener(new WelcomeEmail()); $dispatcher->addListener('customer.register', array($listener, 'onRegister'));
  96. use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); // Wire listeners $listener

    = new CustomerEmailListener(new WelcomeEmail()); $dispatcher->addListener('customer.register', array($listener, 'onRegister')); class CustomerEmailListener { public function __construct(WelcomeEmail $email) { $this->email = $email; } public function onRegister(CustomerEvent $event) { $customer = $event->getCustomer(); $this->email->send($customer->getEmail(), $customer->getName()); } }
  97. use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); // Wire listeners $listener

    = new CustomerEmailListener(new WelcomeEmail()); $dispatcher->addListener('customer.register', array($listener, 'onRegister')); class CustomerEmailListener { public function __construct(WelcomeEmail $email) { $this->email = $email; } public function onRegister(CustomerEvent $event) { $customer = $event->getCustomer(); $this->email->send($customer->getEmail(), $customer->getName()); } }
  98. use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); // Wire listeners $listener

    = new CustomerEmailListener(new WelcomeEmail()); $dispatcher->addListener('customer.register', array($listener, 'onRegister')); class CustomerEmailListener { public function __construct(WelcomeEmail $email) { $this->email = $email; } public function onRegister(CustomerEvent $event) { $customer = $event->getCustomer(); $this->email->send($customer->getEmail(), $customer->getName()); } } class WelcomeEmail { public function send($to, $name) { return mail($to, $this->getSubject(), $this->getMessage($name), $this->getHeaders()); } }
  99. use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); // Wire listeners $listener

    = new CustomerEmailListener(new WelcomeEmail()); $dispatcher->addListener('customer.register', array($listener, 'onRegister')); class CustomerEmailListener { public function __construct(WelcomeEmail $email) { $this->email = $email; } public function onRegister(CustomerEvent $event) { $customer = $event->getCustomer(); $this->email->send($customer->getEmail(), $customer->getName()); } } class WelcomeEmail { public function send($to, $name) { return mail($to, $this->getSubject(), $this->getMessage($name), $this->getHeaders()); } }
  100. 8 Move more code to listeners

  101. class Controller { public function __construct(EventDispatcher $dispatcher) { $this->dispatcher =

    $dispatcher; } public function newCustomer() { $customer = new Customer($_POST); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.register', $event); $dLog = new DiskLogger('/logs/prod.log'); $msg = 'Sent welcome email to '.$customer->getName(); $dLog->log($msg); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' has registered!'); } public function createOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Created order ' . $number); $twitter = new Twitter('demcrookidwigitz', 'b3@tb0Xpr0$'); $twitter->tweet($customer->getName() . ' just ordered from us!'); } public function cancelOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Cancelled order number ' . $number); $eLog = new EmailLogger('boss@demcrookidwigitz.com');
  102. use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $diskLogger = new DiskLogger('/logs/prod.log');

    // Wire listeners $listener = new CustomerEmailListener(new WelcomeEmail(), $diskLogger); $dispatcher->addListener('customer.register', array($listener, 'onRegister'));
  103. use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $diskLogger = new DiskLogger('/logs/prod.log');

    // Wire listeners $listener = new CustomerEmailListener(new WelcomeEmail(), $diskLogger); $dispatcher->addListener('customer.register', array($listener, 'onRegister'));
  104. use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $diskLogger = new DiskLogger('/logs/prod.log');

    // Wire listeners $listener = new CustomerEmailListener(new WelcomeEmail(), $diskLogger); $dispatcher->addListener('customer.register', array($listener, 'onRegister')); class CustomerEmailListener { public function __construct(WelcomeEmail $email) { $this->email = $email; } public function onRegister(CustomerEvent $event) { $customer = $event->getCustomer(); $this->email->send($customer->getEmail(), $customer->getName()); } }
  105. use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $diskLogger = new DiskLogger('/logs/prod.log');

    // Wire listeners $listener = new CustomerEmailListener(new WelcomeEmail(), $diskLogger); $dispatcher->addListener('customer.register', array($listener, 'onRegister')); class CustomerEmailListener { public function __construct(WelcomeEmail $email) { $this->email = $email; } public function onRegister(CustomerEvent $event) { $customer = $event->getCustomer(); $this->email->send($customer->getEmail(), $customer->getName()); } } class CustomerEmailListener { public function __construct(WelcomeEmail $email, DiskLogger $logger) { $this->email = $email; $this->logger = $logger; } public function onRegister(CustomerEvent $event) { $customer = $event->getCustomer(); $this->email->send($customer->getEmail(), $customer->getName()); } }
  106. use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $diskLogger = new DiskLogger('/logs/prod.log');

    // Wire listeners $listener = new CustomerEmailListener(new WelcomeEmail(), $diskLogger); $dispatcher->addListener('customer.register', array($listener, 'onRegister')); class CustomerEmailListener { public function __construct(WelcomeEmail $email) { $this->email = $email; } public function onRegister(CustomerEvent $event) { $customer = $event->getCustomer(); $this->email->send($customer->getEmail(), $customer->getName()); } } class CustomerEmailListener { public function __construct(WelcomeEmail $email, DiskLogger $logger) { $this->email = $email; $this->logger = $logger; } public function onRegister(CustomerEvent $event) { $customer = $event->getCustomer(); $this->email->send($customer->getEmail(), $customer->getName()); } }
  107. use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $diskLogger = new DiskLogger('/logs/prod.log');

    // Wire listeners $listener = new CustomerEmailListener(new WelcomeEmail(), $diskLogger); $dispatcher->addListener('customer.register', array($listener, 'onRegister')); class CustomerEmailListener { public function __construct(WelcomeEmail $email) { $this->email = $email; } public function onRegister(CustomerEvent $event) { $customer = $event->getCustomer(); $this->email->send($customer->getEmail(), $customer->getName()); } } class CustomerEmailListener { public function __construct(WelcomeEmail $email, DiskLogger $logger) { $this->email = $email; $this->logger = $logger; } public function onRegister(CustomerEvent $event) { $customer = $event->getCustomer(); $this->email->send($customer->getEmail(), $customer->getName()); } } class CustomerEmailListener { public function __construct(WelcomeEmail $email, DiskLogger $logger) { $this->email = $email; $this->logger = $logger; } public function onRegister(CustomerEvent $event) { $customer = $event->getCustomer(); $this->email->send($customer->getEmail(), $customer->getName()); $this->logger->log('Sent welcome email to ' . $customer->getName()); } }
  108. use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $diskLogger = new DiskLogger('/logs/prod.log');

    // Wire listeners $listener = new CustomerEmailListener(new WelcomeEmail(), $diskLogger); $dispatcher->addListener('customer.register', array($listener, 'onRegister')); class CustomerEmailListener { public function __construct(WelcomeEmail $email) { $this->email = $email; } public function onRegister(CustomerEvent $event) { $customer = $event->getCustomer(); $this->email->send($customer->getEmail(), $customer->getName()); } } class CustomerEmailListener { public function __construct(WelcomeEmail $email, DiskLogger $logger) { $this->email = $email; $this->logger = $logger; } public function onRegister(CustomerEvent $event) { $customer = $event->getCustomer(); $this->email->send($customer->getEmail(), $customer->getName()); } } class CustomerEmailListener { public function __construct(WelcomeEmail $email, DiskLogger $logger) { $this->email = $email; $this->logger = $logger; } public function onRegister(CustomerEvent $event) { $customer = $event->getCustomer(); $this->email->send($customer->getEmail(), $customer->getName()); $this->logger->log('Sent welcome email to ' . $customer->getName()); } }
  109. class Controller { public function __construct(EventDispatcher $dispatcher) { $this->dispatcher =

    $dispatcher; } public function newCustomer() { $customer = new Customer($_POST); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.register', $event); $dLog = new DiskLogger('/logs/prod.log'); $msg = 'Sent welcome email to '.$customer->getName(); $dLog->log($msg); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' has registered!'); } public function createOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Created order ' . $number); $twitter = new Twitter('demcrookidwigitz', 'b3@tb0Xpr0$'); $twitter->tweet($customer->getName() . ' just ordered from us!'); } public function cancelOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Cancelled order number ' . $number); $eLog = new EmailLogger('boss@demcrookidwigitz.com');
  110. class Controller { public function __construct(EventDispatcher $dispatcher) { $this->dispatcher =

    $dispatcher; } public function newCustomer() { $customer = new Customer($_POST); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.register', $event); $dLog = new DiskLogger('/logs/prod.log'); $msg = 'Sent welcome email to '.$customer->getName(); $dLog->log($msg); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' has registered!'); } public function createOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Created order ' . $number); $twitter = new Twitter('demcrookidwigitz', 'b3@tb0Xpr0$'); $twitter->tweet($customer->getName() . ' just ordered from us!'); } public function cancelOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Cancelled order number ' . $number); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); class Controller { public function __construct(EventDispatcher $dispatcher) { $this->dispatcher = $dispatcher; } public function newCustomer() { $customer = new Customer($_POST); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.register', $event); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' has registered!'); } public function createOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Created order ' . $number); $twitter = new Twitter('demcrookidwigitz', 'b3@tb0Xpr0$'); $twitter->tweet($customer->getName() . ' just ordered from us!'); } public function cancelOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Cancelled order number ' . $number); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' cancelled their order...'); } }
  111. class Controller { public function __construct(EventDispatcher $dispatcher) { $this->dispatcher =

    $dispatcher; } public function newCustomer() { $customer = new Customer($_POST); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.register', $event); $dLog = new DiskLogger('/logs/prod.log'); $msg = 'Sent welcome email to '.$customer->getName(); $dLog->log($msg); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' has registered!'); } public function createOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Created order ' . $number); $twitter = new Twitter('demcrookidwigitz', 'b3@tb0Xpr0$'); $twitter->tweet($customer->getName() . ' just ordered from us!'); } public function cancelOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Cancelled order number ' . $number); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); class Controller { public function __construct(EventDispatcher $dispatcher) { $this->dispatcher = $dispatcher; } public function newCustomer() { $customer = new Customer($_POST); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.register', $event); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' has registered!'); } public function createOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Created order ' . $number); $twitter = new Twitter('demcrookidwigitz', 'b3@tb0Xpr0$'); $twitter->tweet($customer->getName() . ' just ordered from us!'); } public function cancelOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Cancelled order number ' . $number); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' cancelled their order...'); } }
  112. use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $bossEmail = 'boss@demcrookidwigitz.com'; //

    Wire listeners // ... $listener = new BossNewCustomerEmailListener(new BossNewCustomerEmail($bossEmail)); $dispatcher->addListener('customer.register', array($listener, 'onCustomerRegister'));
  113. use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $bossEmail = 'boss@demcrookidwigitz.com'; //

    Wire listeners // ... $listener = new BossNewCustomerEmailListener(new BossNewCustomerEmail($bossEmail)); $dispatcher->addListener('customer.register', array($listener, 'onCustomerRegister'));
  114. use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $bossEmail = 'boss@demcrookidwigitz.com'; //

    Wire listeners // ... $listener = new BossNewCustomerEmailListener(new BossNewCustomerEmail($bossEmail)); $dispatcher->addListener('customer.register', array($listener, 'onCustomerRegister'));
  115. use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $bossEmail = 'boss@demcrookidwigitz.com'; //

    Wire listeners // ... $listener = new BossNewCustomerEmailListener(new BossNewCustomerEmail($bossEmail)); $dispatcher->addListener('customer.register', array($listener, 'onCustomerRegister')); class BossNewCustomerEmail { public function __construct($bossEmail) { $this->bossEmail = $bossEmail; } public function send($name) { return mail($this->bossEmail, $this->getSubject(), $this->getMessage($name), $this->getHeaders()); } protected function getSubject() { return 'New Customer Registered!'; } protected function getMessage($name) { return "Boss! " . $name . " just registered! Sweet, huh?"; } // ... }
  116. use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $bossEmail = 'boss@demcrookidwigitz.com'; //

    Wire listeners // ... $listener = new BossNewCustomerEmailListener(new BossNewCustomerEmail($bossEmail)); $dispatcher->addListener('customer.register', array($listener, 'onCustomerRegister'));
  117. use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $bossEmail = 'boss@demcrookidwigitz.com'; //

    Wire listeners // ... $listener = new BossNewCustomerEmailListener(new BossNewCustomerEmail($bossEmail)); $dispatcher->addListener('customer.register', array($listener, 'onCustomerRegister')); class BossNewCustomerEmailListener { public function __construct(BossNewCustomerEmail $email) { $this->email = $email; } public function onCustomerRegister(CustomerEvent $event) { $customer = $event->getCustomer(); $this->email->send($customer->getName()); } }
  118. use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $bossEmail = 'boss@demcrookidwigitz.com'; //

    Wire listeners // ... $listener = new BossNewCustomerEmailListener(new BossNewCustomerEmail($bossEmail)); $dispatcher->addListener('customer.register', array($listener, 'onCustomerRegister')); class BossNewCustomerEmailListener { public function __construct(BossNewCustomerEmail $email) { $this->email = $email; } public function onCustomerRegister(CustomerEvent $event) { $customer = $event->getCustomer(); $this->email->send($customer->getName()); } }
  119. class Controller { public function __construct(EventDispatcher $dispatcher) { $this->dispatcher =

    $dispatcher; } public function newCustomer() { $customer = new Customer($_POST); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.register', $event); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' has registered!'); } public function createOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Created order ' . $number); $twitter = new Twitter('demcrookidwigitz', 'b3@tb0Xpr0$'); $twitter->tweet($customer->getName() . ' just ordered from us!'); } public function cancelOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Cancelled order number ' . $number); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' cancelled their order...'); } }
  120. class Controller { public function __construct(EventDispatcher $dispatcher) { $this->dispatcher =

    $dispatcher; } public function newCustomer() { $customer = new Customer($_POST); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.register', $event); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' has registered!'); } public function createOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Created order ' . $number); $twitter = new Twitter('demcrookidwigitz', 'b3@tb0Xpr0$'); $twitter->tweet($customer->getName() . ' just ordered from us!'); } public function cancelOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Cancelled order number ' . $number); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' cancelled their order...'); } } class Controller { public function __construct(EventDispatcher $dispatcher) { $this->dispatcher = $dispatcher; } public function newCustomer() { $customer = new Customer($_POST); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.register', $event); } public function createOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Created order ' . $number); $twitter = new Twitter('demcrookidwigitz', 'b3@tb0Xpr0$'); $twitter->tweet($customer->getName() . ' just ordered from us!'); } public function cancelOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Cancelled order number ' . $number); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' cancelled their order...'); } }
  121. 9 Clean Up Other Controllers

  122. class Controller { public function __construct(EventDispatcher $dispatcher) { $this->dispatcher =

    $dispatcher; } public function newCustomer() { $customer = new Customer($_POST); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.register', $event); } public function createOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Created order ' . $number); $twitter = new Twitter('demcrookidwigitz', 'b3@tb0Xpr0$'); $twitter->tweet($customer->getName() . ' just ordered from us!'); } public function cancelOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Cancelled order number ' . $number); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' cancelled their order...'); } }
  123. class Controller { public function __construct(EventDispatcher $dispatcher) { $this->dispatcher =

    $dispatcher; } public function newCustomer() { $customer = new Customer($_POST); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.register', $event); } public function createOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Created order ' . $number); $twitter = new Twitter('demcrookidwigitz', 'b3@tb0Xpr0$'); $twitter->tweet($customer->getName() . ' just ordered from us!'); } public function cancelOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Cancelled order number ' . $number); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' cancelled their order...'); } } class Controller { public function __construct(EventDispatcher $dispatcher) { $this->dispatcher = $dispatcher; } public function newCustomer() { $customer = new Customer($_POST); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.register', $event); } public function createOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Created order ' . $number); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.order.new', $event); } public function cancelOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Cancelled order number ' . $number); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' cancelled their order...'); } }
  124. use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $twitter = new Twitter('demcrookidwigitz',

    'b3@tb0Xpr0$'); // Wire listeners $listener = new TwitterListener($twitter); $dispatcher->addListener('order.new', array($listener, 'tweetAtOrderer'));
  125. use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $twitter = new Twitter('demcrookidwigitz',

    'b3@tb0Xpr0$'); // Wire listeners $listener = new TwitterListener($twitter); $dispatcher->addListener('order.new', array($listener, 'tweetAtOrderer')); class TwitterListener { public function __construct(Twitter $twitter) { $this->twitter = $twitter; } public function tweetAtOrderer(CustomerEvent $event) { $customer = $event->getOrder(); $msg = $customer->getTwitterHandle().' Thanks for ordering from us!'; $this->twitter->tweet($msg); } }
  126. class Controller { public function __construct(EventDispatcher $dispatcher) { $this->dispatcher =

    $dispatcher; } public function newCustomer() { $customer = new Customer($_POST); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.register', $event); } public function createOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Created order ' . $number); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.order.new', $event); } public function cancelOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Cancelled order number ' . $number); $eLog = new EmailLogger('boss@demcrookidwigitz.com'); $eLog->log($customer->getName() . ' cancelled their order...'); } }
  127. use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $bossEmail = 'boss@demcrookidwigitz.com'; //

    Wire listeners // ... $listener = new BossCancelOrderEmailListener(new BossCancelOrderEmail($bossEmail)); $dispatcher->addListener('customer.order.cancel', array($listener, 'onCancelOrder')); class BossCancelOrderEmail { public function __construct($bossEmail) { $this->bossEmail = $bossEmail; } public function send($name) { return mail($this->bossEmail, $this->getSubject(), $this->getMessage($name), $this->getHeaders()); } protected function getSubject() { return 'Customer Order Cancelled'; } protected function getMessage($name) { return "Boss! " . $name . " cancelled their order. Bummer!"; } // ... }
  128. use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $bossEmail = 'boss@demcrookidwigitz.com'; //

    Wire listeners // ... $listener = new BossCancelOrderEmailListener(new BossCancelOrderEmail($bossEmail)); $dispatcher->addListener('customer.order.cancel', array($listener, 'onCancelOrder')); class BossCancelOrderEmailListener { public function __construct(BossCancelOrderEmail $email) { $this->email = $email; } public function onCancelOrder(CustomerEvent $event) { $customer = $event->getCustomer(); $this->email->send($customer->getName()); } }
  129. class Controller { public function __construct(EventDispatcher $dispatcher) { $this->dispatcher =

    $dispatcher; } public function newCustomer() { $customer = new Customer($_POST); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.register', $event); } public function createOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Created order ' . $number); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.order.new', $event); } public function cancelOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Cancelled order number ' . $number); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.order.cancel', $event); } }
  130. 1 0 Our Second Event

  131. class Controller { public function __construct(EventDispatcher $dispatcher) { $this->dispatcher =

    $dispatcher; } public function newCustomer() { $customer = new Customer($_POST); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.register', $event); } public function createOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Created order ' . $number); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.order.new', $event); } public function cancelOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Cancelled order number ' . $number); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.order.cancel', $event); } }
  132. class Controller { public function __construct(EventDispatcher $dispatcher) { $this->dispatcher =

    $dispatcher; } public function newCustomer() { $customer = new Customer($_POST); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.register', $event); } public function createOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Created order ' . $number); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.order.new', $event); } public function cancelOrder() { // ... $dLog = new DiskLogger('/logs/prod.log'); $dLog->log('Cancelled order number ' . $number); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.order.cancel', $event); } } class Controller { public function __construct(EventDispatcher $dispatcher) { $this->dispatcher = $dispatcher; } public function newCustomer() { $customer = new Customer($_POST); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.register', $event); } public function createOrder() { // ... $event = new OrderEvent($order); $this->dispatcher->dispatch('order.new', $event); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.order.new', $event); } public function cancelOrder() { // ... $event = new OrderEvent($order); $this->dispatcher->dispatch('order.cancel', $event); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.order.cancel', $event); } }
  133. use Symfony\Component\EventDispatcher\Event; class OrderEvent extends Event { protected $order; public

    function __construct(Order $order) { $this->order = $order; } public function getOrder() { return $this->order; } }
  134. use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $diskLogger = new DiskLogger('/logs/prod.log');

    // Wire listeners $listener = new OrderLoggerListener($diskLogger); $dispatcher->addListener('order.new', array($listener, 'onNewOrder')); class OrderLoggerListener { public function __construct(DiskLogger $logger) { $this->logger = $logger; } public function onNewOrder(OrderEvent $event) { $order = $event->getOrder(); $this->logger->log('Created order number ' . $order->getNumber()); } }
  135. use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $diskLogger = new DiskLogger('/logs/prod.log');

    // Wire listeners $listener = new OrderLoggerListener($diskLogger); $dispatcher->addListener('order.new', array($listener, 'onNewOrder')); $dispatcher->addListener('order.cancel', array($listener, 'onCancelOrder')); class OrderLoggerListener { public function __construct(DiskLogger $logger) { $this->logger = $logger; } public function onNewOrder(OrderEvent $event) { $order = $event->getOrder(); $this->logger->log('Created order number ' . $order->getNumber()); } public function onCancelOrder(OrderEvent $event) { $order = $event->getOrder(); $this->logger->log('Cancelled order number ' . $order->getNumber()); } }
  136. class Controller { public function __construct(EventDispatcher $dispatcher) { $this->dispatcher =

    $dispatcher; } public function newCustomer() { $customer = new Customer($_POST); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.register', $event); } public function createOrder() { // ... $event = new OrderEvent($order); $this->dispatcher->dispatch('order.new', $event); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.order.new', $event); } public function cancelOrder() { // ... $event = new OrderEvent($order); $this->dispatcher->dispatch('order.cancel', $event); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.order.cancel', $event); } } FINISH
  137. use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $diskLogger = new DiskLogger('/logs/prod.log');

    $twitter = new Twitter('demcrookidwigitz', 'b3@tb0Xpr0$'); $bossEmail = 'boss@demcrookidwigitz.com'; // Wire listeners $listener = new CustomerEmailListener(new WelcomeEmail()); $dispatcher->addListener('customer.register', array($listener, 'onRegister')); $listener = new BossNewCustomerEmailListener(new BossNewCustomerEmail($bossEmail)); $dispatcher->addListener('customer.register', array($listener, 'onCustomerRegister')); $listener = new BossCancelOrderEmailListener(new BossCancelOrderEmail($bossEmail)); $dispatcher->addListener('customer.order.cancel', array($listener, 'onCancelOrder')); $listener = new OrderLoggerListener($diskLogger); $dispatcher->addListener('order.new', array($listener, 'onNewOrder')); $dispatcher->addListener('order.cancel', array($listener, 'onCancelOrder')); $listener = new TwitterListener($twitter); $dispatcher->addListener('order.new', array($listener, 'tweetAtOrderer')); FINISH
  138. Caveats

  139. Listeners are notified in the order registered

  140. Caveat - Priority use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $dispatcher->addListener('customer.register',

    function(CustomerEvent $event) { // First }); $dispatcher->addListener('customer.register', function(CustomerEvent $event) { // Second }); $customer = new Customer(); $customer->setEmail('mikesmith@gmail.com'); $event = new CustomerEvent($customer); $dispatcher->dispatch('customer.register', $event); First Second
  141. unless a Priority integer is given when registering a listener

  142. Caveat - Priority use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $dispatcher->addListener('customer.register',

    function(CustomerEvent $event) { // Second }, 100); $dispatcher->addListener('customer.register', function(CustomerEvent $event) { // First }, 200); $customer = new Customer(); $customer->setEmail('mikesmith@gmail.com'); $event = new CustomerEvent($customer); $dispatcher->dispatch('customer.register', $event); First Second
  143. Caveat - Priority use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $dispatcher->addListener('customer.register',

    function(CustomerEvent $event) { // Third }, 100); $dispatcher->addListener('customer.register', function(CustomerEvent $event) { // First }, 200); $dispatcher->addListener('customer.register', function(CustomerEvent $event) { // Second }, 200); $customer = new Customer(); $customer->setEmail('mikesmith@gmail.com'); $event = new CustomerEvent($customer); $dispatcher->dispatch('customer.register', $event); First Third Second
  144. Don’t rely on priority

  145. Objects attached to Events are passed by reference

  146. which may lead to side effects if you’re not careful

  147. Caveat - Side Effects use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher();

    $dispatcher->addListener('customer.register', function(CustomerEvent $event) { echo $event->getCustomer()->getEmail(); // mikesmith@gmail.com $event->getCustomer()->setEmail('changed@gmail.com'); }); $dispatcher->addListener('customer.register', function(CustomerEvent $event) { echo $event->getCustomer()->getEmail(); // changed@gmail.com }); $customer = new Customer(); $customer->setEmail('mikesmith@gmail.com'); $event = new CustomerEvent($customer); $dispatcher->dispatch('customer.register', $event); 1. Set Email 2. Get Email 3. Update Email 4. Email not the same
  148. Can make debugging difficult

  149. Just ask a developer

  150. Just ask a developer

  151. Adobe Desktop Application Codebase Source: http://stlab.adobe.com/wiki/index.php/File:2008_07_25_google.pdf Event Handling logic All

    other logic 33% Event Handling bugs All other bugs 50%
  152. Ideas for Utilizing Events

  153. Ideas for Utilizing Events • Logging • Offloading expensive operations

    to a message queue • Email, PDF generation, file system access • Setting “created_at” or “updated_at” on an entity • Updating a search index when persisting an entity • Allowing users of your plug-ins to extend their functionality without modifying your code • What ideas have you come up with?
  154. Further Reading • Introduction to Symfony2 EventDispatcher http://bit.ly/sf2-event-dispatcher • An

    Introduction to Zend Framework 2 Event Manager http://bit.ly/zf2-event-manater • The S.O.L.I.D. Principles of OO and Agile Design http://bit.ly/uncle-bob-oo-insights
  155. Sources • http://lampwww.epfl.ch/~imaier/pub/DeprecatingObserversTR2010.pdf • http://stlab.adobe.com/wiki/index.php/File:2008_07_25_google.pdf Photo Credits • http://www.flickr.com/photos/pedromourapinheiro/2456410959/ •

    http://www.flickr.com/photos/seat850/3893504473/ • http://www.flickr.com/photos/slworking/5170065748/ • http://www.flickr.com/photos/33037982@N04/3727397261/ • http://www.flickr.com/photos/factoryjoe/26967479/
  156. John Kary johnkary@ gmail.com @ johnkary Slides @ http://johnkary.net/talks WRITING

    EXTENSIBLE CODE USING EVENT DISPATCHER https://joind.in/7551