SlideShare a Scribd company logo
Symfony Events
Every event happens for a reason




                                   Brent Shaffer
                                    @bshaffer
                          CentreSource Interactive Agency
                            www.brentertainment.com
                                  June 1st, 2010
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
What are Symfony Events
Overview
 • 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
sfEventDispatcher
Connect
  - Connects a listener to a given event name.
   $dispatcher->connect('event.name', array($php, 'callable'));

Notify
  - Notifies all listeners of a given event.
   $dispatcher->notify(sfEvent $event);


Notify Until
  - Notifies all listeners of a given event until one returns a non null value.
   $dispatcher->notifyUntil(sfEvent $event);


Filter
  - Filters a value by calling all listeners of a given event.
   $dispatcher->filter(sfEvent $event, $value);
sfEventDispatcher
Where is it?
  sfContext and sfApplicationConfiguration hold a single sfEventDispatcher
  instance and facilitate it to other classes

How do I access it?

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


  // sfFormSymfony subclasses
  self::getEventDispatcher();


  // sfActions subclass   / sfBaseTask subclass / sfPHPView:
  $this->dispatcher
sfEvent
Constructor
  public function __construct($subject, $name, $parameters = array())



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


  Name            The event name


  Parameters      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'];
Conceptual Example
                                                          Receptionist with Four Employees
Notify
 A client calls in for Employee One to call them back                  Receptionist
                                                                      (event dispatcher)
 // aClient.class.php
 $this->dispatcher
   ->connect('employee_one.becomes_available',                  1                          4
       array($this, 'callMe'));

 A lawyer calls in, needs Employee One to sign
                                                                        2          3
 some lawyer stuff
 // aLawyer.class.php
 $this->dispatcher
   ->connect('employee_one.becomes_available', array($this, 'signMyStuff'));

 Employee One lets secretary know when he’s available.
 // EmployeeOne.class.php
 public function becomesAvailable() {
     $this->dispatcher->notify(new sfEvent($this, 'employee_one.available'));
 }
Conceptual Example
                                                          Receptionist with Four Employees
Notify
 Employee Three wants to know when employee 2                         Receptionist
                                                                      (event dispatcher)
 leaves, so he can eat his leftovers
 // EmployeeThree.class.php
 $this->dispatcher->connect('employee_two.goes_home',
                                                                1                          4
      array($this, 'stealLeftovers'));
                                                                       2           3
 public function stealLeftovers(sfEvent $event) {
   $employeeTwo = $event->getSubject();
   $this->eat($employeeTwo->getLeftovers());
 }


 Employee Two lets secretary know when he’s leaving.

 // EmployeeTwo.class.php
 public function goesHome() {
     $this->dispatcher->notify(new sfEvent($this, 'employee_two.goes_home'));
 }
Conceptual Example
                                                         Receptionist with Four Employees
Notify Until
 Employee 4 puts out an add in the newspaper                         Receptionist
                                                                     (event dispatcher)
     Now Hiring: Personal assistant.
       Strong communication skills.
     Willing to take excessive sexual                         1                           4
     harassment. Call before 5:00 PM
                                                                      2           3
 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'));


 Employee Four notifies the registered listeners until he finds an employee
 // EmployeeFour.class.php (at 5:00)
 $event = $this->dispatcher->notifyUntil(new sfEvent($this, 'employee_four.job_offering'));
 if($event->isProcessed()) $employee = $event->getReturnValue();
Conceptual Example
                                                         Receptionist with Four Employees
Filter
 Employee 4 puts out an add in the newspaper,                        Receptionist
 yadda yadda, but this time, he wants a list.                        (event dispatcher)

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

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


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

// EmployeeFour.class.php (at 5:00)
$event = $this->dispatcher->filter(new sfEvent($this, 'employee_four.job_offering'), $list);
$list = $event->getReturnValue();
Utilizing Symfony Core Events
Lazy-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”
Utilizing Symfony Core Events
Lazy-add mobile templates
    Connect to “filter parameters” event, add request format for the appropriate
    user agent

// ProjectConfiguration.class.php
public 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;
}
Utilizing Symfony Core Events
Lazy-add mobile templates
 Connect to “view.configure_format” event to only set if the template exists

// ProjectConfiguration.class.php
public 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');
        }
    }
}
Utilizing Symfony Core Events
Lazy-add mobile templates
 Set our mobile format in factories.yml
  // factories.yml
  all:
    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!
Creating Your Own Events
Alert System
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

 // ProjectConfiguration.class.php
 public function setup()
 {
   ...
     include_once sfConfig::get('sf_lib_dir').'/alert/sfAlertDispatcher.class.php';
     $this->alertDispatcher = new sfAlertDispatcher();
     $this->alertDispatcher->connectEvents($this->dispatcher);
 }
Creating Your Own Events
Alert System
 Handle your events inside your model. Keep things modular.

 // 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'));
     }
 }
Creating Your Own Events
Alert System
 Write your implementation logic for the appropriate listeners
 // 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));
       }
     }
     ...
 }
Creating Your Own Events
Alert System
 Add the logic in your application for triggering the events

 // 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.php
 public function close(sfEventDispatcher $dispatcher)
 {
   ...
   $dispatcher->notify(new sfEvent($this, 'support.ticket_closed'));
 }
Creating Your Own Events
Alert 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
Questions?

                      Brent Shaffer
                       @bshaffer
             CentreSource Interactive Agency
               www.brentertainment.com




2010-05-01

More Related Content

What's hot

Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)
Fabien Potencier
 
2014 database - course 2 - php
2014 database - course 2 - php2014 database - course 2 - php
2014 database - course 2 - php
Hung-yu Lin
 

What's hot (12)

Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)
 
Extbase and Beyond
Extbase and BeyondExtbase and Beyond
Extbase and Beyond
 
Generating Power with Yield
Generating Power with YieldGenerating Power with Yield
Generating Power with Yield
 
Feeds drupal cafe
Feeds drupal cafeFeeds drupal cafe
Feeds drupal cafe
 
8時間耐久CakePHP2 勉強会
8時間耐久CakePHP2 勉強会8時間耐久CakePHP2 勉強会
8時間耐久CakePHP2 勉強会
 
Isset(), unset(), empty() 4
Isset(), unset(), empty()   4Isset(), unset(), empty()   4
Isset(), unset(), empty() 4
 
What is the difference between a good and a bad repository? (Forum PHP 2018)
What is the difference between a good and a bad repository? (Forum PHP 2018)What is the difference between a good and a bad repository? (Forum PHP 2018)
What is the difference between a good and a bad repository? (Forum PHP 2018)
 
Digital Mayflower - Data Pilgrimage with the Drupal Migrate Module
Digital Mayflower - Data Pilgrimage with the Drupal Migrate ModuleDigital Mayflower - Data Pilgrimage with the Drupal Migrate Module
Digital Mayflower - Data Pilgrimage with the Drupal Migrate Module
 
Storytelling By Numbers
Storytelling By NumbersStorytelling By Numbers
Storytelling By Numbers
 
2014 database - course 2 - php
2014 database - course 2 - php2014 database - course 2 - php
2014 database - course 2 - php
 
PHP for Adults: Clean Code and Object Calisthenics
PHP for Adults: Clean Code and Object CalisthenicsPHP for Adults: Clean Code and Object Calisthenics
PHP for Adults: Clean Code and Object Calisthenics
 
The Truth About Lambdas in PHP
The Truth About Lambdas in PHPThe Truth About Lambdas in PHP
The Truth About Lambdas in PHP
 

Similar to Symfony Events

Phpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsPhpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friends
Michael Peacock
 
SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Development
jsmith92
 
Beyond symfony 1.2 (Symfony Camp 2008)
Beyond symfony 1.2 (Symfony Camp 2008)Beyond symfony 1.2 (Symfony Camp 2008)
Beyond symfony 1.2 (Symfony Camp 2008)
Fabien Potencier
 
Design patterns revisited with PHP 5.3
Design patterns revisited with PHP 5.3Design patterns revisited with PHP 5.3
Design patterns revisited with PHP 5.3
Fabien Potencier
 
Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2
Fabien Potencier
 

Similar to Symfony Events (20)

Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et Pimple
 
How I started to love design patterns
How I started to love design patternsHow I started to love design patterns
How I started to love design patterns
 
A Series of Fortunate Events - Symfony Camp Sweden 2014
A Series of Fortunate Events - Symfony Camp Sweden 2014A Series of Fortunate Events - Symfony Camp Sweden 2014
A Series of Fortunate Events - Symfony Camp Sweden 2014
 
Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12
 
Phpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsPhpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friends
 
Symfony2 your way
Symfony2   your waySymfony2   your way
Symfony2 your way
 
A Series of Fortunate Events - Drupalcon Europe, Amsterdam 2014
A Series of Fortunate Events - Drupalcon Europe, Amsterdam 2014A Series of Fortunate Events - Drupalcon Europe, Amsterdam 2014
A Series of Fortunate Events - Drupalcon Europe, Amsterdam 2014
 
How I started to love design patterns
How I started to love design patternsHow I started to love design patterns
How I started to love design patterns
 
Symfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteSymfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il cliente
 
Filesystem abstractions and msg queue sergeev - symfony camp 2018
Filesystem abstractions and msg queue   sergeev - symfony camp 2018Filesystem abstractions and msg queue   sergeev - symfony camp 2018
Filesystem abstractions and msg queue sergeev - symfony camp 2018
 
Mocking Demystified
Mocking DemystifiedMocking Demystified
Mocking Demystified
 
Symfony internals [english]
Symfony internals [english]Symfony internals [english]
Symfony internals [english]
 
SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Development
 
Beyond symfony 1.2 (Symfony Camp 2008)
Beyond symfony 1.2 (Symfony Camp 2008)Beyond symfony 1.2 (Symfony Camp 2008)
Beyond symfony 1.2 (Symfony Camp 2008)
 
Design patterns revisited with PHP 5.3
Design patterns revisited with PHP 5.3Design patterns revisited with PHP 5.3
Design patterns revisited with PHP 5.3
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony Apps
 
Estendere applicazioni extbase
Estendere applicazioni extbaseEstendere applicazioni extbase
Estendere applicazioni extbase
 
Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2
 
Event Sourcing with php
Event Sourcing with phpEvent Sourcing with php
Event Sourcing with php
 
Алексей Плеханов: Новинки Laravel 5
Алексей Плеханов: Новинки Laravel 5Алексей Плеханов: Новинки Laravel 5
Алексей Плеханов: Новинки Laravel 5
 

More from Brent Shaffer

More from Brent Shaffer (9)

Web Security 101
Web Security 101Web Security 101
Web Security 101
 
HTTP - The Protocol of Our Lives
HTTP - The Protocol of Our LivesHTTP - The Protocol of Our Lives
HTTP - The Protocol of Our Lives
 
OAuth2 - The Swiss Army Framework
OAuth2 - The Swiss Army FrameworkOAuth2 - The Swiss Army Framework
OAuth2 - The Swiss Army Framework
 
Why Open Source is better than Your Homerolled Garbage
Why Open Source is better than Your Homerolled GarbageWhy Open Source is better than Your Homerolled Garbage
Why Open Source is better than Your Homerolled Garbage
 
OAuth 2.0 (as a comic strip)
OAuth 2.0 (as a comic strip)OAuth 2.0 (as a comic strip)
OAuth 2.0 (as a comic strip)
 
In The Future We All Use Symfony2
In The Future We All Use Symfony2In The Future We All Use Symfony2
In The Future We All Use Symfony2
 
Nashville Symfony Functional Testing
Nashville Symfony Functional TestingNashville Symfony Functional Testing
Nashville Symfony Functional Testing
 
Nashvile Symfony Routes Presentation
Nashvile Symfony Routes PresentationNashvile Symfony Routes Presentation
Nashvile Symfony Routes Presentation
 
Nashville Php Symfony Presentation
Nashville Php Symfony PresentationNashville Php Symfony Presentation
Nashville Php Symfony Presentation
 

Recently uploaded

Recently uploaded (20)

FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
 
IoT Analytics Company Presentation May 2024
IoT Analytics Company Presentation May 2024IoT Analytics Company Presentation May 2024
IoT Analytics Company Presentation May 2024
 
The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
 
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
 
When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
 
Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
 
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptxIOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
 
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered QualitySoftware Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
 
Speed Wins: From Kafka to APIs in Minutes
Speed Wins: From Kafka to APIs in MinutesSpeed Wins: From Kafka to APIs in Minutes
Speed Wins: From Kafka to APIs in Minutes
 
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
 
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
 
"Impact of front-end architecture on development cost", Viktor Turskyi
"Impact of front-end architecture on development cost", Viktor Turskyi"Impact of front-end architecture on development cost", Viktor Turskyi
"Impact of front-end architecture on development cost", Viktor Turskyi
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
 
Exploring UiPath Orchestrator API: updates and limits in 2024 🚀
Exploring UiPath Orchestrator API: updates and limits in 2024 🚀Exploring UiPath Orchestrator API: updates and limits in 2024 🚀
Exploring UiPath Orchestrator API: updates and limits in 2024 🚀
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
 
UiPath Test Automation using UiPath Test Suite series, part 2
UiPath Test Automation using UiPath Test Suite series, part 2UiPath Test Automation using UiPath Test Suite series, part 2
UiPath Test Automation using UiPath Test Suite series, part 2
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
 

Symfony Events

  • 1. Symfony Events Every event happens for a reason Brent Shaffer @bshaffer CentreSource Interactive Agency www.brentertainment.com June 1st, 2010
  • 2. 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
  • 3. What are Symfony Events Overview • 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
  • 4. sfEventDispatcher Connect - Connects a listener to a given event name. $dispatcher->connect('event.name', array($php, 'callable')); Notify - Notifies all listeners of a given event. $dispatcher->notify(sfEvent $event); Notify Until - Notifies all listeners of a given event until one returns a non null value. $dispatcher->notifyUntil(sfEvent $event); Filter - Filters a value by calling all listeners of a given event. $dispatcher->filter(sfEvent $event, $value);
  • 5. sfEventDispatcher Where is it? sfContext and sfApplicationConfiguration hold a single sfEventDispatcher instance and facilitate it to other classes How do I access it? // sfContext and sfApplicationConfiguration: $this->context->getEventDispatcher(); sfApplicationConfiguration::getActive()->getEventDispatcher(); // sfFormSymfony subclasses self::getEventDispatcher(); // sfActions subclass / sfBaseTask subclass / sfPHPView: $this->dispatcher
  • 6. sfEvent Constructor public function __construct($subject, $name, $parameters = array()) Subject The subject of the event (the object notifying the event, or object the event is about. It can also be null); Name The event name Parameters 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'];
  • 7. Conceptual Example Receptionist with Four Employees Notify A client calls in for Employee One to call them back Receptionist (event dispatcher) // aClient.class.php $this->dispatcher ->connect('employee_one.becomes_available', 1 4 array($this, 'callMe')); A lawyer calls in, needs Employee One to sign 2 3 some lawyer stuff // aLawyer.class.php $this->dispatcher ->connect('employee_one.becomes_available', array($this, 'signMyStuff')); Employee One lets secretary know when he’s available. // EmployeeOne.class.php public function becomesAvailable() { $this->dispatcher->notify(new sfEvent($this, 'employee_one.available')); }
  • 8. Conceptual Example Receptionist with Four Employees Notify Employee Three wants to know when employee 2 Receptionist (event dispatcher) leaves, so he can eat his leftovers // EmployeeThree.class.php $this->dispatcher->connect('employee_two.goes_home', 1 4 array($this, 'stealLeftovers')); 2 3 public function stealLeftovers(sfEvent $event) { $employeeTwo = $event->getSubject(); $this->eat($employeeTwo->getLeftovers()); } Employee Two lets secretary know when he’s leaving. // EmployeeTwo.class.php public function goesHome() { $this->dispatcher->notify(new sfEvent($this, 'employee_two.goes_home')); }
  • 9. Conceptual Example Receptionist with Four Employees Notify Until Employee 4 puts out an add in the newspaper Receptionist (event dispatcher) Now Hiring: Personal assistant. Strong communication skills. Willing to take excessive sexual 1 4 harassment. Call before 5:00 PM 2 3 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')); Employee Four notifies the registered listeners until he finds an employee // EmployeeFour.class.php (at 5:00) $event = $this->dispatcher->notifyUntil(new sfEvent($this, 'employee_four.job_offering')); if($event->isProcessed()) $employee = $event->getReturnValue();
  • 10. Conceptual Example Receptionist with Four Employees Filter Employee 4 puts out an add in the newspaper, Receptionist yadda yadda, but this time, he wants a list. (event dispatcher) // aProspect.class.php $this->dispatcher 1 4 ->connect('employee_four.job_offering', array($this, 'addToList')); 2 3 public function addToList($event, $list) { $list[] = $self; $event->setReturnValue($list); } Employee Four notifies the registered listener and provides the item to filter // EmployeeFour.class.php (at 5:00) $event = $this->dispatcher->filter(new sfEvent($this, 'employee_four.job_offering'), $list); $list = $event->getReturnValue();
  • 11. Utilizing Symfony Core Events Lazy-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”
  • 12. Utilizing Symfony Core Events Lazy-add mobile templates Connect to “filter parameters” event, add request format for the appropriate user agent // ProjectConfiguration.class.php public 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; }
  • 13. Utilizing Symfony Core Events Lazy-add mobile templates Connect to “view.configure_format” event to only set if the template exists // ProjectConfiguration.class.php public 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'); } } }
  • 14. Utilizing Symfony Core Events Lazy-add mobile templates Set our mobile format in factories.yml // factories.yml all: 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!
  • 15. Creating Your Own Events Alert System 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 // ProjectConfiguration.class.php public function setup() { ... include_once sfConfig::get('sf_lib_dir').'/alert/sfAlertDispatcher.class.php'; $this->alertDispatcher = new sfAlertDispatcher(); $this->alertDispatcher->connectEvents($this->dispatcher); }
  • 16. Creating Your Own Events Alert System Handle your events inside your model. Keep things modular. // 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')); } }
  • 17. Creating Your Own Events Alert System Write your implementation logic for the appropriate listeners // 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)); } } ... }
  • 18. Creating Your Own Events Alert System Add the logic in your application for triggering the events // 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.php public function close(sfEventDispatcher $dispatcher) { ... $dispatcher->notify(new sfEvent($this, 'support.ticket_closed')); }
  • 19. Creating Your Own Events Alert 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
  • 20. Questions? Brent Shaffer @bshaffer CentreSource Interactive Agency www.brentertainment.com 2010-05-01