Provider.php #1

  • //
  • guest/
  • perforce_software/
  • chronicle/
  • main/
  • library/
  • Phly/
  • PubSub/
  • Provider.php
  • View
  • Commits
  • Open Download .zip Download (5 KB)
<?php
/**
 * Phly - PHp LibrarY
 * 
 * @category  Phly
 * @package   Phly_PubSub
 * @copyright Copyright (C) 2008 - Present, Matthew Weier O'Phinney
 * @author    Matthew Weier O'Phinney <mweierophinney@gmail.com> 
 * @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]);
        }
    }
}
# Change User Description Committed
#1 16170 perforce_software Move Chronicle files to follow new path scheme for branching.
//guest/perforce_software/chronicle/library/Phly/PubSub/Provider.php
#1 8972 Matt Attaway Initial add of the Chronicle source code