symfony events

20
Symfony Events Every event happens for a reason Brent Shaffer @bshaffer CentreSource Interactive Agency www.brentertainment.com June 1st, 2010

Upload: brent-shaffer

Post on 15-Jan-2015

3.835 views

Category:

Technology


6 download

DESCRIPTION

An introduction to symfony events. Includes: - Symfony Events Overview - Conceptual Examples - Utilizing Symfony Core Events - Creating Your Own Event System

TRANSCRIPT

Page 1: Symfony Events

Symfony EventsEvery event happens for a reason

Brent Shaffer@bshaffer

CentreSource Interactive Agencywww.brentertainment.com

June 1st, 2010

Page 2: Symfony Events

Symfony Events“All [symfony] events are blessings given to us to learn from.” - Elizabeth Kubler-Ross

“Great [symfony] events make me quiet and calm; it is only [fat controllers] that irritate my nerves.”- Queen Elizabeth

“Keep [symfony events] around for when shit gets crazy. Cause shit will get crazy!”

- Carp Guy

Page 3: Symfony Events

• Symfony events are part of the Event Dispatcher component

• Implements the Observer design pattern (Design Patterns, GoF)

• “...The subject maintains a list of its dependants, called observers, and notifies them automatically of any state changes”

• Lightweight, consists of only 2 classes

1. sfEventDispatcher - object responsible for maintaining a register of listeners and calling them whenever an event is notified

2. sfEvent - object that stores information about the notified event

Overview

What are Symfony Events

Page 4: Symfony Events

Notify Until - Notifies all listeners of a given event until one returns a non null value.

Filter - Filters a value by calling all listeners of a given event.

Notify - Notifies all listeners of a given event.

sfEventDispatcherConnect - Connects a listener to a given event name.

$dispatcher->notifyUntil(sfEvent $event);

$dispatcher->notify(sfEvent $event);

$dispatcher->filter(sfEvent $event, $value);

$dispatcher->connect('event.name', array($php, 'callable'));

Page 5: Symfony Events

// sfContext and sfApplicationConfiguration:$this->context->getEventDispatcher();sfApplicationConfiguration::getActive()->getEventDispatcher();

// sfFormSymfony subclassesself::getEventDispatcher();

// sfActions subclass / sfBaseTask subclass / sfPHPView:$this->dispatcher

How do I access it?

sfContext and sfApplicationConfiguration hold a single sfEventDispatcher instance and facilitate it to other classes

sfEventDispatcherWhere is it?

Page 6: Symfony Events

sfEvent

public function __construct($subject, $name, $parameters = array())

Subject

Name

Parameters

The subject of the event (the object notifying the event, or object the event is about. It can also be null);

The event name

An array of parameters to pass to the listeners (an empty array by default)

The event object can also be accessed as an array to get its parameters

$method = $event['method'];// Is the same as$parameters = $event->getParameters();$method = $parameters['method'];

Constructor

Page 7: Symfony Events

NotifyA client calls in for Employee One to call them back// aClient.class.php$this->dispatcher ->connect('employee_one.becomes_available', array($this, 'callMe'));

A lawyer calls in, needs Employee One to sign some lawyer stuff

Receptionist with Four Employees

12 3

4

Receptionist (event dispatcher)

// EmployeeOne.class.phppublic function becomesAvailable() { $this->dispatcher->notify(new sfEvent($this, 'employee_one.available'));}

Employee One lets secretary know when he’s available.

// aLawyer.class.php$this->dispatcher ->connect('employee_one.becomes_available', array($this, 'signMyStuff'));

Conceptual Example

Page 8: Symfony Events

Conceptual Example Notify

Employee Three wants to know when employee 2 leaves, so he can eat his leftovers// EmployeeThree.class.php$this->dispatcher->connect('employee_two.goes_home', array($this, 'stealLeftovers'));

public function stealLeftovers(sfEvent $event) { $employeeTwo = $event->getSubject(); $this->eat($employeeTwo->getLeftovers());}

// EmployeeTwo.class.phppublic function goesHome() { $this->dispatcher->notify(new sfEvent($this, 'employee_two.goes_home'));}

Employee Two lets secretary know when he’s leaving.

Receptionist with Four Employees

12 3

4

Receptionist (event dispatcher)

Page 9: Symfony Events

Conceptual Example

Employee 4 puts out an add in the newspaper

Now Hiring: Personal assistant. Strong communication skills.

Willing to take excessive sexual harassment. Call before 5:00 PM

Individuals call in to register// aProspect.class.php$this->dispatcher->connect('employee_four.job_offering', array($this, 'callMe'));

// aFeministMovement.class.php$this->dispatcher->connect('employee_four.job_offering', array($this, 'sue'));

// EmployeeFour.class.php (at 5:00)$event = $this->dispatcher->notifyUntil(new sfEvent($this, 'employee_four.job_offering'));if($event->isProcessed()) $employee = $event->getReturnValue();

Employee Four notifies the registered listeners until he finds an employee

Notify Until Receptionist with Four Employees

12 3

4

Receptionist (event dispatcher)

Page 10: Symfony Events

Conceptual Example

Employee 4 puts out an add in the newspaper, yadda yadda, but this time, he wants a list.

// EmployeeFour.class.php (at 5:00)$event = $this->dispatcher->filter(new sfEvent($this, 'employee_four.job_offering'), $list);$list = $event->getReturnValue();

// aProspect.class.php$this->dispatcher ->connect('employee_four.job_offering', array($this, 'addToList'));

public function addToList($event, $list) { $list[] = $self; $event->setReturnValue($list);}

Employee Four notifies the registered listener and provides the item to filter

Filter Receptionist with Four Employees

12 3

4

Receptionist (event dispatcher)

Page 11: Symfony Events

Utilizing Symfony Core EventsLazy-add mobile templates

We will now demonstrate how useful symfony core events can be in your application

We will show how to add mobile-specific layouts to your existing application.

“Lazy-add” - add mobile templates as you go while keeping everything without a mobile template still accessible. In other words, if a mobile template exists, render it for mobile devices. Otherwise, render the default template.

Based largely on the blog post “How to create an optimized version of your website for the iPhone in symfony 1.1”

Page 12: Symfony Events

Utilizing Symfony Core EventsLazy-add mobile templates

Connect to “filter parameters” event, add request format for the appropriate user agent

// ProjectConfiguration.class.phppublic function setup() { ... $this->dispatcher->connect('request.filter_parameters', array($this, 'filterRequestParameters'));}

public function filterRequestParameters(sfEvent $event, $parameters){ $request = $event->getSubject(); if (preg_match('#Mobile/.+Safari#i', $request->getHttpHeader('User-Agent'))) { $request->setRequestFormat('m'); } return $parameters;}

Page 13: Symfony Events

Utilizing Symfony Core EventsLazy-add mobile templates

Connect to “view.configure_format” event to only set if the template exists

// ProjectConfiguration.class.phppublic function setup() { ... $this->dispatcher->connect('view.configure_format', array($this, 'configureMobileFormat'));}

public function configureMobileFormat(sfEvent $event){ if ('m' == $event['format']) { $view = $event->getSubject(); $dir = sfConfig::get('sf_app_module_dir').'/'.$view->getModuleName().'/templates/'. $view->getActionName().$view->getViewName().$view->getExtension();

if (!file_exists($dir)) { $view->setExtension('.php'); } }}

Page 14: Symfony Events

Utilizing Symfony Core EventsLazy-add mobile templates

Set our mobile format in factories.yml

// factories.ymlall: request: class: sfWebRequest param: formats: m: text/html ...

Now, we can add mobile templates as we go, while keeping the rest of the site as-is!

Page 15: Symfony Events

Creating Your Own EventsAlert System

// ProjectConfiguration.class.phppublic function setup() { ... include_once sfConfig::get('sf_lib_dir').'/alert/sfAlertDispatcher.class.php'; $this->alertDispatcher = new sfAlertDispatcher(); $this->alertDispatcher->connectEvents($this->dispatcher);}

We will now demonstrate how creating your own set of events can be useful.

Using events keeps your libraries modular and decoupled. It also makes them very easy to unit test.

You want to build a system in your application that sends email alerts out for various triggers. You’re smart, so you will accomplish this using the event dispatcher

Page 16: Symfony Events

Creating Your Own EventsAlert System

// lib/alert/sfAlertDispatcher.class.php class cfitAlertDispatcher{ public function connectEvents(sfEventDispatcher $dispatcher) { // = Raise Alerts = $dispatcher->connect('contact.form_submitted', array($this, 'alertContactForm'));

$dispatcher->connect('support.ticket_submitted', array($this, 'alertTicketSubmitted')); // = Resolve Alerts = $dispatcher->connect('support.ticket_closed', array($this, 'resolveSupportTicket')); }}

Handle your events inside your model. Keep things modular.

Page 17: Symfony Events

Creating Your Own EventsAlert System

// lib/alert/sfAlertDispatcher.class.php class cfitAlertDispatcher{ ... public function alertContactForm(sfEvent $event) { // ...do alert logic, etc $form = $event->getSubject(); $this->mailer->send($this->getContactEmailFromForm($form)); }

public function alertTicketSubmitted(sfEvent $event) { // Notice how easy this logic will be to unit test! $ticket = $event->getSubject(); if($ticket->isAtleastCritical()) { $this->mailer->send($this->getEmailFromTicket($ticket)); } } ... }

Write your implementation logic for the appropriate listeners

Page 18: Symfony Events

Creating Your Own EventsAlert System

// contactActions.class.php ...$this->dispatcher->notify(new sfEvent($form, 'contact.form_submitted'));

// ticketActions.class.php...$dispatcher->notify(new sfEvent($ticket, 'support.ticket_submitted')); ...// Ticket.class.phppublic function close(sfEventDispatcher $dispatcher){ ... $dispatcher->notify(new sfEvent($this, 'support.ticket_closed'));}

Add the logic in your application for triggering the events

Page 19: Symfony Events

Creating Your Own EventsAlert System

And that’s it! The rest is a matter of implementation logic for your specific application

Notice how easy cfitAlertDispatcher is to unit test. Get rid of all those fat controllers!

And one last quote...

“...Gather in your resources, rally all your faculties, marshal all your energies, focus all your capacities upon mastery of [symfony events]”- John Haggai

Page 20: Symfony Events

2010-05-01

Brent Shaffer@bshaffer

CentreSource Interactive Agencywww.brentertainment.com

Questions?