Event_Dispatcher
[ class tree: Event_Dispatcher ] [ index: Event_Dispatcher ] [ all elements ]

Source for file Dispatcher.php

Documentation is available at Dispatcher.php

  1. <?php
  2. // +-----------------------------------------------------------------------+
  3. // | Copyright (c) 2005, Bertrand Mansion                                  |
  4. // | All rights reserved.                                                  |
  5. // |                                                                       |
  6. // | Redistribution and use in source and binary forms, with or without    |
  7. // | modification, are permitted provided that the following conditions    |
  8. // | are met:                                                              |
  9. // |                                                                       |
  10. // | o Redistributions of source code must retain the above copyright      |
  11. // |   notice, this list of conditions and the following disclaimer.       |
  12. // | o Redistributions in binary form must reproduce the above copyright   |
  13. // |   notice, this list of conditions and the following disclaimer in the |
  14. // |   documentation and/or other materials provided with the distribution.|
  15. // | o The names of the authors may not be used to endorse or promote      |
  16. // |   products derived from this software without specific prior written  |
  17. // |   permission.                                                         |
  18. // |                                                                       |
  19. // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   |
  20. // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT     |
  21. // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
  22. // | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT  |
  23. // | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
  24. // | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT      |
  25. // | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
  26. // | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
  27. // | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT   |
  28. // | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
  29. // | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  |
  30. // |                                                                       |
  31. // +-----------------------------------------------------------------------+
  32. // | Author: Bertrand Mansion <bmansion@mamasam.com>                       |
  33. // |         Stephan Schmidt <schst@php.net>                               |
  34. // +-----------------------------------------------------------------------+
  35. //
  36. // $Id: Dispatcher.php 284686 2009-07-24 05:22:17Z clockwerx $
  37.  
  38. require_once 'Event/Notification.php';
  39.  
  40. /**
  41.  * Pseudo 'static property' for Notification object
  42.  * @global array $GLOBALS["_Event_Dispatcher"] 
  43.  */
  44. $GLOBALS['_Event_Dispatcher'= array(
  45.                                   'NotificationClass' => 'Event_Notification'
  46.                                      );
  47.  
  48. /**
  49.  * Registers a global observer
  50.  */
  51. define('EVENT_DISPATCHER_GLOBAL''');
  52.  
  53. /**
  54.  * Dispatch notifications using PHP callbacks
  55.  *
  56.  * The Event_Dispatcher acts acts as a notification dispatch table.
  57.  * It is used to notify other objects of interesting things, if
  58.  * they meet certain criteria. This information is encapsulated
  59.  * in {@link Event_Notification} objects. Client objects register
  60.  * themselves with the Event_Dispatcher as observers of specific
  61.  * notifications posted by other objects. When an event occurs,
  62.  * an object posts an appropriate notification to the Event_Dispatcher.
  63.  * The Event_Dispatcher dispatches a message to each
  64.  * registered observer, passing the notification as the sole argument.
  65.  *
  66.  * The Event_Dispatcher is actually a combination of three design
  67.  * patterns: the Singleton, {@link http://c2.com/cgi/wiki?MediatorPattern Mediator},
  68.  * and Observer patterns. The idea behind Event_Dispatcher is borrowed from
  69.  * {@link http://developer.apple.com/documentation/Cocoa/Conceptual/Notifications/index.html Apple's Cocoa framework}.
  70.  *
  71.  * @category   Event
  72.  * @package    Event_Dispatcher
  73.  * @author     Bertrand Mansion <bmansion@mamasam.com>
  74.  * @author     Stephan Schmidt <schst@php.net>
  75.  * @copyright  1997-2005 The PHP Group
  76.  * @license    http://www.opensource.org/licenses/bsd-license.php BSD License
  77.  * @version    Release: @package_version@
  78.  * @link       http://pear.php.net/package/Event_Dispatcher
  79.  */
  80. {
  81.     /**
  82.      * Registered observer callbacks
  83.      * @var array 
  84.      * @access private
  85.      */
  86.     var $_ro = array();
  87.     
  88.     /**
  89.      * Pending notifications
  90.      * @var array 
  91.      * @access private
  92.      */
  93.     var $_pending = array();
  94.  
  95.     /**
  96.      * Nested observers
  97.      * @var array 
  98.      * @access private
  99.      */
  100.     var $_nestedDispatchers = array();
  101.  
  102.     /**
  103.      * Name of the dispatcher
  104.      * @var string 
  105.      * @access private
  106.      */
  107.     var $_name = null;
  108.  
  109.     /**
  110.      * Class used for notifications
  111.      * @var string 
  112.      * @access private
  113.      */
  114.     var $_notificationClass = null;
  115.  
  116.     /**
  117.      * PHP4 constructor
  118.      *
  119.      * Please use {@link getInstance()} instead.
  120.      *
  121.      * @access  private
  122.      * @param   string      Name of the notification dispatcher.
  123.      */
  124.     function Event_Dispatcher($name)
  125.     {
  126.         Event_Dispatcher::__construct($name);
  127.     }
  128.  
  129.     /**
  130.      * PHP5 constructor
  131.      *
  132.      * Please use {@link getInstance()} instead.
  133.      *
  134.      * @access  private
  135.      * @param   string      Name of the notification dispatcher.
  136.      */
  137.     function __construct($name)
  138.     {
  139.         $this->_name $name;
  140.         $this->_notificationClass $GLOBALS['_Event_Dispatcher']['NotificationClass'];
  141.     }
  142.  
  143.     /**
  144.      * Returns a notification dispatcher singleton
  145.      *
  146.      * There is usually no need to have more than one notification
  147.      * center for an application so this is the recommended way
  148.      * to get a Event_Dispatcher object.
  149.      *
  150.      * @param string    Name of the notification dispatcher.
  151.      *                   The default notification dispatcher is named __default.
  152.      * 
  153.      * @return object Event_Dispatcher 
  154.      */
  155.     function &getInstance($name '__default')
  156.     {
  157.         static $dispatchers = array();
  158.  
  159.         if (!isset($dispatchers[$name])) {
  160.             $dispatchers[$name= new Event_Dispatcher($name);
  161.         }
  162.  
  163.         return $dispatchers[$name];
  164.     }
  165.  
  166.     /**
  167.      * Registers an observer callback
  168.      *
  169.      * This method registers a {@link http://www.php.net/manual/en/language.pseudo-types.php#language.types.callback callback}
  170.      * which is called when the notification corresponding to the
  171.      * criteria given at registration time is posted.
  172.      * The criteria are the notification name and eventually the
  173.      * class of the object posted with the notification.
  174.      *
  175.      * If there are any pending notifications corresponding to the criteria
  176.      * given here, the callback will be called straight away.
  177.      *
  178.      * If the notification name is empty, the observer will receive all the
  179.      * posted notifications. Same goes for the class name.
  180.      *
  181.      * @access  public
  182.      * @param   mixed       A PHP callback
  183.      * @param   string      Expected notification name, serves as a filter
  184.      * @param   string      Expected contained object class, serves as a filter
  185.      * @return void 
  186.      */
  187.     function addObserver($callback$nName = EVENT_DISPATCHER_GLOBAL$class = null)
  188.     {
  189.         if (is_array($callback)) {
  190.             if (is_object($callback[0])) {
  191.                 // Note : PHP4 does not allow correct object comparison so
  192.                 // only the class name is used for registration checks.
  193.                 $reg get_class($callback[0]).'::'.$callback[1];
  194.             else {
  195.                 $reg $callback[0].'::'.$callback[1];
  196.             }
  197.         else {
  198.             $reg $callback;
  199.         }
  200.  
  201.         $this->_ro[$nName][$reg= array(
  202.                                     'callback' => $callback,
  203.                                     'class'    => $class
  204.                                     );
  205.  
  206.         // Post eventual pending notifications for this observer
  207.         if (isset($this->_pending[$nName])) {
  208.             foreach (array_keys($this->_pending[$nName]as $k{
  209.                 $notification =$this->_pending[$nName][$k];
  210.                 if (!$notification->isNotificationCancelled()) {
  211.                     $objClass get_class($notification->getNotificationObject());
  212.                     if (empty($class|| strcasecmp($class$objClass== 0{
  213.                         call_user_func_array($callbackarray(&$notification));
  214.                         $notification->increaseNotificationCount();
  215.                     }
  216.                 }
  217.             }
  218.         }
  219.     }
  220.  
  221.     /**
  222.      * Creates and posts a notification object
  223.      *
  224.      * The purpose of the optional associated object is generally to pass
  225.      * the object posting the notification to the observers, so that the
  226.      * observers can query the posting object for more information about
  227.      * the event.
  228.      *
  229.      * Notifications are by default added to a pending notification list.
  230.      * This way, if an observer is not registered by the time they are
  231.      * posted, it will still be notified when it is added as an observer.
  232.      * This behaviour can be turned off in order to make sure that only
  233.      * the registered observers will be notified.
  234.      *
  235.      * The info array serves as a container for any kind of useful
  236.      * information. It is added to the notification object and posted along.
  237.      *
  238.      * @access  public
  239.      * @param   object      Notification associated object
  240.      * @param   string      Notification name
  241.      * @param   array       Optional user information
  242.      * @param   bool        Whether the notification is pending
  243.      * @param   bool        Whether you want the notification to bubble up
  244.      * @return  object  The notification object
  245.      */
  246.     function &post(&$object$nName$info = array()$pending = true$bubble = true)
  247.     {
  248.         $notification =new $this->_notificationClass($object$nName$info);
  249.         return $this->postNotification($notification$pending$bubble);
  250.     }
  251.  
  252.     /**
  253.      * Posts the {@link Event_Notification} object
  254.      *
  255.      * @access  public
  256.      * @param   object      The Notification object
  257.      * @param   bool        Whether to post the notification immediately
  258.      * @param   bool        Whether you want the notification to bubble up
  259.      * @see Event_Dispatcher::post()
  260.      * @return  object  The notification object
  261.      */
  262.     function &postNotification(&$notification$pending = true$bubble = true)
  263.     {
  264.         $nName $notification->getNotificationName();
  265.         if ($pending === true{
  266.             $this->_pending[$nName][=$notification;
  267.         }
  268.         $objClass get_class($notification->getNotificationObject());
  269.  
  270.         // Find the registered observers
  271.         if (isset($this->_ro[$nName])) {
  272.             foreach (array_keys($this->_ro[$nName]as $k{
  273.                 $rObserver =$this->_ro[$nName][$k];
  274.                 if ($notification->isNotificationCancelled()) {
  275.                     return $notification;
  276.                 }
  277.                 if (empty($rObserver['class']||
  278.                     strcasecmp($rObserver['class']$objClass== 0{
  279.                     call_user_func_array($rObserver['callback']array(&$notification));
  280.                     $notification->increaseNotificationCount();
  281.                 }
  282.             }
  283.         }
  284.  
  285.         // Notify globally registered observers
  286.         if (isset($this->_ro[EVENT_DISPATCHER_GLOBAL])) {
  287.             foreach (array_keys($this->_ro[EVENT_DISPATCHER_GLOBAL]as $k{
  288.                 $rObserver =$this->_ro[EVENT_DISPATCHER_GLOBAL][$k];
  289.                 if ($notification->isNotificationCancelled()) {
  290.                     return $notification;
  291.                 }
  292.                 if (empty($rObserver['class']|| 
  293.                     strcasecmp($rObserver['class']$objClass== 0{
  294.                     call_user_func_array($rObserver['callback']array(&$notification));
  295.                     $notification->increaseNotificationCount();
  296.                 }
  297.             }
  298.         }
  299.  
  300.         if ($bubble === false{
  301.             return $notification;
  302.         }
  303.         
  304.         // Notify in nested dispatchers
  305.         foreach (array_keys($this->_nestedDispatchersas $nested{
  306.             $notification =$this->_nestedDispatchers[$nested]->postNotification($notification$pending);
  307.         }
  308.  
  309.         return $notification;
  310.     }
  311.  
  312.     /**
  313.      * Removes a registered observer that correspond to the given criteria
  314.      *
  315.      * @access  public
  316.      * @param   mixed       A PHP callback
  317.      * @param   string      Notification name
  318.      * @param   string      Contained object class
  319.      * @return  bool    True if an observer was removed, false otherwise
  320.      */
  321.     function removeObserver($callback$nName = EVENT_DISPATCHER_GLOBAL$class = null)
  322.     {
  323.         if (is_array($callback)) {
  324.             if (is_object($callback[0])) {
  325.                 $reg get_class($callback[0]).'::'.$callback[1];
  326.             else {
  327.                 $reg $callback[0].'::'.$callback[1];
  328.             }
  329.         else {
  330.             $reg $callback;
  331.         }
  332.  
  333.         $removed = false;
  334.         if (isset($this->_ro[$nName][$reg])) {
  335.             if (!empty($class)) {
  336.                 if (strcasecmp($this->_ro[$nName][$reg]['class']$class== 0{
  337.                     unset($this->_ro[$nName][$reg]);
  338.                     $removed = true;
  339.                 }
  340.             else {
  341.                 unset($this->_ro[$nName][$reg]);
  342.                 $removed = true;
  343.             }
  344.         }
  345.  
  346.         if (isset($this->_ro[$nName]&& count($this->_ro[$nName]== 0{
  347.             unset($this->_ro[$nName]);
  348.         }
  349.         return $removed;
  350.     }
  351.  
  352.    /**
  353.     * Check, whether the specified observer has been registered with the
  354.     * dispatcher
  355.     *
  356.      * @access  public
  357.      * @param   mixed       A PHP callback
  358.      * @param   string      Notification name
  359.      * @param   string      Contained object class
  360.      * @return  bool        True if the observer has been registered, false otherwise
  361.     */
  362.     function observerRegistered($callback$nName = EVENT_DISPATCHER_GLOBAL$class = null)
  363.     {
  364.         if (is_array($callback)) {
  365.             if (is_object($callback[0])) {
  366.                 $reg get_class($callback[0]).'::'.$callback[1];
  367.             else {
  368.                 $reg $callback[0].'::'.$callback[1];
  369.             }
  370.         else {
  371.             $reg $callback;
  372.         }
  373.  
  374.         if (!isset($this->_ro[$nName][$reg])) {
  375.             return false;
  376.         }
  377.         if (empty($class)) {
  378.             return true;
  379.         }
  380.         if (strcasecmp($this->_ro[$nName][$reg]['class']$class== 0{
  381.             return true;
  382.         }
  383.         return false;
  384.     }
  385.  
  386.    /**
  387.     * Get all observers, that have been registered for a notification
  388.     *
  389.      * @access  public
  390.      * @param   string      Notification name
  391.      * @param   string      Contained object class
  392.      * @return  array       List of all observers
  393.     */
  394.     function getObservers($nName = EVENT_DISPATCHER_GLOBAL$class = null)
  395.     {
  396.         $observers = array();        
  397.         if (!isset($this->_ro[$nName])) {
  398.             return $observers;
  399.         }
  400.         foreach ($this->_ro[$nNameas $reg => $observer{
  401.             if ($class == null || $observer['class'== null ||  strcasecmp($observer['class']$class== 0{
  402.                 $observers[$reg;
  403.             }
  404.         }
  405.         return $observers;
  406.     }
  407.     
  408.     /**
  409.      * Get the name of the dispatcher.
  410.      *
  411.      * The name is the unique identifier of a dispatcher.
  412.      *
  413.      * @access   public
  414.      * @return   string     name of the dispatcher
  415.      */
  416.     function getName()
  417.     {
  418.         return $this->_name;
  419.     }
  420.  
  421.     /**
  422.      * add a new nested dispatcher
  423.      *
  424.      * Notifications will be broadcasted to this dispatcher as well, which
  425.      * allows you to create event bubbling.
  426.      *
  427.      * @access   public
  428.      * @param    Event_Dispatcher    The nested dispatcher
  429.      */
  430.     function addNestedDispatcher(&$dispatcher)
  431.     {
  432.         $name $dispatcher->getName();
  433.         $this->_nestedDispatchers[$name=$dispatcher;
  434.     }
  435.  
  436.    /**
  437.     * remove a nested dispatcher
  438.     *
  439.     * @access   public
  440.     * @param    Event_Dispatcher    Dispatcher to remove
  441.     * @return   boolean 
  442.     */
  443.     function removeNestedDispatcher($dispatcher)
  444.     {
  445.         if (is_object($dispatcher)) {
  446.             $dispatcher $dispatcher->getName();
  447.         }
  448.         if (!isset($this->_nestedDispatchers[$dispatcher])) {
  449.             return false;
  450.         }
  451.         unset($this->_nestedDispatchers[$dispatcher]);
  452.         return true;
  453.     }
  454.  
  455.     /**
  456.      * Changes the class used for notifications
  457.      *
  458.      * You may call this method on an object to change it for a single
  459.      * dispatcher or statically, to set the default for all dispatchers
  460.      * that will be created.
  461.      *
  462.      * @access   public
  463.      * @param    string     name of the notification class
  464.      * @return   boolean 
  465.      */
  466.     function setNotificationClass($class)
  467.     {
  468.         if (isset($this&& is_a($this'Event_Dispatcher')) {
  469.             $this->_notificationClass $class;
  470.             return true;
  471.         }
  472.         $GLOBALS['_Event_Dispatcher']['NotificationClass'$class;
  473.         return true;
  474.     }
  475.  
  476. }
  477. ?>

Documentation generated on Mon, 11 Mar 2019 15:32:31 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.