Verzeichnisstruktur phpBB-3.2.0


Veröffentlicht
06.01.2017

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

EventManager.php

Zuletzt modifiziert: 09.10.2024, 12:55 - Dateigröße: 17.01 KiB


001  <?php
002  /**
003   * Zend Framework (http://framework.zend.com/)
004   *
005   * @link      http://github.com/zendframework/zf2 for the canonical source repository
006   * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
007   * @license   http://framework.zend.com/license/new-bsd New BSD License
008   */
009   
010  namespace Zend\EventManager;
011   
012  use ArrayAccess;
013  use ArrayObject;
014  use Traversable;
015  use Zend\Stdlib\CallbackHandler;
016  use Zend\Stdlib\PriorityQueue;
017   
018  /**
019   * Event manager: notification system
020   *
021   * Use the EventManager when you want to create a per-instance notification
022   * system for your objects.
023   */
024  class EventManager implements EventManagerInterface
025  {
026      /**
027       * Subscribed events and their listeners
028       * @var array Array of PriorityQueue objects
029       */
030      protected $events = array();
031   
032      /**
033       * @var string Class representing the event being emitted
034       */
035      protected $eventClass = 'Zend\EventManager\Event';
036   
037      /**
038       * Identifiers, used to pull shared signals from SharedEventManagerInterface instance
039       * @var array
040       */
041      protected $identifiers = array();
042   
043      /**
044       * Shared event manager
045       * @var false|null|SharedEventManagerInterface
046       */
047      protected $sharedManager = null;
048   
049      /**
050       * Constructor
051       *
052       * Allows optionally specifying identifier(s) to use to pull signals from a
053       * SharedEventManagerInterface.
054       *
055       * @param  null|string|int|array|Traversable $identifiers
056       */
057      public function __construct($identifiers = null)
058      {
059          $this->setIdentifiers($identifiers);
060      }
061   
062      /**
063       * Set the event class to utilize
064       *
065       * @param  string $class
066       * @return EventManager
067       */
068      public function setEventClass($class)
069      {
070          $this->eventClass = $class;
071          return $this;
072      }
073   
074      /**
075       * Set shared event manager
076       *
077       * @param SharedEventManagerInterface $sharedEventManager
078       * @return EventManager
079       */
080      public function setSharedManager(SharedEventManagerInterface $sharedEventManager)
081      {
082          $this->sharedManager = $sharedEventManager;
083          StaticEventManager::setInstance($sharedEventManager);
084          return $this;
085      }
086   
087      /**
088       * Remove any shared event manager currently attached
089       *
090       * @return void
091       */
092      public function unsetSharedManager()
093      {
094          $this->sharedManager = false;
095      }
096   
097      /**
098       * Get shared event manager
099       *
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  }
527