236 lines
8.5 KiB
PHP
236 lines
8.5 KiB
PHP
<?php
|
|
/**
|
|
* Zend Framework (http://framework.zend.com/)
|
|
*
|
|
* @link http://github.com/zendframework/zend-eventmanager for the canonical source repository
|
|
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
|
|
* @license https://github.com/zendframework/zend-eventmanager/blob/master/LICENSE.md
|
|
*/
|
|
|
|
namespace Zend\EventManager;
|
|
|
|
/**
|
|
* Shared/contextual EventManager
|
|
*
|
|
* Allows attaching to EMs composed by other classes without having an instance first.
|
|
* The assumption is that the SharedEventManager will be injected into EventManager
|
|
* instances, and then queried for additional listeners when triggering an event.
|
|
*/
|
|
class SharedEventManager implements SharedEventManagerInterface
|
|
{
|
|
/**
|
|
* Identifiers with event connections
|
|
* @var array
|
|
*/
|
|
protected $identifiers = [];
|
|
|
|
/**
|
|
* Attach a listener to an event emitted by components with specific identifiers.
|
|
*
|
|
* Allows attaching a listener to an event offered by an identifying
|
|
* components. As an example, the following connects to the "getAll" event
|
|
* of both an AbstractResource and EntityResource:
|
|
*
|
|
* <code>
|
|
* $sharedEventManager = new SharedEventManager();
|
|
* foreach (['My\Resource\AbstractResource', 'My\Resource\EntityResource'] as $identifier) {
|
|
* $sharedEventManager->attach(
|
|
* $identifier,
|
|
* 'getAll',
|
|
* function ($e) use ($cache) {
|
|
* if (!$id = $e->getParam('id', false)) {
|
|
* return;
|
|
* }
|
|
* if (!$data = $cache->load(get_class($resource) . '::getOne::' . $id )) {
|
|
* return;
|
|
* }
|
|
* return $data;
|
|
* }
|
|
* );
|
|
* }
|
|
* </code>
|
|
*
|
|
* @param string $identifier Identifier for event emitting component.
|
|
* @param string $event
|
|
* @param callable $listener Listener that will handle the event.
|
|
* @param int $priority Priority at which listener should execute
|
|
* @return void
|
|
* @throws Exception\InvalidArgumentException for invalid identifier arguments.
|
|
* @throws Exception\InvalidArgumentException for invalid event arguments.
|
|
*/
|
|
public function attach($identifier, $event, callable $listener, $priority = 1)
|
|
{
|
|
if (! is_string($identifier) || empty($identifier)) {
|
|
throw new Exception\InvalidArgumentException(sprintf(
|
|
'Invalid identifier provided; must be a string; received "%s"',
|
|
(is_object($identifier) ? get_class($identifier) : gettype($identifier))
|
|
));
|
|
}
|
|
|
|
if (! is_string($event) || empty($event)) {
|
|
throw new Exception\InvalidArgumentException(sprintf(
|
|
'Invalid event provided; must be a non-empty string; received "%s"',
|
|
(is_object($event) ? get_class($event) : gettype($event))
|
|
));
|
|
}
|
|
|
|
$this->identifiers[$identifier][$event][(int) $priority][] = $listener;
|
|
}
|
|
|
|
/**
|
|
* @inheritDoc
|
|
*/
|
|
public function detach(callable $listener, $identifier = null, $eventName = null, $force = false)
|
|
{
|
|
// No identifier or wildcard identifier: loop through all identifiers and detach
|
|
if (null === $identifier || ('*' === $identifier && ! $force)) {
|
|
foreach (array_keys($this->identifiers) as $identifier) {
|
|
$this->detach($listener, $identifier, $eventName, true);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (! is_string($identifier) || empty($identifier)) {
|
|
throw new Exception\InvalidArgumentException(sprintf(
|
|
'Invalid identifier provided; must be a string, received %s',
|
|
(is_object($identifier) ? get_class($identifier) : gettype($identifier))
|
|
));
|
|
}
|
|
|
|
// Do we have any listeners on the provided identifier?
|
|
if (! isset($this->identifiers[$identifier])) {
|
|
return;
|
|
}
|
|
|
|
if (null === $eventName || ('*' === $eventName && ! $force)) {
|
|
foreach (array_keys($this->identifiers[$identifier]) as $eventName) {
|
|
$this->detach($listener, $identifier, $eventName, true);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (! is_string($eventName) || empty($eventName)) {
|
|
throw new Exception\InvalidArgumentException(sprintf(
|
|
'Invalid event name provided; must be a string, received %s',
|
|
(is_object($eventName) ? get_class($eventName) : gettype($eventName))
|
|
));
|
|
}
|
|
|
|
if (! isset($this->identifiers[$identifier][$eventName])) {
|
|
return;
|
|
}
|
|
|
|
foreach ($this->identifiers[$identifier][$eventName] as $priority => $listeners) {
|
|
foreach ($listeners as $index => $evaluatedListener) {
|
|
if ($evaluatedListener !== $listener) {
|
|
continue;
|
|
}
|
|
|
|
// Found the listener; remove it.
|
|
unset($this->identifiers[$identifier][$eventName][$priority][$index]);
|
|
|
|
// Is the priority queue empty?
|
|
if (empty($this->identifiers[$identifier][$eventName][$priority])) {
|
|
unset($this->identifiers[$identifier][$eventName][$priority]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Is the event queue empty?
|
|
if (empty($this->identifiers[$identifier][$eventName])) {
|
|
unset($this->identifiers[$identifier][$eventName]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Is the identifier queue now empty? Remove it.
|
|
if (empty($this->identifiers[$identifier])) {
|
|
unset($this->identifiers[$identifier]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retrieve all listeners for a given identifier and event
|
|
*
|
|
* @param string[] $identifiers
|
|
* @param string $eventName
|
|
* @return array[]
|
|
* @throws Exception\InvalidArgumentException
|
|
*/
|
|
public function getListeners(array $identifiers, $eventName)
|
|
{
|
|
if ('*' === $eventName || ! is_string($eventName) || empty($eventName)) {
|
|
throw new Exception\InvalidArgumentException(sprintf(
|
|
'Event name passed to %s must be a non-empty, non-wildcard string',
|
|
__METHOD__
|
|
));
|
|
}
|
|
|
|
$returnListeners = [];
|
|
|
|
foreach ($identifiers as $identifier) {
|
|
if ('*' === $identifier || ! is_string($identifier) || empty($identifier)) {
|
|
throw new Exception\InvalidArgumentException(sprintf(
|
|
'Identifier names passed to %s must be non-empty, non-wildcard strings',
|
|
__METHOD__
|
|
));
|
|
}
|
|
|
|
if (isset($this->identifiers[$identifier])) {
|
|
$listenersByIdentifier = $this->identifiers[$identifier];
|
|
if (isset($listenersByIdentifier[$eventName])) {
|
|
foreach ($listenersByIdentifier[$eventName] as $priority => $listeners) {
|
|
$returnListeners[$priority][] = $listeners;
|
|
}
|
|
}
|
|
if (isset($listenersByIdentifier['*'])) {
|
|
foreach ($listenersByIdentifier['*'] as $priority => $listeners) {
|
|
$returnListeners[$priority][] = $listeners;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isset($this->identifiers['*'])) {
|
|
$wildcardIdentifier = $this->identifiers['*'];
|
|
if (isset($wildcardIdentifier[$eventName])) {
|
|
foreach ($wildcardIdentifier[$eventName] as $priority => $listeners) {
|
|
$returnListeners[$priority][] = $listeners;
|
|
}
|
|
}
|
|
if (isset($wildcardIdentifier['*'])) {
|
|
foreach ($wildcardIdentifier['*'] as $priority => $listeners) {
|
|
$returnListeners[$priority][] = $listeners;
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach ($returnListeners as $priority => $listOfListeners) {
|
|
$returnListeners[$priority] = array_merge(...$listOfListeners);
|
|
}
|
|
|
|
return $returnListeners;
|
|
}
|
|
|
|
/**
|
|
* @inheritDoc
|
|
*/
|
|
public function clearListeners($identifier, $eventName = null)
|
|
{
|
|
if (! isset($this->identifiers[$identifier])) {
|
|
return false;
|
|
}
|
|
|
|
if (null === $eventName) {
|
|
unset($this->identifiers[$identifier]);
|
|
return;
|
|
}
|
|
|
|
if (! isset($this->identifiers[$identifier][$eventName])) {
|
|
return;
|
|
}
|
|
|
|
unset($this->identifiers[$identifier][$eventName]);
|
|
}
|
|
}
|