$predicate ?? NULL, 'observer' => [$observer, $method] ]; } /** * Remove an object registered with the NotificationCenter. * Trying to remove an observer that was not registered is * allowed and has no effect. * * @param object $observer object to be removed * @param string $event name of event (may be NULL) * @param mixed $object subject to observe (may be NULL) */ public static function removeObserver($observer, $event = NULL, $object = NULL) { if ($event === NULL) { $events = array_keys(self::$observers); } else if (isset(self::$observers[$event])) { $events = [$event]; } else { return; } foreach ($events as $event) { foreach (self::$observers[$event] as $index => $list) { if ($object === NULL || $list['predicate'] && $list['predicate']($object)) { if ($list['observer'][0] === $observer) { unset(self::$observers[$event][$index]); } } } } } /** * Post an event notification to all registered observers. * Only observers registered for this event type and subject * are notified. * * @param string $event name of this notification * @param mixed $object subject of this notification * @param mixed $user_data additional information (optional) * * @throws NotificationVetoException on observer veto */ public static function postNotification($event, $object, $user_data = null) { $current_observers = []; foreach (self::$observers as $e => $l) { if ($e === '' || fnmatch($e, $event, FNM_NOESCAPE)) { $current_observers = array_merge($current_observers, $l); } } foreach ($current_observers as $list) { if (!$list['predicate'] || $list['predicate']($object)) { call_user_func($list['observer'], $event, $object, $user_data); } } } /** * Convenience method that uses a jQuery like structure for event * registration by closures. * * @param string $event * @param Callable $callback * @param mixed $object * @since Stud.IP 4.2 */ public static function on($event, Callable $callback, $object = null) { if ($callback instanceof Closure || is_object($callback)) { static::addObserver($callback, '__invoke', $event, $object); } elseif (is_array($callback)) { static::addObserver($callback[0], $callback[1], $event, $object); } elseif (is_string($callback)) { throw new Exception('Strings as callable may not be passed to ' . __METHOD__); } } /** * Convenience method that uses a jQuery like structure for event * unregistration by closures. * * @param string $event * @param Callable $callback * @param mixed $object * @since Stud.IP 4.2 */ public static function off($event, Callable $callback, $object = null) { if ($callback instanceof Closure || is_object($callback)) { static::removeObserver($callback, $event, $object); } elseif (is_array($callback)) { static::removeObserver($callback[0], $event, $object); } elseif (is_string($callback)) { throw new Exception('Strings as callable may not be passed to ' . __METHOD__); } } }