[ Index ] |
PHP Cross Reference of phpBB-3.2.11-deutsch |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Nov 11 20:33:01 2020 | Cross-referenced by PHPXref 0.7.1 |