* @license New BSD {@link http://www.opensource.org/licenses/bsd-license.php} */ /** * Phly_PubSub_Provider: per-instance Publish-Subscribe system * * Use Phly_PubSub_Provider when you want to create a per-instance plugin * system for your objects. * * @package Phly_PubSub * @version $Id: $ */ class Phly_PubSub_Provider { /** * Subscribed topics and their handles */ protected $_topics = array(); /** * Publish to all handlers for a given topic * * @param string $topic * @param mixed $argv All arguments besides the topic are passed as arguments to the handler * @return void */ public function publish($topic, $argv = null) { if (empty($this->_topics[$topic])) { return; } $return = null; $argv = func_get_args(); array_shift($argv); foreach ($this->_topics[$topic] as $handle) { $return = $handle->call($argv); } return $return; } /** * Notify subscribers until return value of one causes a callback to * evaluate to true * * Publishes subscribers until the provided callback evaluates the return * value of one as true, or until all subscribers have been executed. * * @param Callable $callback * @param string $topic * @param mixed $argv All arguments besides the topic are passed as arguments to the handler * @return mixed * @throws Phly_PubSub_InvalidCallbackException if invalid callback provided */ public function publishUntil($callback, $topic, $argv = null) { if (!is_callable($callback)) { throw new Phly_PubSub_InvalidCallbackException('Invalid filter callback provided'); } if (empty($this->_topics[$topic])) { return; } $return = null; $argv = func_get_args(); $argv = array_slice($argv, 2); foreach ($this->_topics[$topic] as $handle) { $return = $handle->call($argv); if (call_user_func($callback, $return)) { break; } } return $return; } /** * Filter a value * * Notifies subscribers to the topic and passes the single value provided * as an argument. Each subsequent subscriber is passed the return value * of the previous subscriber, and the value of the last subscriber is * returned. * * @param string $topic * @param mixed $value * @return mixed */ public function filter($topic, $value) { if (empty($this->_topics[$topic])) { return; } foreach ($this->_topics[$topic] as $handle) { $value = $handle->call(array($value)); } return $value; } /** * Subscribe to a topic * * @param string $topic * @param string|object $context Function name, class name, or object instance * @param null|string $handler If $context is a class or object, the name of the method to call * @return Phly_PubSub_Handle Pub-Sub handle (to allow later unsubscribe) */ public function subscribe($topic, $context, $handler = null) { if (empty($this->_topics[$topic])) { $this->_topics[$topic] = array(); } $handle = new Phly_PubSub_Handle($topic, $context, $handler); if ($index = array_search($handle, $this->_topics[$topic])) { return $this->_topics[$topic][$index]; } $this->_topics[$topic][] = $handle; return $handle; } /** * Unsubscribe a handler from a topic * * @param Phly_PubSub_Handle $handle * @return bool Returns true if topic and handle found, and unsubscribed; returns false if either topic or handle not found */ public function unsubscribe(Phly_PubSub_Handle $handle) { $topic = $handle->getTopic(); if (empty($this->_topics[$topic])) { return false; } if (false === ($index = array_search($handle, $this->_topics[$topic]))) { return false; } unset($this->_topics[$topic][$index]); return true; } /** * Retrieve all registered topics * * @return array */ public function getTopics() { return array_keys($this->_topics); } /** * Retrieve all handlers for a given topic * * @param string $topic * @return array Array of Phly_PubSub_Handle objects */ public function getSubscribedHandles($topic) { if (empty($this->_topics[$topic])) { return array(); } return $this->_topics[$topic]; } /** * Clear all handlers for a given topic * * @param string $topic * @return void */ public function clearHandles($topic) { if (!empty($this->_topics[$topic])) { unset($this->_topics[$topic]); } } }