Slide 1

Slide 1 text

WRITING EXTENSIBLE CODE USING EVENT DISPATCHER John Kary Kansas City PHP User Group, October 2012

Slide 2

Slide 2 text

ABOUT PHP since 2005 Contract PHP Developer in Lawrence Education & Trucking Industry Previously of University of Kansas - IT

Slide 3

Slide 3 text

EventDispatcher http://bit.ly/sf2-event-dispatcher { "require": { "symfony/event-dispatcher": "dev-master" } } php composer.phar update

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

DemCrookidWigitz.com

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

0Before We Begin

Slide 10

Slide 10 text

0Before We Begin UTION CAUTION CAUTION CAUTIO

Slide 11

Slide 11 text

The Code In This Presentation Is Not Production-Ready

Slide 12

Slide 12 text

1Procedural PHP

Slide 13

Slide 13 text

Procedural PHP $_POST = array( 'name' => 'John Kary', 'email' => '[email protected]', ); $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: [email protected]'; $headers[] = 'Reply-To: [email protected]'; $headers[] = 'X-Mailer: PHP/' . phpversion(); mail($to, $subject, $message, implode($headers, "\r\n"));

Slide 14

Slide 14 text

2 Object-Oriented PHP

Slide 15

Slide 15 text

Object-Oriented PHP $_POST = array( 'name' => 'John Kary', 'email' => '[email protected]', ); $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: [email protected]'; $headers[] = 'Reply-To: [email protected]'; $headers[] = 'X-Mailer: PHP/' . phpversion(); mail($to, $subject, $message, implode($headers, "\r\n")); Customer

Slide 16

Slide 16 text

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; } }

Slide 17

Slide 17 text

Object-Oriented PHP $_POST = array( 'name' => 'John Kary', 'email' => '[email protected]', ); $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: [email protected]'; $headers[] = 'Reply-To: [email protected]'; $headers[] = 'X-Mailer: PHP/' . phpversion(); mail($to, $subject, $message, implode($headers, "\r\n")); Customer WelcomeEmail

Slide 18

Slide 18 text

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: [email protected]'; $headers[] = 'Reply-To: [email protected]'; $headers[] = 'X-Mailer: PHP/' . phpversion(); return implode($headers, "\r\n"); } }

Slide 19

Slide 19 text

Object-Oriented PHP $_POST = array( 'name' => 'John Kary', 'email' => '[email protected]', ); $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: [email protected]'; $headers[] = 'Reply-To: [email protected]'; $headers[] = 'X-Mailer: PHP/' . phpversion(); mail($to, $subject, $message, implode($headers, "\r\n")); Customer WelcomeEmail Controller

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

3Disk Logging

Slide 23

Slide 23 text

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); } }

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

4More Disk Logging

Slide 27

Slide 27 text

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); } }

Slide 28

Slide 28 text

No content

Slide 29

Slide 29 text

5Moar Logging!

Slide 30

Slide 30 text

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('[email protected]'); $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('[email protected]'); $eLog->log($customer->getName() . ' cancelled their order...'); } }

Slide 31

Slide 31 text

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('[email protected]'); $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('[email protected]'); $eLog->log($customer->getName() . ' cancelled their order...');

Slide 32

Slide 32 text

Your Codebase Is Growing

Slide 33

Slide 33 text

?

Slide 34

Slide 34 text

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('[email protected]'); $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('[email protected]'); $eLog->log($customer->getName() . ' cancelled their order...'); } }

Slide 35

Slide 35 text

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('[email protected]'); $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('[email protected]'); $eLog->log($customer->getName() . ' cancelled their order...'); } }

Slide 36

Slide 36 text

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('[email protected]'); $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('[email protected]'); $eLog->log($customer->getName() . ' cancelled their order...'); } }

Slide 37

Slide 37 text

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('[email protected]'); $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('[email protected]'); $eLog->log($customer->getName() . ' cancelled their order...'); } }

Slide 38

Slide 38 text

Extensibility [A] system design principle where the implementation takes into consideration future growth. Extensibility - Wikipedia http://en.wikipedia.org/wiki/Extensibility

Slide 39

Slide 39 text

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('[email protected]'); $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('[email protected]'); $eLog->log($customer->getName() . ' cancelled their order...'); } }

Slide 40

Slide 40 text

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('[email protected]'); $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('[email protected]'); $eLog->log($customer->getName() . ' cancelled their order...'); } } NOT EXTENSIBLE!

Slide 41

Slide 41 text

Model View Controller

Slide 42

Slide 42 text

What is the Responsibility of a Controller?

Slide 43

Slide 43 text

Controllers should contain LOGIC

Slide 44

Slide 44 text

Controllers should contain LOGIC

Slide 45

Slide 45 text

Controllers should contain LOGIC

Slide 46

Slide 46 text

Controllers as Glue Custom Application Code Framework Controller

Slide 47

Slide 47 text

Controllers as Glue Custom Application Code Controller

Slide 48

Slide 48 text

Controllers as Glue Custom Application Code Controller

Slide 49

Slide 49 text

Event Dispatcher

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

Event Dispatcher - Register Listeners EventDispatcher AListener named.eventA BListener named.eventB CListener named.eventC

Slide 57

Slide 57 text

Let’s use a more concrete example

Slide 58

Slide 58 text

Event Dispatcher - Register Listeners CartListener:: onAddToCart() EventDispatcher cart.add CustomerListener:: onRegister() customer.register CartListener:: grantDiscount() cart.checkout

Slide 59

Slide 59 text

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()

Slide 60

Slide 60 text

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 } }

Slide 61

Slide 61 text

Event Dispatcher - Register Listeners use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $dispatcher->addListener('customer.register', function(CustomerEvent $event) { // Do some work });

Slide 62

Slide 62 text

Event Dispatcher - Dispatch an Event

Slide 63

Slide 63 text

Request Response Event Dispatcher - Dispatch an Event

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

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' => '[email protected]', )); $event = new CustomerEvent($customer); $this->dispatcher->dispatch('customer.register', $event); } } Customer Event Event Name

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

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);

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

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()

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

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 } }

Slide 74

Slide 74 text

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; } }

Slide 75

Slide 75 text

Event Dispatcher - All together now!

Slide 76

Slide 76 text

Event Dispatcher - All together now! EventDispatcher

Slide 77

Slide 77 text

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

Slide 78

Slide 78 text

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

Slide 79

Slide 79 text

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()

Slide 80

Slide 80 text

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);

Slide 81

Slide 81 text

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()

Slide 82

Slide 82 text

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()

Slide 83

Slide 83 text

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!

Slide 84

Slide 84 text

Let’s refactor our Controller

Slide 85

Slide 85 text

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('[email protected]'); $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('[email protected]'); $eLog->log($customer->getName() . ' cancelled their order...'); } } START

Slide 86

Slide 86 text

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

Slide 87

Slide 87 text

6 Inject the EventDispatcher

Slide 88

Slide 88 text

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('[email protected]'); $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('[email protected]');

Slide 89

Slide 89 text

7Our First Event

Slide 90

Slide 90 text

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('[email protected]'); $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('[email protected]');

Slide 91

Slide 91 text

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('[email protected]'); $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('[email protected]');

Slide 92

Slide 92 text

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; } }

Slide 93

Slide 93 text

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: [email protected]';

Slide 94

Slide 94 text

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

Slide 95

Slide 95 text

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

Slide 96

Slide 96 text

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()); } }

Slide 97

Slide 97 text

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()); } }

Slide 98

Slide 98 text

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()); } }

Slide 99

Slide 99 text

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()); } }

Slide 100

Slide 100 text

8 Move more code to listeners

Slide 101

Slide 101 text

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('[email protected]'); $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('[email protected]');

Slide 102

Slide 102 text

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'));

Slide 103

Slide 103 text

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'));

Slide 104

Slide 104 text

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()); } }

Slide 105

Slide 105 text

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()); } }

Slide 106

Slide 106 text

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()); } }

Slide 107

Slide 107 text

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()); } }

Slide 108

Slide 108 text

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()); } }

Slide 109

Slide 109 text

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('[email protected]'); $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('[email protected]');

Slide 110

Slide 110 text

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('[email protected]'); $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('[email protected]'); 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('[email protected]'); $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('[email protected]'); $eLog->log($customer->getName() . ' cancelled their order...'); } }

Slide 111

Slide 111 text

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('[email protected]'); $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('[email protected]'); 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('[email protected]'); $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('[email protected]'); $eLog->log($customer->getName() . ' cancelled their order...'); } }

Slide 112

Slide 112 text

use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $bossEmail = '[email protected]'; // Wire listeners // ... $listener = new BossNewCustomerEmailListener(new BossNewCustomerEmail($bossEmail)); $dispatcher->addListener('customer.register', array($listener, 'onCustomerRegister'));

Slide 113

Slide 113 text

use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $bossEmail = '[email protected]'; // Wire listeners // ... $listener = new BossNewCustomerEmailListener(new BossNewCustomerEmail($bossEmail)); $dispatcher->addListener('customer.register', array($listener, 'onCustomerRegister'));

Slide 114

Slide 114 text

use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $bossEmail = '[email protected]'; // Wire listeners // ... $listener = new BossNewCustomerEmailListener(new BossNewCustomerEmail($bossEmail)); $dispatcher->addListener('customer.register', array($listener, 'onCustomerRegister'));

Slide 115

Slide 115 text

use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $bossEmail = '[email protected]'; // 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?"; } // ... }

Slide 116

Slide 116 text

use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $bossEmail = '[email protected]'; // Wire listeners // ... $listener = new BossNewCustomerEmailListener(new BossNewCustomerEmail($bossEmail)); $dispatcher->addListener('customer.register', array($listener, 'onCustomerRegister'));

Slide 117

Slide 117 text

use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $bossEmail = '[email protected]'; // 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()); } }

Slide 118

Slide 118 text

use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $bossEmail = '[email protected]'; // 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()); } }

Slide 119

Slide 119 text

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('[email protected]'); $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('[email protected]'); $eLog->log($customer->getName() . ' cancelled their order...'); } }

Slide 120

Slide 120 text

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('[email protected]'); $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('[email protected]'); $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('[email protected]'); $eLog->log($customer->getName() . ' cancelled their order...'); } }

Slide 121

Slide 121 text

9 Clean Up Other Controllers

Slide 122

Slide 122 text

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('[email protected]'); $eLog->log($customer->getName() . ' cancelled their order...'); } }

Slide 123

Slide 123 text

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('[email protected]'); $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('[email protected]'); $eLog->log($customer->getName() . ' cancelled their order...'); } }

Slide 124

Slide 124 text

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'));

Slide 125

Slide 125 text

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); } }

Slide 126

Slide 126 text

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('[email protected]'); $eLog->log($customer->getName() . ' cancelled their order...'); } }

Slide 127

Slide 127 text

use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $bossEmail = '[email protected]'; // 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!"; } // ... }

Slide 128

Slide 128 text

use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $bossEmail = '[email protected]'; // 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()); } }

Slide 129

Slide 129 text

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); } }

Slide 130

Slide 130 text

1 0 Our Second Event

Slide 131

Slide 131 text

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); } }

Slide 132

Slide 132 text

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); } }

Slide 133

Slide 133 text

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; } }

Slide 134

Slide 134 text

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()); } }

Slide 135

Slide 135 text

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()); } }

Slide 136

Slide 136 text

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

Slide 137

Slide 137 text

use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $diskLogger = new DiskLogger('/logs/prod.log'); $twitter = new Twitter('demcrookidwigitz', 'b3@tb0Xpr0$'); $bossEmail = '[email protected]'; // 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

Slide 138

Slide 138 text

Caveats

Slide 139

Slide 139 text

Listeners are notified in the order registered

Slide 140

Slide 140 text

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('[email protected]'); $event = new CustomerEvent($customer); $dispatcher->dispatch('customer.register', $event); First Second

Slide 141

Slide 141 text

unless a Priority integer is given when registering a listener

Slide 142

Slide 142 text

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('[email protected]'); $event = new CustomerEvent($customer); $dispatcher->dispatch('customer.register', $event); First Second

Slide 143

Slide 143 text

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('[email protected]'); $event = new CustomerEvent($customer); $dispatcher->dispatch('customer.register', $event); First Third Second

Slide 144

Slide 144 text

Don’t rely on priority

Slide 145

Slide 145 text

Objects attached to Events are passed by reference

Slide 146

Slide 146 text

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

Slide 147

Slide 147 text

Caveat - Side Effects use Symfony\Component\EventDispatcher\EventDispatcher; $dispatcher = new EventDispatcher(); $dispatcher->addListener('customer.register', function(CustomerEvent $event) { echo $event->getCustomer()->getEmail(); // [email protected] $event->getCustomer()->setEmail('[email protected]'); }); $dispatcher->addListener('customer.register', function(CustomerEvent $event) { echo $event->getCustomer()->getEmail(); // [email protected] }); $customer = new Customer(); $customer->setEmail('[email protected]'); $event = new CustomerEvent($customer); $dispatcher->dispatch('customer.register', $event); 1. Set Email 2. Get Email 3. Update Email 4. Email not the same

Slide 148

Slide 148 text

Can make debugging difficult

Slide 149

Slide 149 text

Just ask a developer

Slide 150

Slide 150 text

Just ask a developer

Slide 151

Slide 151 text

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%

Slide 152

Slide 152 text

Ideas for Utilizing Events

Slide 153

Slide 153 text

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?

Slide 154

Slide 154 text

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

Slide 155

Slide 155 text

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/

Slide 156

Slide 156 text

John Kary johnkary@ gmail.com @ johnkary Slides @ http://johnkary.net/talks WRITING EXTENSIBLE CODE USING EVENT DISPATCHER https://joind.in/7551