[ Index ]

PHP Cross Reference of phpBB-3.2.8-deutsch

title

Body

[close]

/vendor/zendframework/zend-eventmanager/src/ -> EventManager.php (source)

   1  <?php
   2  /**
   3   * Zend Framework (http://framework.zend.com/)
   4   *
   5   * @link      http://github.com/zendframework/zf2 for the canonical source repository
   6   * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
   7   * @license   http://framework.zend.com/license/new-bsd New BSD License
   8   */
   9  
  10  namespace Zend\EventManager;
  11  
  12  use ArrayAccess;
  13  use ArrayObject;
  14  use Traversable;
  15  use Zend\Stdlib\CallbackHandler;
  16  use Zend\Stdlib\PriorityQueue;
  17  
  18  /**
  19   * Event manager: notification system
  20   *
  21   * Use the EventManager when you want to create a per-instance notification
  22   * system for your objects.
  23   */
  24  class EventManager implements EventManagerInterface
  25  {
  26      /**
  27       * Subscribed events and their listeners
  28       * @var array Array of PriorityQueue objects
  29       */
  30      protected $events = array();
  31  
  32      /**
  33       * @var string Class representing the event being emitted
  34       */
  35      protected $eventClass = 'Zend\EventManager\Event';
  36  
  37      /**
  38       * Identifiers, used to pull shared signals from SharedEventManagerInterface instance
  39       * @var array
  40       */
  41      protected $identifiers = array();
  42  
  43      /**
  44       * Shared event manager
  45       * @var false|null|SharedEventManagerInterface
  46       */
  47      protected $sharedManager = null;
  48  
  49      /**
  50       * Constructor
  51       *
  52       * Allows optionally specifying identifier(s) to use to pull signals from a
  53       * SharedEventManagerInterface.
  54       *
  55       * @param  null|string|int|array|Traversable $identifiers
  56       */
  57      public function __construct($identifiers = null)
  58      {
  59          $this->setIdentifiers($identifiers);
  60      }
  61  
  62      /**
  63       * Set the event class to utilize
  64       *
  65       * @param  string $class
  66       * @return EventManager
  67       */
  68      public function setEventClass($class)
  69      {
  70          $this->eventClass = $class;
  71          return $this;
  72      }
  73  
  74      /**
  75       * Set shared event manager
  76       *
  77       * @param SharedEventManagerInterface $sharedEventManager
  78       * @return EventManager
  79       */
  80      public function setSharedManager(SharedEventManagerInterface $sharedEventManager)
  81      {
  82          $this->sharedManager = $sharedEventManager;
  83          StaticEventManager::setInstance($sharedEventManager);
  84          return $this;
  85      }
  86  
  87      /**
  88       * Remove any shared event manager currently attached
  89       *
  90       * @return void
  91       */
  92      public function unsetSharedManager()
  93      {
  94          $this->sharedManager = false;
  95      }
  96  
  97      /**
  98       * Get shared event manager
  99       *
 100       * If one is not defined, but we have a static instance in
 101       * StaticEventManager, that one will be used and set in this instance.
 102       *
 103       * If none is available in the StaticEventManager, a boolean false is
 104       * returned.
 105       *
 106       * @return false|SharedEventManagerInterface
 107       */
 108      public function getSharedManager()
 109      {
 110          // "false" means "I do not want a shared manager; don't try and fetch one"
 111          if (false === $this->sharedManager
 112              || $this->sharedManager instanceof SharedEventManagerInterface
 113          ) {
 114              return $this->sharedManager;
 115          }
 116  
 117          if (!StaticEventManager::hasInstance()) {
 118              return false;
 119          }
 120  
 121          $this->sharedManager = StaticEventManager::getInstance();
 122          return $this->sharedManager;
 123      }
 124  
 125      /**
 126       * Get the identifier(s) for this EventManager
 127       *
 128       * @return array
 129       */
 130      public function getIdentifiers()
 131      {
 132          return $this->identifiers;
 133      }
 134  
 135      /**
 136       * Set the identifiers (overrides any currently set identifiers)
 137       *
 138       * @param string|int|array|Traversable $identifiers
 139       * @return EventManager Provides a fluent interface
 140       */
 141      public function setIdentifiers($identifiers)
 142      {
 143          if (is_array($identifiers) || $identifiers instanceof Traversable) {
 144              $this->identifiers = array_unique((array) $identifiers);
 145          } elseif ($identifiers !== null) {
 146              $this->identifiers = array($identifiers);
 147          }
 148          return $this;
 149      }
 150  
 151      /**
 152       * Add some identifier(s) (appends to any currently set identifiers)
 153       *
 154       * @param string|int|array|Traversable $identifiers
 155       * @return EventManager Provides a fluent interface
 156       */
 157      public function addIdentifiers($identifiers)
 158      {
 159          if (is_array($identifiers) || $identifiers instanceof Traversable) {
 160              $this->identifiers = array_unique(array_merge($this->identifiers, (array) $identifiers));
 161          } elseif ($identifiers !== null) {
 162              $this->identifiers = array_unique(array_merge($this->identifiers, array($identifiers)));
 163          }
 164          return $this;
 165      }
 166  
 167      /**
 168       * Trigger all listeners for a given event
 169       *
 170       * @param  string|EventInterface $event
 171       * @param  string|object     $target   Object calling emit, or symbol describing target (such as static method name)
 172       * @param  array|ArrayAccess $argv     Array of arguments; typically, should be associative
 173       * @param  null|callable     $callback Trigger listeners until return value of this callback evaluate to true
 174       * @return ResponseCollection All listener return values
 175       * @throws Exception\InvalidCallbackException
 176       */
 177      public function trigger($event, $target = null, $argv = array(), $callback = null)
 178      {
 179          if ($event instanceof EventInterface) {
 180              $e        = $event;
 181              $event    = $e->getName();
 182              $callback = $target;
 183          } elseif ($target instanceof EventInterface) {
 184              $e = $target;
 185              $e->setName($event);
 186              $callback = $argv;
 187          } elseif ($argv instanceof EventInterface) {
 188              $e = $argv;
 189              $e->setName($event);
 190              $e->setTarget($target);
 191          } else {
 192              $e = new $this->eventClass();
 193              $e->setName($event);
 194              $e->setTarget($target);
 195              $e->setParams($argv);
 196          }
 197  
 198          if ($callback && !is_callable($callback)) {
 199              throw new Exception\InvalidCallbackException('Invalid callback provided');
 200          }
 201  
 202          // Initial value of stop propagation flag should be false
 203          $e->stopPropagation(false);
 204  
 205          return $this->triggerListeners($event, $e, $callback);
 206      }
 207  
 208      /**
 209       * Trigger listeners until return value of one causes a callback to
 210       * evaluate to true
 211       *
 212       * Triggers listeners until the provided callback evaluates the return
 213       * value of one as true, or until all listeners have been executed.
 214       *
 215       * @param  string|EventInterface $event
 216       * @param  string|object $target Object calling emit, or symbol describing target (such as static method name)
 217       * @param  array|ArrayAccess $argv Array of arguments; typically, should be associative
 218       * @param  callable $callback
 219       * @return ResponseCollection
 220       * @deprecated Please use trigger()
 221       * @throws Exception\InvalidCallbackException if invalid callable provided
 222       */
 223      public function triggerUntil($event, $target, $argv = null, $callback = null)
 224      {
 225          trigger_error(
 226              'This method is deprecated and will be removed in the future. Please use trigger() instead.',
 227              E_USER_DEPRECATED
 228          );
 229          return $this->trigger($event, $target, $argv, $callback);
 230      }
 231  
 232      /**
 233       * Attach a listener to an event
 234       *
 235       * The first argument is the event, and the next argument describes a
 236       * callback that will respond to that event. A CallbackHandler instance
 237       * describing the event listener combination will be returned.
 238       *
 239       * The last argument indicates a priority at which the event should be
 240       * executed. By default, this value is 1; however, you may set it for any
 241       * integer value. Higher values have higher priority (i.e., execute first).
 242       *
 243       * You can specify "*" for the event name. In such cases, the listener will
 244       * be triggered for every event.
 245       *
 246       * @param  string|array|ListenerAggregateInterface $event An event or array of event names. If a ListenerAggregateInterface, proxies to {@link attachAggregate()}.
 247       * @param  callable|int $callback If string $event provided, expects PHP callback; for a ListenerAggregateInterface $event, this will be the priority
 248       * @param  int $priority If provided, the priority at which to register the callable
 249       * @return CallbackHandler|mixed CallbackHandler if attaching callable (to allow later unsubscribe); mixed if attaching aggregate
 250       * @throws Exception\InvalidArgumentException
 251       */
 252      public function attach($event, $callback = null, $priority = 1)
 253      {
 254          // Proxy ListenerAggregateInterface arguments to attachAggregate()
 255          if ($event instanceof ListenerAggregateInterface) {
 256              return $this->attachAggregate($event, $callback);
 257          }
 258  
 259          // Null callback is invalid
 260          if (null === $callback) {
 261              throw new Exception\InvalidArgumentException(sprintf(
 262                  '%s: expects a callback; none provided',
 263                  __METHOD__
 264              ));
 265          }
 266  
 267          // Array of events should be registered individually, and return an array of all listeners
 268          if (is_array($event)) {
 269              $listeners = array();
 270              foreach ($event as $name) {
 271                  $listeners[] = $this->attach($name, $callback, $priority);
 272              }
 273              return $listeners;
 274          }
 275  
 276          // If we don't have a priority queue for the event yet, create one
 277          if (empty($this->events[$event])) {
 278              $this->events[$event] = new PriorityQueue();
 279          }
 280  
 281          // Create a callback handler, setting the event and priority in its metadata
 282          $listener = new CallbackHandler($callback, array('event' => $event, 'priority' => $priority));
 283  
 284          // Inject the callback handler into the queue
 285          $this->events[$event]->insert($listener, $priority);
 286          return $listener;
 287      }
 288  
 289      /**
 290       * Attach a listener aggregate
 291       *
 292       * Listener aggregates accept an EventManagerInterface instance, and call attach()
 293       * one or more times, typically to attach to multiple events using local
 294       * methods.
 295       *
 296       * @param  ListenerAggregateInterface $aggregate
 297       * @param  int $priority If provided, a suggested priority for the aggregate to use
 298       * @return mixed return value of {@link ListenerAggregateInterface::attach()}
 299       */
 300      public function attachAggregate(ListenerAggregateInterface $aggregate, $priority = 1)
 301      {
 302          return $aggregate->attach($this, $priority);
 303      }
 304  
 305      /**
 306       * Unsubscribe a listener from an event
 307       *
 308       * @param  CallbackHandler|ListenerAggregateInterface $listener
 309       * @return bool Returns true if event and listener found, and unsubscribed; returns false if either event or listener not found
 310       * @throws Exception\InvalidArgumentException if invalid listener provided
 311       */
 312      public function detach($listener)
 313      {
 314          if ($listener instanceof ListenerAggregateInterface) {
 315              return $this->detachAggregate($listener);
 316          }
 317  
 318          if (!$listener instanceof CallbackHandler) {
 319              throw new Exception\InvalidArgumentException(sprintf(
 320                  '%s: expected a ListenerAggregateInterface or CallbackHandler; received "%s"',
 321                  __METHOD__,
 322                  (is_object($listener) ? get_class($listener) : gettype($listener))
 323              ));
 324          }
 325  
 326          $event = $listener->getMetadatum('event');
 327          if (!$event || empty($this->events[$event])) {
 328              return false;
 329          }
 330          $return = $this->events[$event]->remove($listener);
 331          if (!$return) {
 332              return false;
 333          }
 334          if (!count($this->events[$event])) {
 335              unset($this->events[$event]);
 336          }
 337          return true;
 338      }
 339  
 340      /**
 341       * Detach a listener aggregate
 342       *
 343       * Listener aggregates accept an EventManagerInterface instance, and call detach()
 344       * of all previously attached listeners.
 345       *
 346       * @param  ListenerAggregateInterface $aggregate
 347       * @return mixed return value of {@link ListenerAggregateInterface::detach()}
 348       */
 349      public function detachAggregate(ListenerAggregateInterface $aggregate)
 350      {
 351          return $aggregate->detach($this);
 352      }
 353  
 354      /**
 355       * Retrieve all registered events
 356       *
 357       * @return array
 358       */
 359      public function getEvents()
 360      {
 361          return array_keys($this->events);
 362      }
 363  
 364      /**
 365       * Retrieve all listeners for a given event
 366       *
 367       * @param  string $event
 368       * @return PriorityQueue
 369       */
 370      public function getListeners($event)
 371      {
 372          if (!array_key_exists($event, $this->events)) {
 373              return new PriorityQueue();
 374          }
 375          return $this->events[$event];
 376      }
 377  
 378      /**
 379       * Clear all listeners for a given event
 380       *
 381       * @param  string $event
 382       * @return void
 383       */
 384      public function clearListeners($event)
 385      {
 386          if (!empty($this->events[$event])) {
 387              unset($this->events[$event]);
 388          }
 389      }
 390  
 391      /**
 392       * Prepare arguments
 393       *
 394       * Use this method if you want to be able to modify arguments from within a
 395       * listener. It returns an ArrayObject of the arguments, which may then be
 396       * passed to trigger().
 397       *
 398       * @param  array $args
 399       * @return ArrayObject
 400       */
 401      public function prepareArgs(array $args)
 402      {
 403          return new ArrayObject($args);
 404      }
 405  
 406      /**
 407       * Trigger listeners
 408       *
 409       * Actual functionality for triggering listeners, to which trigger() delegate.
 410       *
 411       * @param  string           $event Event name
 412       * @param  EventInterface $e
 413       * @param  null|callable    $callback
 414       * @return ResponseCollection
 415       */
 416      protected function triggerListeners($event, EventInterface $e, $callback = null)
 417      {
 418          $responses = new ResponseCollection;
 419          $listeners = $this->getListeners($event);
 420  
 421          // Add shared/wildcard listeners to the list of listeners,
 422          // but don't modify the listeners object
 423          $sharedListeners         = $this->getSharedListeners($event);
 424          $sharedWildcardListeners = $this->getSharedListeners('*');
 425          $wildcardListeners       = $this->getListeners('*');
 426          if (count($sharedListeners) || count($sharedWildcardListeners) || count($wildcardListeners)) {
 427              $listeners = clone $listeners;
 428  
 429              // Shared listeners on this specific event
 430              $this->insertListeners($listeners, $sharedListeners);
 431  
 432              // Shared wildcard listeners
 433              $this->insertListeners($listeners, $sharedWildcardListeners);
 434  
 435              // Add wildcard listeners
 436              $this->insertListeners($listeners, $wildcardListeners);
 437          }
 438  
 439          foreach ($listeners as $listener) {
 440              $listenerCallback = $listener->getCallback();
 441  
 442              // Trigger the listener's callback, and push its result onto the
 443              // response collection
 444              $responses->push(call_user_func($listenerCallback, $e));
 445  
 446              // If the event was asked to stop propagating, do so
 447              if ($e->propagationIsStopped()) {
 448                  $responses->setStopped(true);
 449                  break;
 450              }
 451  
 452              // If the result causes our validation callback to return true,
 453              // stop propagation
 454              if ($callback && call_user_func($callback, $responses->last())) {
 455                  $responses->setStopped(true);
 456                  break;
 457              }
 458          }
 459  
 460          return $responses;
 461      }
 462  
 463      /**
 464       * Get list of all listeners attached to the shared event manager for
 465       * identifiers registered by this instance
 466       *
 467       * @param  string $event
 468       * @return array
 469       */
 470      protected function getSharedListeners($event)
 471      {
 472          if (!$sharedManager = $this->getSharedManager()) {
 473              return array();
 474          }
 475  
 476          $identifiers     = $this->getIdentifiers();
 477          //Add wildcard id to the search, if not already added
 478          if (!in_array('*', $identifiers)) {
 479              $identifiers[] = '*';
 480          }
 481          $sharedListeners = array();
 482  
 483          foreach ($identifiers as $id) {
 484              if (!$listeners = $sharedManager->getListeners($id, $event)) {
 485                  continue;
 486              }
 487  
 488              if (!is_array($listeners) && !($listeners instanceof Traversable)) {
 489                  continue;
 490              }
 491  
 492              foreach ($listeners as $listener) {
 493                  if (!$listener instanceof CallbackHandler) {
 494                      continue;
 495                  }
 496                  $sharedListeners[] = $listener;
 497              }
 498          }
 499  
 500          return $sharedListeners;
 501      }
 502  
 503      /**
 504       * Add listeners to the master queue of listeners
 505       *
 506       * Used to inject shared listeners and wildcard listeners.
 507       *
 508       * @param  PriorityQueue $masterListeners
 509       * @param  array|Traversable $listeners
 510       * @return void
 511       */
 512      protected function insertListeners($masterListeners, $listeners)
 513      {
 514          foreach ($listeners as $listener) {
 515              $priority = $listener->getMetadatum('priority');
 516              if (null === $priority) {
 517                  $priority = 1;
 518              } elseif (is_array($priority)) {
 519                  // If we have an array, likely using PriorityQueue. Grab first
 520                  // element of the array, as that's the actual priority.
 521                  $priority = array_shift($priority);
 522              }
 523              $masterListeners->insert($listener, $priority);
 524          }
 525      }
 526  }


Generated: Tue Apr 7 19:42:26 2020 Cross-referenced by PHPXref 0.7.1