|
Key
This line was removed.
This word was removed. This word was added.
This line was added.
|
Comment:
Changes (0)
View Page History{zone-template-instance:ZFDEV:Zend Proposal Zone Template}
{composition-setup}
{zone-data:component-name}
Zend_Notification
{zone-data}
{zone-data:proposer-list}
[Jurriën Stutterheim|mailto:j.stutterheim@hccnet.nl]
{zone-data}
{zone-data:revision}
1.4 - 11 march 2008: updated class skeletons and text
1.3 - 20 februari 2008: Updated link and added another usecase
1.2 - 3 January 2008: Added some use cases, operation description and updated skeletons
1.1 - 30 December 2007: Refactoring and renaming
1.0 - 29 December 2007: Setting up first draft
{zone-data}
{zone-data:overview}
Zend_Notification provides an infrastructure to relay messages between objects that don't necessarily know eachother.
This provides a loose coupling between components and makes your app more flexible.
An implementation of this proposal is available in [Zym|http://www.zym-project.com/].
{zone-data}
{zone-data:references}
* [Zym_Notification|http://svn2.assembla.com/svn/zym/trunk/library/Zym/]
* [Zym_Notification docs|http://www.zym-project.com/docs/manual/en/zym.notification.html]
* [Cocoa NSNotification documentation|http://developer.apple.com/documentation/Cocoa/Conceptual/Notifications/Introduction/introNotifications.html]
{zone-data}
{zone-data:requirements}
* This component *must* provide a clean, non-intrusive way to handle event notification
* *Must not* require existing classes to implement interfaces or extend classes for it to work
{zone-data}
{zone-data:dependencies}
* Zend_Exception
{zone-data}
{zone-data:operation}
The operation is very simple, but also very powerful. You can attach an object to a notification by calling the Notification's attach() method.
This method takes the observer and the name of the notification as argument. More than one object can register to the same notification.
When a notification is sent, all objects that subscribed to that notification will be notified in order of subscription.
By default the observer's notify() method will be called. You can also register another method when registering the observering at the notification center.
The Notification constructor takes three arguments (of which the last is optional). The first is the name of the notification. The second is (usually) the object than sent the notification.
The last argument is an array that allows for extra data to be sent along with the notification.
When attaching an observer to an event you can either use a string to attach it to just one event, or provide an array with multiple event names. (See usecase UC-02)
When you attach an observer to an event with an asterisk in the name, the asterisk will be used as wildcard. See usecase UC-03 for an example.
{zone-data}
{zone-data:milestones}
* Milestone 1: \[DONE\] finish this proposal
* Milestone 2: \[DONE\] write documentation
* Milestone 3: \[DONE\] write unit tests
* Milestone 4: get approval and move the component to incubator
* Milestone 5: finish component and move it to core
{zone-data}
{zone-data:class-list}
* Zend_Notification
* Zend_Notification_Message
* Zend_Notification_Registration
* Zend_Notification_Interface
* Zend_Notification_Exception
{zone-data}
{zone-data:use-cases}
{deck:id=Use Cases}
{card:label=UC-01: Basic usage}
{code}
class CoffeeShop_Customer
{
public function __construct()
{
$notification = Zend_Notification::get();
$notification->attach($this, CoffeeShop::PIE_READY) // Uses the default callback notify()
->attach($this, CoffeeShop::COFFEE_READY, 'drinkCoffee'); // Uses a custom callback
}
public function notify(Zend_Notification_Message $notification)
{
$sender = $notification->getSender();
$data = $notification->getData();
$pie = $data['pie'];
$pie->eat();
echo "Eating the pie...\n";
if ($sender instanceof CoffeeShop) {
$sender->recommendToFriends();
}
}
public function drinkCoffee(Zend_Notification_Message $notification)
{
$data = $notification->getData();
$coffee = $data['coffee'];
$coffee->drink();
echo "Drinking the coffee...\n";
}
}
class CoffeeShop
{
const COFFEE_READY = 'coffeeReady';
const PIE_READY = 'pieReady';
protected $_notification;
public function __construct()
{
$this->_notification = Zend_Notification::get();
}
public function bakePie()
{
$pie = new Pie();
while (!$pie->isDone()) {
$pie->bake();
}
$this->_notification->post(CoffeeShop::PIE_READY, $this, array('pie' => $pie));
}
public function makeCoffee()
{
$coffee = new Coffee();
$this->_notification->post(CoffeeShop::COFFEE_READY, $this, array('coffee' => $coffee));
}
public function recommendToFriends()
{
echo 'This place rocks!';
}
}
$customer = new CoffeeShop_Customer();
$coffeeShop = new CoffeeShop();
$coffeeShop->bakePie();
$coffeeShop->makeCoffee();
/*
This prints:
Eating the pie...
Drinking the coffee...
This place rocks!
*/
{code}
{card}
{card:label=UC-02: Register for multiple notifications}
{code}
class CoffeeShop_Customer
{
public function __construct()
{
$notification = Zend_Notification::get();
// Assumes both use the default callback
$notification->attach($this, array(CoffeeShop::PIE_READY, CoffeeShop::COFFEE_READY)); // Uses the default callback notify()
}
// Rest of the code here ...
}
{code}
{card}
{card:label=UC-03: Wildcards}
{code}
class CoffeeShop_Customer
{
public function __construct()
{
$notification = Zend_Notification::get();
// Attaches the customer to all event starting with foo e.g. fooBar, fooBaz etc.
$notification->attach($this, 'foo*'); // Uses the default callback notify()
}
// Rest of the code here ...
}
{code}
{card}
{card:label=UC-04: Intergrated in Zend_Controller_Front::dispatch()}
{code}
/** Front Controller **/
$notification = Zend_Notification::get();
/**
* Notify plugins of router startup
*/
$this->_plugins->routeStartup($this->_request);
$notification->post('FCRouteStartup', $this, array('request' => $this->_request));
$router->route($this->_request);
/**
* Notify plugins of router completion
*/
$this->_plugins->routeShutdown($this->_request);
$notification->post('FCRouteShutdown', $this, array('request' => $this->_request));
/**
* Notify plugins of dispatch loop startup
*/
$this->_plugins->dispatchLoopStartup($this->_request);
$notification->post('FCDispatchLoopStartup', $this, array('request' => $this->_request));
/**
* Attempt to dispatch the controller/action. If the $this->_request
* indicates that it needs to be dispatched, move to the next
* action in the request.
*/
do {
$this->_request->setDispatched(true);
/**
* Notify plugins of dispatch startup
*/
$this->_plugins->preDispatch($this->_request);
$notification->post('FCPreDispatch', $this, array('request' => $this->_request));
/**
* Skip requested action if preDispatch() has reset it
*/
if (!$this->_request->isDispatched()) {
continue;
}
/**
* Dispatch request
*/
try {
$dispatcher->dispatch($this->_request, $this->_response);
} catch (Exception $e) {
if ($this->throwExceptions()) {
throw $e;
}
$this->_response->setException($e);
}
/**
* Notify plugins of dispatch completion
*/
$this->_plugins->postDispatch($this->_request);
$notification->post('FCPostDispatch', $this, array('request' => $this->_request));
} while (!$this->_request->isDispatched());
} catch (Exception $e) {
if ($this->throwExceptions()) {
throw $e;
}
$this->_response->setException($e);
}
/**
* Notify plugins of dispatch loop completion
*/
try {
$this->_plugins->dispatchLoopShutdown();
$notification->post('FCDispatchLoopShutdown', $this, array('request' => $this->_request));
} catch (Exception $e) {
if ($this->throwExceptions()) {
throw $e;
}
$this->_response->setException($e);
}
/** A plugin or other script that responds to the postDispatch notification **/
class MyLogger
{
public function __construct()
{
$notification = Zend_Notification::get();
// Assumes both use the default callback
$notification->attach($this, 'FCPostDispatch'); // Uses the default callback notify()
}
public function notify()
{
MyLog::writeLine('Another postDispatch has been fired! \o/');
}
}
{code}
{card}
{deck}
{zone-data}
{zone-data:skeletons}
{deck:id=Class Skeletons}
{card:label=Zend_Notification_Interface}
{code}
interface Zend_Notification_Interface
{
/**
* Notify the observer by passing the Zend_Notification instance
*
* @param Zend_Notification_Message $notification
*/
public function notify(Zend_Notification_Message $notification);
}
{code}
{card}
{card:label=Zend_Notification_Registration}
{code}
class Zend_Notification_Registration
{
/**
* @var object
*/
protected $_observer = null;
/**
* @var string
*/
protected $_callback = null;
/**
* Constructor
*
* @param object $observer
* @param string $callback
*/
public function __construct($observer, $callback)
{
}
/**
* Get the observer
*
* @return object
*/
public function getObserver()
{
}
/**
* Get the name of the callback method
*
* @return string
*/
public function getCallback()
{
}
}
{code}
{card}
{card:label=Zend_Notification_Message}
{code}
class Zend_Notification_Message
{
/**
* Notification name
*
* @var string
*/
protected $_name;
/**
* The object that sent the notification
*
* @var object
*/
protected $_sender;
/**
* Optional objects
*
* @var array
*/
protected $_data = array();
/**
* Constructor
*
* @param string $name
* @param object $sender
* @param array $data
*/
public function __construct($name, $sender, array $data = array())
{
}
/**
* Get notification name
*
* @return string
*/
public function getName()
{
}
/**
* Get the object that sent the notification
*
* @return object
*/
public function getSender()
{
}
/**
* Get the optional information
*
* @return array
*/
public function getData()
{
}
}
{code}
{card}
{card:label=Zend_Notification}
{code}
class Zend_Notification
{
/**
* The default callback method name
*
* @var string
*/
protected $_defaultCallback = 'notify';
/**
* Wildcard for the catch-all event
*
* @var string
*/
protected $_wildcard = '*';
/**
* The collection of objects that registered to notifications
*
* @var array
*/
protected $_observers = array();
/**
* Singleton instance
*
* @var array
*/
protected static $_instances = array();
/**
* Get a notification instance from the internal registry
*
* @param string name
* @return Zend_Notification
*/
public static function get($namespace = 'default')
{
}
/**
* Remove a notification instance from the internal registry
*
* @param string $name
*/
public static function remove($namespace)
{
}
/**
* Check if the namespace is already set
*
* @return boolean
*/
public static function has($namespace)
{
}
/**
* Singleton constructor
*
*/
protected function __construct()
{
}
/**
* Get the wildcard
*
* @return string
*/
public function getWildcard()
{
}
/**
* Post a notification
*
* @param string $name
* @param object $sender
* @param array $data
* @return Zend_Notification
*/
public function post($name, $sender = null, array $data = array())
{
}
/**
* Post the notification
*
* @param Zend_Notification_Message $message
* @param Zend_Notification_Registration $observerData
*/
protected function _postNotification(Zend_Notification_Message $message, Zend_Notification_Registration $registration)
{
}
/**
* Register an observer for the specified notification
*
* @param object $observer
* @param string|array $events
* @param string $callback
* @return Zend_Notification
*/
public function attach($observer, $events = null, $callback = null)
{
}
/**
* Remove an observer
*
* @param object $observer
* @param string|array $event
* @return Zend_Notification
*/
public function detach($observer, $events = null)
{
}
/**
* Clear an event.
* If no event is specified all events will be cleared.
*
* @param string $event
* @return Zend_Notification
*/
public function reset($event = null)
{
}
/**
* Check if an event is registered
*
* @param string $event
* @return boolean
*/
public function isRegistered($event)
{
}
/**
* Check if the observer is registered for the specified event
*
* @param object|string &$observer either spl_object_hash or the object itself
* @param string $event
* @return boolean
*/
public function hasObserver(&$observer, $event)
{
}
}
{code}
{card}
{card:label=Zend_Notification_Exception}
{code}
class Zend_Notification_Exception extends Zend_Exception
{
}
{code}
{card}
{zone-data}
{zone-template-instance}