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.8 Red Velvet API

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