Don't attach events to listeners by default (attach when notify() is
authorMichael M Slusarz <slusarz@curecanti.org>
Tue, 9 Feb 2010 03:52:45 +0000 (20:52 -0700)
committerMichael M Slusarz <slusarz@curecanti.org>
Tue, 9 Feb 2010 04:31:26 +0000 (21:31 -0700)
called on a listener).

Remove _initNotification() workaround.
Since the notification system no longer attaches events to listeners
until notify() is called, it is safe to change notification listeners as
needed directly within _init() calls.

framework/Core/lib/Horde/Registry.php
framework/Core/lib/Horde/Registry/Application.php
framework/Notification/lib/Horde/Notification/Handler/Base.php
imp/lib/Application.php
kronolith/lib/Application.php
nag/lib/Application.php

index d629be2..8b4583b 100644 (file)
@@ -232,6 +232,7 @@ class Horde_Registry
         $injector->addBinder('Horde_Template', new Horde_Core_Binder_Template());
         $injector->addBinder('Net_DNS_Resolver', new Horde_Core_Binder_Dns());
 
+        $GLOBALS['registry'] = $this;
         $injector->setInstance('Horde_Registry', $this);
 
         /* Initialize browser object. */
@@ -314,11 +315,10 @@ class Horde_Registry
         $GLOBALS['perms'] = Horde_Perms::singleton();
         $injector->setInstance('Horde_Perms', $GLOBALS['perms']);
 
-        /**
-         * Initialize notification object.
-         * No listeners are attached at this point.
-         */
+        /* Initialize notification object. Always attach status listener by
+         * default. */
         $GLOBALS['notification'] = Horde_Notification::singleton();
+        $GLOBALS['notification']->attach('status');
         $injector->setInstance('Horde_Notification', $GLOBALS['notification']);
     }
 
index c5c6446..1ed11be 100644 (file)
@@ -77,7 +77,6 @@ class Horde_Registry_Application
             }
 
             $this->_init();
-            $this->_initNotification($GLOBALS['notification']);
         }
     }
 
@@ -89,17 +88,4 @@ class Horde_Registry_Application
     {
     }
 
-    /**
-     * Initialization for Notification system.
-     * This is run after _init() is called so app-specific code can appear
-     * inside.
-     *
-     * @param Horde_Notification_Handler_Base $notify  The notification
-     *                                                 object.
-     */
-    protected function _initNotification($notify)
-    {
-        $notify->attach('status');
-    }
-
 }
index dfb27a0..2238137 100644 (file)
@@ -90,8 +90,7 @@ implements Horde_Notification_Handler_Interface
     }
 
     /**
-     * Remove a listener from the notification list. This will discard any
-     * notifications in this listeners stack.
+     * Remove a listener from the notification list.
      *
      * @param string $listner  The name of the listener to detach.
      *
@@ -100,49 +99,73 @@ implements Horde_Notification_Handler_Interface
     public function detach($listener)
     {
         $listener = Horde_String::lower(basename($listener));
-        if (!isset($this->_listeners[$listener])) {
+        if (isset($this->_listeners[$listener])) {
+            unset($this->_listeners[$listener]);
+        } else {
             throw new Horde_Exception(sprintf('Notification listener %s not found.', $listener));
         }
-
-        $instance = $this->_listeners[$listener];
-        unset($this->_listeners[$listener]);
-        $this->_storage->clear($instance->getName());
     }
 
     /**
-     * Replaces a listener in the notification list. This preserves all
-     * notifications in this listeners stack. If the listener does not exist,
-     * the new listener will be added automatically.
+     * Replaces a listener in the notification list. If the listener does not
+     * exist, the new listener will be added automatically.
      *
      * @param string $listener  See attach().
      * @param array $params     See attach().
      * @param string $class     See attach().
      *
-     * @return Horde_Notification_Listener  See attach()
-     * @throws Horde_Exception
+     * @return Horde_Notification_Listener  See attach().
      */
     public function replace($listener, array $params = array(), $class = null)
     {
-        $listener = Horde_String::lower(basename($listener));
-        unset($this->_listeners[$listener]);
+        try {
+            $this->detach($listener);
+        } catch (Horde_Exception $e) {}
+
         return $this->attach($listener, $params, $class);
     }
 
     /**
+     * Clear any notification events that may exist in a listener.
+     *
+     * @param string $listener  The name of the listener to flush. If null,
+     *                          clears all unattached events.
+     */
+    public function clear($listener = null)
+    {
+        if (is_null($listener)) {
+            $this->_storage->clear('_unattached');
+        } else {
+            $listener = Horde_String::lower(basename($listener));
+            if (isset($this->_listeners[$listener])) {
+                $this->_storage->clear($this->_listeners[$listener]->getName());
+            }
+        }
+    }
+
+    /**
      * Add an event to the Horde message stack.
      *
      * The event type parameter should begin with 'horde.' unless the
      * application defines its own Horde_Notification_Listener subclass that
      * handles additional codes.
      *
-     * @param mixed $event   Horde_Notification_Event object or message string.
-     * @param integer $type  The type of message: 'horde.error',
-     *                       'horde.warning', 'horde.success', or
-     *                       'horde.message'.
-     * @param array $flags   Array of optional flags that will be passed to the
-     *                       registered listeners.
+     * @param mixed $event    Horde_Notification_Event object or message
+     *                        string.
+     * @param integer $type   The type of message.
+     * @param array $flags    Array of optional flags that will be passed to
+     *                        the registered listeners.
+     * @param array $options  Additional options:
+     * <pre>
+     * 'immediate' - (boolean) If true, immediately tries to attach to a
+     *               listener. If no listener exists for this type, the
+     *               message will be dropped.
+     *               DEFAULT: false (message will be attached to available
+     *               handler at the time notify() is called).
+     * </pre>
      */
-    public function push($event, $type = null, array $flags = array())
+    public function push($event, $type = null, array $flags = array(),
+                         $options = array())
     {
         if ($event instanceof Horde_Notification_Event) {
             $event->flags = $flags;
@@ -152,9 +175,13 @@ implements Horde_Notification_Handler_Interface
             $event = new Horde_Notification_Event($event, $type, $flags);
         }
 
-        foreach ($this->_listeners as $listener) {
-            if ($listener->handles($event->type)) {
-                $this->_storage->push($listener->getName(), $event);
+        if (empty($options['immediate'])) {
+            $this->_storage->push('_unattached', $event);
+        } else {
+            foreach ($this->_listeners as $listener) {
+                if ($listener->handles($event->type)) {
+                    $this->_storage->push($listener->getName(), $event);
+                }
             }
         }
     }
@@ -207,11 +234,30 @@ implements Horde_Notification_Handler_Interface
      */
     public function notifyListeners(array $options)
     {
+        $unattached = $this->_storage->exists('_unattached')
+            ? $this->_storage->get('_unattached')
+            : array();
+
         foreach ($options['listeners'] as $listener) {
             if (isset($this->_listeners[$listener])) {
-                $this->_listeners[$listener]->notify($this->_storage->get($this->_listeners[$listener]->getName()), $options);
+                $instance = $this->_listeners[$listener];
+
+                foreach (array_keys($unattached) as $val) {
+                    if ($instance->handles($unattached[$val]->type)) {
+                        $this->_storage->push($instance->getName(), $unattached[$val]);
+                        unset($unattached[$val]);
+                    }
+                }
+
+                $instance->notify($this->_storage->get($instance->getName()), $options);
             }
         }
+
+        if (empty($unattached)) {
+            $this->_storage->clear('_unattached');
+        } else {
+            $this->_storage->set('_unattached', $unattached);
+        }
     }
 
     /**
@@ -225,17 +271,18 @@ implements Horde_Notification_Handler_Interface
      */
     public function count($my_listener = null)
     {
-        if (is_null($my_listener)) {
-            $count = 0;
-            foreach ($this->_listeners as $listener) {
-                if ($this->_storage->exists($listener->getName())) {
-                    $count += count($this->_storage->get($listener->getName()));
-                }
+        if (!is_null($my_listener)) {
+            return @count($this->_storage->get($this->_listeners[Horde_String::lower($my_listener)]->getName()));
+        }
+
+        $count = 0;
+        foreach (array_merge($this->_listeners, array('_unattached')) as $val) {
+            if ($this->_storage->exists($val->getName())) {
+                $count += count($this->_storage->get($val->getName()));
             }
-            return $count;
         }
 
-        return @count($this->_storage->get($this->_listeners[Horde_String::lower($my_listener)]->getName()));
+        return $count;
     }
 
 }
index 1764571..11b6cce 100644 (file)
@@ -87,13 +87,8 @@ class IMP_Application extends Horde_Registry_Application
      * Global variables defined:
      *   $imp_imap     - An IMP_Imap object
      *   $imp_mbox     - Current mailbox information
+     *   $imp_notify   - A Horde_Notification_Listener object
      *   $imp_search   - An IMP_Search object
-     *
-     * When calling Horde_Registry::appInit(), the following parameters are
-     * also supported:
-     * <pre>
-     * 'tz' - (boolean) If true, sets the current time zone on the server.
-     * </pre>
      */
     protected function _init()
     {
@@ -111,27 +106,14 @@ class IMP_Application extends Horde_Registry_Application
         // Initialize global $imp_mbox array. This call also initializes the
         // IMP_Search object.
         IMP::setCurrentMailboxInfo();
-    }
 
-    /**
-     * Initialization for Notification system.
-     *
-     * Global variables defined:
-     *   $imp_notify   - A Horde_Notification_Listener object
-     *
-     * @param Horde_Notification_Handler_Base $notify  The notification
-     *                                                 object.
-     */
-    protected function _initNotification($notify)
-    {
         $viewmode = IMP::getViewMode();
-
         if ($viewmode == 'mimp') {
-            $GLOBALS['imp_notify'] = $notify->attach('status', null, 'IMP_Notification_Listener_StatusMobile');
+            $GLOBALS['imp_notify'] = $GLOBALS['notification']->replace('status', array(), 'IMP_Notification_Listener_StatusMobile');
         } else {
-            $GLOBALS['imp_notify'] = $notify->attach('status', array('viewmode' => $viewmode), 'IMP_Notification_Listener_Status');
+            $GLOBALS['imp_notify'] = $GLOBALS['notification']->replace('status', array('viewmode' => $viewmode), 'IMP_Notification_Listener_Status');
             if ($viewmode == 'imp') {
-                $notify->attach('audio');
+                $GLOBALS['notification']->attach('audio');
             }
         }
     }
index 2e3a96a..53ca8c9 100644 (file)
@@ -45,6 +45,7 @@ class Kronolith_Application extends Horde_Registry_Application
      * Initialization function.
      *
      * Global variables defined:
+     *   $kronolith_notify - A Horde_Notification_Listener object.
      *   $kronolith_shares - TODO
      */
     protected function _init()
@@ -64,20 +65,8 @@ class Kronolith_Application extends Horde_Registry_Application
         $GLOBALS['kronolith_shares'] = Horde_Share::singleton($GLOBALS['registry']->getApp());
 
         Kronolith::initialize();
-    }
 
-    /**
-     * Initialization for Notification system.
-     *
-     * Global variables defined:
-     *   $kronolith_notify - A Horde_Notification_Listener object.
-     *
-     * @param Horde_Notification_Handler_Base $notify  The notification
-     *                                                 object.
-     */
-    protected function _initNotification($notify)
-    {
-        $GLOBALS['kronolith_notify'] = $notify->attach('status', null, 'Kronolith_Notification_Listener_Status');
+        $GLOBALS['kronolith_notify'] = $GLOBALS['notification']->replace('status', array(), 'Kronolith_Notification_Listener_Status');
     }
 
     /**
index acdc5f8..4a5690c 100644 (file)
@@ -47,27 +47,15 @@ class Nag_Application extends Horde_Registry_Application
      */
     protected function _init()
     {
-       // Set the timezone variable.
-       Horde_Nls::setTimeZone();
+        // Set the timezone variable.
+        Horde_Nls::setTimeZone();
 
-       // Create a share instance.
-       $GLOBALS['nag_shares'] = Horde_Share::singleton($GLOBALS['registry']->getApp());
+        // Create a share instance.
+        $GLOBALS['nag_shares'] = Horde_Share::singleton($GLOBALS['registry']->getApp());
 
-       Nag::initialize();
-    }
+        Nag::initialize();
 
-    /**
-     * Initialization for Notification system.
-     *
-     * Global variables defined:
-     *   $kronolith_notify - A Horde_Notification_Listener object.
-     *
-     * @param Horde_Notification_Handler_Base $notify  The notification
-     *                                                 object.
-     */
-    protected function _initNotification($notify)
-    {
-        $notify->attach('status', null, 'Nag_Notification_Listener_Status');
+        $GLOBALS['notification']->replace('status', array(), 'Nag_Notification_Listener_Status');
     }
 
     /**