CakePHP
  • Documentation
    • Book
    • API
    • Videos
    • Logos & Trademarks
  • Business Solutions
  • Swag
  • Road Trip
  • Team
  • Community
    • Community
    • Team
    • Issues (Github)
    • YouTube Channel
    • Get Involved
    • Bakery
    • Featured Resources
    • Newsletter
    • Certification
    • My CakePHP
    • CakeFest
    • Facebook
    • Twitter
    • Help & Support
    • Forum
    • Stack Overflow
    • IRC
    • Slack
    • Paid Support
CakePHP

C CakePHP 3.7 Red Velvet API

  • Overview
  • Tree
  • Deprecated
  • Version:
    • 3.7
      • 3.7
      • 3.6
      • 3.5
      • 3.4
      • 3.3
      • 3.2
      • 3.1
      • 3.0
      • 2.10
      • 2.9
      • 2.8
      • 2.7
      • 2.6
      • 2.5
      • 2.4
      • 2.3
      • 2.2
      • 2.1
      • 2.0
      • 1.3
      • 1.2

Namespaces

  • Cake
    • Auth
      • Storage
    • Cache
      • Engine
    • Collection
      • Iterator
    • Command
    • Console
      • Exception
    • Controller
      • Component
      • Exception
    • Core
      • Configure
        • Engine
      • Exception
      • Retry
    • Database
      • Driver
      • Exception
      • Expression
      • Schema
      • Statement
      • Type
    • Datasource
      • Exception
    • Error
      • Middleware
    • Event
      • Decorator
    • Filesystem
    • Form
    • Http
      • Client
        • Adapter
        • Auth
      • Cookie
      • Exception
      • Middleware
      • Session
    • I18n
      • Formatter
      • Middleware
      • Parser
    • Log
      • Engine
    • Mailer
      • Exception
      • Transport
    • Network
      • Exception
    • ORM
      • Association
      • Behavior
        • Translate
      • Exception
      • Locator
      • Rule
    • Routing
      • Exception
      • Filter
      • Middleware
      • Route
    • Shell
      • Helper
      • Task
    • TestSuite
      • Fixture
      • Stub
    • Utility
      • Exception
    • Validation
    • View
      • Exception
      • Form
      • Helper
      • Widget
  • None

Classes

  • Event
  • EventList
  • EventManager

Interfaces

  • EventDispatcherInterface
  • EventInterface
  • EventListenerInterface
  • EventManagerInterface

Traits

  • EventDispatcherTrait
  • EventManagerTrait
  1: <?php
  2: /**
  3:  * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  4:  * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  5:  *
  6:  * Licensed under The MIT License
  7:  * For full copyright and license information, please see the LICENSE.txt
  8:  * Redistributions of files must retain the above copyright notice.
  9:  *
 10:  * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 11:  * @link          https://cakephp.org CakePHP(tm) Project
 12:  * @since         2.1.0
 13:  * @license       https://opensource.org/licenses/mit-license.php MIT License
 14:  */
 15: namespace Cake\Event;
 16: 
 17: use InvalidArgumentException;
 18: 
 19: /**
 20:  * The event manager is responsible for keeping track of event listeners, passing the correct
 21:  * data to them, and firing them in the correct order, when associated events are triggered. You
 22:  * can create multiple instances of this object to manage local events or keep a single instance
 23:  * and pass it around to manage all events in your app.
 24:  */
 25: class EventManager implements EventManagerInterface
 26: {
 27: 
 28:     /**
 29:      * The default priority queue value for new, attached listeners
 30:      *
 31:      * @var int
 32:      */
 33:     public static $defaultPriority = 10;
 34: 
 35:     /**
 36:      * The globally available instance, used for dispatching events attached from any scope
 37:      *
 38:      * @var \Cake\Event\EventManager
 39:      */
 40:     protected static $_generalManager;
 41: 
 42:     /**
 43:      * List of listener callbacks associated to
 44:      *
 45:      * @var array
 46:      */
 47:     protected $_listeners = [];
 48: 
 49:     /**
 50:      * Internal flag to distinguish a common manager from the singleton
 51:      *
 52:      * @var bool
 53:      */
 54:     protected $_isGlobal = false;
 55: 
 56:     /**
 57:      * The event list object.
 58:      *
 59:      * @var \Cake\Event\EventList|null
 60:      */
 61:     protected $_eventList;
 62: 
 63:     /**
 64:      * Enables automatic adding of events to the event list object if it is present.
 65:      *
 66:      * @var bool
 67:      */
 68:     protected $_trackEvents = false;
 69: 
 70:     /**
 71:      * Returns the globally available instance of a Cake\Event\EventManager
 72:      * this is used for dispatching events attached from outside the scope
 73:      * other managers were created. Usually for creating hook systems or inter-class
 74:      * communication
 75:      *
 76:      * If called with the first parameter, it will be set as the globally available instance
 77:      *
 78:      * @param \Cake\Event\EventManager|null $manager Event manager instance.
 79:      * @return static The global event manager
 80:      */
 81:     public static function instance($manager = null)
 82:     {
 83:         if ($manager instanceof EventManager) {
 84:             static::$_generalManager = $manager;
 85:         }
 86:         if (empty(static::$_generalManager)) {
 87:             static::$_generalManager = new static();
 88:         }
 89: 
 90:         static::$_generalManager->_isGlobal = true;
 91: 
 92:         return static::$_generalManager;
 93:     }
 94: 
 95:     /**
 96:      * Adds a new listener to an event.
 97:      *
 98:      * @param callable|\Cake\Event\EventListenerInterface $callable PHP valid callback type or instance of Cake\Event\EventListenerInterface to be called
 99:      * when the event named with $eventKey is triggered. If a Cake\Event\EventListenerInterface instance is passed, then the `implementedEvents`
100:      * method will be called on the object to register the declared events individually as methods to be managed by this class.
101:      * It is possible to define multiple event handlers per event name.
102:      *
103:      * @param string|null $eventKey The event unique identifier name with which the callback will be associated. If $callable
104:      * is an instance of Cake\Event\EventListenerInterface this argument will be ignored
105:      *
106:      * @param array $options used to set the `priority` flag to the listener. In the future more options may be added.
107:      * Priorities are treated as queues. Lower values are called before higher ones, and multiple attachments
108:      * added to the same priority queue will be treated in the order of insertion.
109:      *
110:      * @return void
111:      * @throws \InvalidArgumentException When event key is missing or callable is not an
112:      *   instance of Cake\Event\EventListenerInterface.
113:      * @deprecated 3.0.0 Use on() instead.
114:      */
115:     public function attach($callable, $eventKey = null, array $options = [])
116:     {
117:         deprecationWarning('EventManager::attach() is deprecated. Use EventManager::on() instead.');
118:         if ($eventKey === null) {
119:             $this->on($callable);
120: 
121:             return;
122:         }
123:         if ($options) {
124:             $this->on($eventKey, $options, $callable);
125: 
126:             return;
127:         }
128:         $this->on($eventKey, $callable);
129:     }
130: 
131:     /**
132:      * {@inheritDoc}
133:      */
134:     public function on($eventKey = null, $options = [], $callable = null)
135:     {
136:         if ($eventKey instanceof EventListenerInterface) {
137:             $this->_attachSubscriber($eventKey);
138: 
139:             return $this;
140:         }
141:         $argCount = func_num_args();
142:         if ($argCount === 2) {
143:             $this->_listeners[$eventKey][static::$defaultPriority][] = [
144:                 'callable' => $options
145:             ];
146: 
147:             return $this;
148:         }
149:         if ($argCount === 3) {
150:             $priority = isset($options['priority']) ? $options['priority'] : static::$defaultPriority;
151:             $this->_listeners[$eventKey][$priority][] = [
152:                 'callable' => $callable
153:             ];
154: 
155:             return $this;
156:         }
157:         throw new InvalidArgumentException(
158:             'Invalid arguments for EventManager::on(). ' .
159:             "Expected 1, 2 or 3 arguments. Got {$argCount} arguments."
160:         );
161:     }
162: 
163:     /**
164:      * Auxiliary function to attach all implemented callbacks of a Cake\Event\EventListenerInterface class instance
165:      * as individual methods on this manager
166:      *
167:      * @param \Cake\Event\EventListenerInterface $subscriber Event listener.
168:      * @return void
169:      */
170:     protected function _attachSubscriber(EventListenerInterface $subscriber)
171:     {
172:         foreach ((array)$subscriber->implementedEvents() as $eventKey => $function) {
173:             $options = [];
174:             $method = $function;
175:             if (is_array($function) && isset($function['callable'])) {
176:                 list($method, $options) = $this->_extractCallable($function, $subscriber);
177:             } elseif (is_array($function) && is_numeric(key($function))) {
178:                 foreach ($function as $f) {
179:                     list($method, $options) = $this->_extractCallable($f, $subscriber);
180:                     $this->on($eventKey, $options, $method);
181:                 }
182:                 continue;
183:             }
184:             if (is_string($method)) {
185:                 $method = [$subscriber, $function];
186:             }
187:             $this->on($eventKey, $options, $method);
188:         }
189:     }
190: 
191:     /**
192:      * Auxiliary function to extract and return a PHP callback type out of the callable definition
193:      * from the return value of the `implementedEvents` method on a Cake\Event\EventListenerInterface
194:      *
195:      * @param array $function the array taken from a handler definition for an event
196:      * @param \Cake\Event\EventListenerInterface $object The handler object
197:      * @return callable
198:      */
199:     protected function _extractCallable($function, $object)
200:     {
201:         $method = $function['callable'];
202:         $options = $function;
203:         unset($options['callable']);
204:         if (is_string($method)) {
205:             $method = [$object, $method];
206:         }
207: 
208:         return [$method, $options];
209:     }
210: 
211:     /**
212:      * Removes a listener from the active listeners.
213:      *
214:      * @param callable|\Cake\Event\EventListenerInterface $callable any valid PHP callback type or an instance of EventListenerInterface
215:      * @param string|null $eventKey The event unique identifier name with which the callback has been associated
216:      * @return void
217:      * @deprecated 3.0.0 Use off() instead.
218:      */
219:     public function detach($callable, $eventKey = null)
220:     {
221:         deprecationWarning('EventManager::detach() is deprecated. Use EventManager::off() instead.');
222:         if ($eventKey === null) {
223:             $this->off($callable);
224: 
225:             return;
226:         }
227:         $this->off($eventKey, $callable);
228:     }
229: 
230:     /**
231:      * {@inheritDoc}
232:      */
233:     public function off($eventKey, $callable = null)
234:     {
235:         if ($eventKey instanceof EventListenerInterface) {
236:             $this->_detachSubscriber($eventKey);
237: 
238:             return $this;
239:         }
240:         if ($callable instanceof EventListenerInterface) {
241:             $this->_detachSubscriber($callable, $eventKey);
242: 
243:             return $this;
244:         }
245:         if ($callable === null && is_string($eventKey)) {
246:             unset($this->_listeners[$eventKey]);
247: 
248:             return $this;
249:         }
250:         if ($callable === null) {
251:             foreach (array_keys($this->_listeners) as $name) {
252:                 $this->off($name, $eventKey);
253:             }
254: 
255:             return $this;
256:         }
257:         if (empty($this->_listeners[$eventKey])) {
258:             return $this;
259:         }
260:         foreach ($this->_listeners[$eventKey] as $priority => $callables) {
261:             foreach ($callables as $k => $callback) {
262:                 if ($callback['callable'] === $callable) {
263:                     unset($this->_listeners[$eventKey][$priority][$k]);
264:                     break;
265:                 }
266:             }
267:         }
268: 
269:         return $this;
270:     }
271: 
272:     /**
273:      * Auxiliary function to help detach all listeners provided by an object implementing EventListenerInterface
274:      *
275:      * @param \Cake\Event\EventListenerInterface $subscriber the subscriber to be detached
276:      * @param string|null $eventKey optional event key name to unsubscribe the listener from
277:      * @return void
278:      */
279:     protected function _detachSubscriber(EventListenerInterface $subscriber, $eventKey = null)
280:     {
281:         $events = (array)$subscriber->implementedEvents();
282:         if (!empty($eventKey) && empty($events[$eventKey])) {
283:             return;
284:         }
285:         if (!empty($eventKey)) {
286:             $events = [$eventKey => $events[$eventKey]];
287:         }
288:         foreach ($events as $key => $function) {
289:             if (is_array($function)) {
290:                 if (is_numeric(key($function))) {
291:                     foreach ($function as $handler) {
292:                         $handler = isset($handler['callable']) ? $handler['callable'] : $handler;
293:                         $this->off($key, [$subscriber, $handler]);
294:                     }
295:                     continue;
296:                 }
297:                 $function = $function['callable'];
298:             }
299:             $this->off($key, [$subscriber, $function]);
300:         }
301:     }
302: 
303:     /**
304:      * {@inheritDoc}
305:      */
306:     public function dispatch($event)
307:     {
308:         if (is_string($event)) {
309:             $event = new Event($event);
310:         }
311: 
312:         $listeners = $this->listeners($event->getName());
313: 
314:         if ($this->_trackEvents) {
315:             $this->addEventToList($event);
316:         }
317: 
318:         if (!$this->_isGlobal && static::instance()->isTrackingEvents()) {
319:             static::instance()->addEventToList($event);
320:         }
321: 
322:         if (empty($listeners)) {
323:             return $event;
324:         }
325: 
326:         foreach ($listeners as $listener) {
327:             if ($event->isStopped()) {
328:                 break;
329:             }
330:             $result = $this->_callListener($listener['callable'], $event);
331:             if ($result === false) {
332:                 $event->stopPropagation();
333:             }
334:             if ($result !== null) {
335:                 $event->setResult($result);
336:             }
337:         }
338: 
339:         return $event;
340:     }
341: 
342:     /**
343:      * Calls a listener.
344:      *
345:      * @param callable $listener The listener to trigger.
346:      * @param \Cake\Event\Event $event Event instance.
347:      * @return mixed The result of the $listener function.
348:      */
349:     protected function _callListener(callable $listener, Event $event)
350:     {
351:         $data = $event->getData();
352: 
353:         return $listener($event, ...array_values($data));
354:     }
355: 
356:     /**
357:      * {@inheritDoc}
358:      */
359:     public function listeners($eventKey)
360:     {
361:         $localListeners = [];
362:         if (!$this->_isGlobal) {
363:             $localListeners = $this->prioritisedListeners($eventKey);
364:             $localListeners = empty($localListeners) ? [] : $localListeners;
365:         }
366:         $globalListeners = static::instance()->prioritisedListeners($eventKey);
367:         $globalListeners = empty($globalListeners) ? [] : $globalListeners;
368: 
369:         $priorities = array_merge(array_keys($globalListeners), array_keys($localListeners));
370:         $priorities = array_unique($priorities);
371:         asort($priorities);
372: 
373:         $result = [];
374:         foreach ($priorities as $priority) {
375:             if (isset($globalListeners[$priority])) {
376:                 $result = array_merge($result, $globalListeners[$priority]);
377:             }
378:             if (isset($localListeners[$priority])) {
379:                 $result = array_merge($result, $localListeners[$priority]);
380:             }
381:         }
382: 
383:         return $result;
384:     }
385: 
386:     /**
387:      * Returns the listeners for the specified event key indexed by priority
388:      *
389:      * @param string $eventKey Event key.
390:      * @return array
391:      */
392:     public function prioritisedListeners($eventKey)
393:     {
394:         if (empty($this->_listeners[$eventKey])) {
395:             return [];
396:         }
397: 
398:         return $this->_listeners[$eventKey];
399:     }
400: 
401:     /**
402:      * Returns the listeners matching a specified pattern
403:      *
404:      * @param string $eventKeyPattern Pattern to match.
405:      * @return array
406:      */
407:     public function matchingListeners($eventKeyPattern)
408:     {
409:         $matchPattern = '/' . preg_quote($eventKeyPattern, '/') . '/';
410:         $matches = array_intersect_key(
411:             $this->_listeners,
412:             array_flip(
413:                 preg_grep($matchPattern, array_keys($this->_listeners), 0)
414:             )
415:         );
416: 
417:         return $matches;
418:     }
419: 
420:     /**
421:      * Returns the event list.
422:      *
423:      * @return \Cake\Event\EventList
424:      */
425:     public function getEventList()
426:     {
427:         return $this->_eventList;
428:     }
429: 
430:     /**
431:      * Adds an event to the list if the event list object is present.
432:      *
433:      * @param \Cake\Event\Event $event An event to add to the list.
434:      * @return $this
435:      */
436:     public function addEventToList(Event $event)
437:     {
438:         if ($this->_eventList) {
439:             $this->_eventList->add($event);
440:         }
441: 
442:         return $this;
443:     }
444: 
445:     /**
446:      * Enables / disables event tracking at runtime.
447:      *
448:      * @param bool $enabled True or false to enable / disable it.
449:      * @return $this
450:      */
451:     public function trackEvents($enabled)
452:     {
453:         $this->_trackEvents = (bool)$enabled;
454: 
455:         return $this;
456:     }
457: 
458:     /**
459:      * Returns whether this manager is set up to track events
460:      *
461:      * @return bool
462:      */
463:     public function isTrackingEvents()
464:     {
465:         return $this->_trackEvents && $this->_eventList;
466:     }
467: 
468:     /**
469:      * Enables the listing of dispatched events.
470:      *
471:      * @param \Cake\Event\EventList $eventList The event list object to use.
472:      * @return $this
473:      */
474:     public function setEventList(EventList $eventList)
475:     {
476:         $this->_eventList = $eventList;
477:         $this->_trackEvents = true;
478: 
479:         return $this;
480:     }
481: 
482:     /**
483:      * Disables the listing of dispatched events.
484:      *
485:      * @return $this
486:      */
487:     public function unsetEventList()
488:     {
489:         $this->_eventList = null;
490:         $this->_trackEvents = false;
491: 
492:         return $this;
493:     }
494: 
495:     /**
496:      * Debug friendly object properties.
497:      *
498:      * @return array
499:      */
500:     public function __debugInfo()
501:     {
502:         $properties = get_object_vars($this);
503:         $properties['_generalManager'] = '(object) EventManager';
504:         $properties['_listeners'] = [];
505:         foreach ($this->_listeners as $key => $priorities) {
506:             $listenerCount = 0;
507:             foreach ($priorities as $listeners) {
508:                 $listenerCount += count($listeners);
509:             }
510:             $properties['_listeners'][$key] = $listenerCount . ' listener(s)';
511:         }
512:         if ($this->_eventList) {
513:             $count = count($this->_eventList);
514:             for ($i = 0; $i < $count; $i++) {
515:                 $event = $this->_eventList[$i];
516:                 $subject = $event->getSubject();
517:                 $properties['_dispatchedEvents'][] = $event->getName() . ' with ' .
518:                     (is_object($subject) ? 'subject ' . get_class($subject) : 'no subject');
519:             }
520:         } else {
521:             $properties['_dispatchedEvents'] = null;
522:         }
523:         unset($properties['_eventList']);
524: 
525:         return $properties;
526:     }
527: }
528: 
Follow @CakePHP
#IRC
OpenHub
Rackspace
  • Business Solutions
  • Showcase
  • Documentation
  • Book
  • API
  • Videos
  • Logos & Trademarks
  • Community
  • Team
  • Issues (Github)
  • YouTube Channel
  • Get Involved
  • Bakery
  • Featured Resources
  • Newsletter
  • Certification
  • My CakePHP
  • CakeFest
  • Facebook
  • Twitter
  • Help & Support
  • Forum
  • Stack Overflow
  • IRC
  • Slack
  • Paid Support

Generated using CakePHP API Docs