upgraded dependencies

This commit is contained in:
RafficMohammed
2023-01-08 01:59:16 +05:30
parent 51056e3aad
commit f9ae387337
6895 changed files with 133617 additions and 178680 deletions

View File

@@ -0,0 +1,29 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\EventDispatcher\Attribute;
/**
* Service tag to autoconfigure event listeners.
*
* @author Alexander M. Turek <me@derrabus.de>
*/
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class AsEventListener
{
public function __construct(
public ?string $event = null,
public ?string $method = null,
public int $priority = 0,
public ?string $dispatcher = null,
) {
}
}

View File

@@ -1,6 +1,30 @@
CHANGELOG
=========
5.4
---
* Allow `#[AsEventListener]` attribute on methods
5.3
---
* Add `#[AsEventListener]` attribute for declaring listeners on PHP 8
5.1.0
-----
* The `LegacyEventDispatcherProxy` class has been deprecated.
* Added an optional `dispatcher` attribute to the listener and subscriber tags in `RegisterListenerPass`.
5.0.0
-----
* The signature of the `EventDispatcherInterface::dispatch()` method has been changed to `dispatch($event, string $eventName = null): object`.
* The `Event` class has been removed in favor of `Symfony\Contracts\EventDispatcher\Event`.
* The `TraceableEventDispatcherInterface` has been removed.
* The `WrappedListener` class is now final.
4.4.0
-----

View File

@@ -13,15 +13,12 @@ namespace Symfony\Component\EventDispatcher\Debug;
use Psr\EventDispatcher\StoppableEventInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy;
use Symfony\Component\EventDispatcher\LegacyEventProxy;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Stopwatch\Stopwatch;
use Symfony\Contracts\EventDispatcher\Event as ContractsEvent;
use Symfony\Contracts\Service\ResetInterface;
/**
* Collects some data about event listeners.
@@ -30,11 +27,14 @@ use Symfony\Contracts\EventDispatcher\Event as ContractsEvent;
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class TraceableEventDispatcher implements TraceableEventDispatcherInterface
class TraceableEventDispatcher implements EventDispatcherInterface, ResetInterface
{
protected $logger;
protected $stopwatch;
/**
* @var \SplObjectStorage<WrappedListener, array{string, string}>
*/
private $callStack;
private $dispatcher;
private $wrappedListeners;
@@ -44,7 +44,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
public function __construct(EventDispatcherInterface $dispatcher, Stopwatch $stopwatch, LoggerInterface $logger = null, RequestStack $requestStack = null)
{
$this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher);
$this->dispatcher = $dispatcher;
$this->stopwatch = $stopwatch;
$this->logger = $logger;
$this->wrappedListeners = [];
@@ -55,7 +55,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
/**
* {@inheritdoc}
*/
public function addListener($eventName, $listener, $priority = 0)
public function addListener(string $eventName, $listener, int $priority = 0)
{
$this->dispatcher->addListener($eventName, $listener, $priority);
}
@@ -71,7 +71,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
/**
* {@inheritdoc}
*/
public function removeListener($eventName, $listener)
public function removeListener(string $eventName, $listener)
{
if (isset($this->wrappedListeners[$eventName])) {
foreach ($this->wrappedListeners[$eventName] as $index => $wrappedListener) {
@@ -97,7 +97,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
/**
* {@inheritdoc}
*/
public function getListeners($eventName = null)
public function getListeners(string $eventName = null)
{
return $this->dispatcher->getListeners($eventName);
}
@@ -105,7 +105,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
/**
* {@inheritdoc}
*/
public function getListenerPriority($eventName, $listener)
public function getListenerPriority(string $eventName, $listener)
{
// we might have wrapped listeners for the event (if called while dispatching)
// in that case get the priority by wrapper
@@ -123,39 +123,25 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
/**
* {@inheritdoc}
*/
public function hasListeners($eventName = null)
public function hasListeners(string $eventName = null)
{
return $this->dispatcher->hasListeners($eventName);
}
/**
* {@inheritdoc}
*
* @param string|null $eventName
*/
public function dispatch($event/* , string $eventName = null */)
public function dispatch(object $event, string $eventName = null): object
{
$eventName = $eventName ?? \get_class($event);
if (null === $this->callStack) {
$this->callStack = new \SplObjectStorage();
}
$currentRequestHash = $this->currentRequestHash = $this->requestStack && ($request = $this->requestStack->getCurrentRequest()) ? spl_object_hash($request) : '';
$eventName = 1 < \func_num_args() ? func_get_arg(1) : null;
if (\is_object($event)) {
$eventName = $eventName ?? \get_class($event);
} else {
@trigger_error(sprintf('Calling the "%s::dispatch()" method with the event name as first argument is deprecated since Symfony 4.3, pass it second and provide the event object first instead.', EventDispatcherInterface::class), \E_USER_DEPRECATED);
$swap = $event;
$event = $eventName ?? new Event();
$eventName = $swap;
if (!$event instanceof Event) {
throw new \TypeError(sprintf('Argument 1 passed to "%s::dispatch()" must be an instance of "%s", "%s" given.', EventDispatcherInterface::class, Event::class, \is_object($event) ? \get_class($event) : \gettype($event)));
}
}
if (null !== $this->logger && ($event instanceof Event || $event instanceof ContractsEvent || $event instanceof StoppableEventInterface) && $event->isPropagationStopped()) {
if (null !== $this->logger && $event instanceof StoppableEventInterface && $event->isPropagationStopped()) {
$this->logger->debug(sprintf('The "%s" event is already stopped. No listeners have been called.', $eventName));
}
@@ -183,17 +169,15 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
}
/**
* {@inheritdoc}
*
* @param Request|null $request The request to get listeners for
* @return array
*/
public function getCalledListeners(/* Request $request = null */)
public function getCalledListeners(Request $request = null)
{
if (null === $this->callStack) {
return [];
}
$hash = 1 <= \func_num_args() && null !== ($request = func_get_arg(0)) ? spl_object_hash($request) : null;
$hash = $request ? spl_object_hash($request) : null;
$called = [];
foreach ($this->callStack as $listener) {
[$eventName, $requestHash] = $this->callStack->getInfo();
@@ -206,11 +190,9 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
}
/**
* {@inheritdoc}
*
* @param Request|null $request The request to get listeners for
* @return array
*/
public function getNotCalledListeners(/* Request $request = null */)
public function getNotCalledListeners(Request $request = null)
{
try {
$allListeners = $this->getListeners();
@@ -223,7 +205,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
return [];
}
$hash = 1 <= \func_num_args() && null !== ($request = func_get_arg(0)) ? spl_object_hash($request) : null;
$hash = $request ? spl_object_hash($request) : null;
$calledListeners = [];
if (null !== $this->callStack) {
@@ -253,12 +235,9 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
return $notCalled;
}
/**
* @param Request|null $request The request to get orphaned events for
*/
public function getOrphanedEvents(/* Request $request = null */): array
public function getOrphanedEvents(Request $request = null): array
{
if (1 <= \func_num_args() && null !== $request = func_get_arg(0)) {
if ($request) {
return $this->orphanedEvents[spl_object_hash($request)] ?? [];
}
@@ -284,46 +263,26 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
*
* @return mixed
*/
public function __call($method, $arguments)
public function __call(string $method, array $arguments)
{
return $this->dispatcher->{$method}(...$arguments);
}
/**
* Called before dispatching the event.
*
* @param object $event
*/
protected function beforeDispatch(string $eventName, $event)
protected function beforeDispatch(string $eventName, object $event)
{
$this->preDispatch($eventName, $event instanceof Event ? $event : new LegacyEventProxy($event));
}
/**
* Called after dispatching the event.
*
* @param object $event
*/
protected function afterDispatch(string $eventName, $event)
{
$this->postDispatch($eventName, $event instanceof Event ? $event : new LegacyEventProxy($event));
}
/**
* @deprecated since Symfony 4.3, will be removed in 5.0, use beforeDispatch instead
*/
protected function preDispatch($eventName, Event $event)
protected function afterDispatch(string $eventName, object $event)
{
}
/**
* @deprecated since Symfony 4.3, will be removed in 5.0, use afterDispatch instead
*/
protected function postDispatch($eventName, Event $event)
{
}
private function preProcess(string $eventName)
private function preProcess(string $eventName): void
{
if (!$this->dispatcher->hasListeners($eventName)) {
$this->orphanedEvents[$this->currentRequestHash][] = $eventName;
@@ -341,7 +300,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
}
}
private function postProcess(string $eventName)
private function postProcess(string $eventName): void
{
unset($this->wrappedListeners[$eventName]);
$skipped = false;

View File

@@ -1,42 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\EventDispatcher\Debug;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Contracts\Service\ResetInterface;
/**
* @deprecated since Symfony 4.1
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface TraceableEventDispatcherInterface extends EventDispatcherInterface, ResetInterface
{
/**
* Gets the called listeners.
*
* @param Request|null $request The request to get listeners for
*
* @return array An array of called listeners
*/
public function getCalledListeners(/* Request $request = null */);
/**
* Gets the not called listeners.
*
* @param Request|null $request The request to get listeners for
*
* @return array An array of not called listeners
*/
public function getNotCalledListeners(/* Request $request = null */);
}

View File

@@ -12,19 +12,14 @@
namespace Symfony\Component\EventDispatcher\Debug;
use Psr\EventDispatcher\StoppableEventInterface;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\LegacyEventProxy;
use Symfony\Component\Stopwatch\Stopwatch;
use Symfony\Component\VarDumper\Caster\ClassStub;
use Symfony\Contracts\EventDispatcher\Event as ContractsEvent;
/**
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 4.3: the "Event" type-hint on __invoke() will be replaced by "object" in 5.0
*/
class WrappedListener
final class WrappedListener
{
private $listener;
private $optimizedListener;
@@ -48,13 +43,13 @@ class WrappedListener
$this->stoppedPropagation = false;
if (\is_array($listener)) {
$this->name = \is_object($listener[0]) ? \get_class($listener[0]) : $listener[0];
$this->name = \is_object($listener[0]) ? get_debug_type($listener[0]) : $listener[0];
$this->pretty = $this->name.'::'.$listener[1];
} elseif ($listener instanceof \Closure) {
$r = new \ReflectionFunction($listener);
if (str_contains($r->name, '{closure}')) {
$this->pretty = $this->name = 'closure';
} elseif ($class = $r->getClosureScopeClass()) {
} elseif ($class = \PHP_VERSION_ID >= 80111 ? $r->getClosureCalledClass() : $r->getClosureScopeClass()) {
$this->name = $class->name;
$this->pretty = $this->name.'::'.$r->name;
} else {
@@ -63,7 +58,7 @@ class WrappedListener
} elseif (\is_string($listener)) {
$this->pretty = $this->name = $listener;
} else {
$this->name = \get_class($listener);
$this->name = get_debug_type($listener);
$this->pretty = $this->name.'::__invoke';
}
@@ -81,22 +76,22 @@ class WrappedListener
return $this->listener;
}
public function wasCalled()
public function wasCalled(): bool
{
return $this->called;
}
public function stoppedPropagation()
public function stoppedPropagation(): bool
{
return $this->stoppedPropagation;
}
public function getPretty()
public function getPretty(): string
{
return $this->pretty;
}
public function getInfo($eventName)
public function getInfo(string $eventName): array
{
if (null === $this->stub) {
$this->stub = self::$hasClassStub ? new ClassStub($this->pretty.'()', $this->listener) : $this->pretty.'()';
@@ -110,12 +105,8 @@ class WrappedListener
];
}
public function __invoke(Event $event, $eventName, EventDispatcherInterface $dispatcher)
public function __invoke(object $event, string $eventName, EventDispatcherInterface $dispatcher): void
{
if ($event instanceof LegacyEventProxy) {
$event = $event->getEvent();
}
$dispatcher = $this->dispatcher ?: $dispatcher;
$this->called = true;
@@ -129,7 +120,7 @@ class WrappedListener
$e->stop();
}
if (($event instanceof Event || $event instanceof ContractsEvent || $event instanceof StoppableEventInterface) && $event->isPropagationStopped()) {
if ($event instanceof StoppableEventInterface && $event->isPropagationStopped()) {
$this->stoppedPropagation = true;
}
}

View File

@@ -26,6 +26,10 @@ class AddEventAliasesPass implements CompilerPassInterface
public function __construct(array $eventAliases, string $eventAliasesParameter = 'event_dispatcher.event_aliases')
{
if (1 < \func_num_args()) {
trigger_deprecation('symfony/event-dispatcher', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
}
$this->eventAliases = $eventAliases;
$this->eventAliasesParameter = $eventAliasesParameter;
}

View File

@@ -16,7 +16,6 @@ use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\EventDispatcher\Event as LegacyEvent;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Contracts\EventDispatcher\Event;
@@ -32,20 +31,48 @@ class RegisterListenersPass implements CompilerPassInterface
protected $eventAliasesParameter;
private $hotPathEvents = [];
private $hotPathTagName;
private $hotPathTagName = 'container.hot_path';
private $noPreloadEvents = [];
private $noPreloadTagName = 'container.no_preload';
public function __construct(string $dispatcherService = 'event_dispatcher', string $listenerTag = 'kernel.event_listener', string $subscriberTag = 'kernel.event_subscriber', string $eventAliasesParameter = 'event_dispatcher.event_aliases')
{
if (0 < \func_num_args()) {
trigger_deprecation('symfony/event-dispatcher', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
}
$this->dispatcherService = $dispatcherService;
$this->listenerTag = $listenerTag;
$this->subscriberTag = $subscriberTag;
$this->eventAliasesParameter = $eventAliasesParameter;
}
public function setHotPathEvents(array $hotPathEvents, $tagName = 'container.hot_path')
/**
* @return $this
*/
public function setHotPathEvents(array $hotPathEvents)
{
$this->hotPathEvents = array_flip($hotPathEvents);
$this->hotPathTagName = $tagName;
if (1 < \func_num_args()) {
trigger_deprecation('symfony/event-dispatcher', '5.4', 'Configuring "$tagName" in "%s" is deprecated.', __METHOD__);
$this->hotPathTagName = func_get_arg(1);
}
return $this;
}
/**
* @return $this
*/
public function setNoPreloadEvents(array $noPreloadEvents): self
{
$this->noPreloadEvents = array_flip($noPreloadEvents);
if (1 < \func_num_args()) {
trigger_deprecation('symfony/event-dispatcher', '5.4', 'Configuring "$tagName" in "%s" is deprecated.', __METHOD__);
$this->noPreloadTagName = func_get_arg(1);
}
return $this;
}
@@ -62,9 +89,11 @@ class RegisterListenersPass implements CompilerPassInterface
$aliases = $container->getParameter($this->eventAliasesParameter);
}
$definition = $container->findDefinition($this->dispatcherService);
$globalDispatcherDefinition = $container->findDefinition($this->dispatcherService);
foreach ($container->findTaggedServiceIds($this->listenerTag, true) as $id => $events) {
$noPreload = 0;
foreach ($events as $event) {
$priority = $event['priority'] ?? 0;
@@ -91,17 +120,28 @@ class RegisterListenersPass implements CompilerPassInterface
}
}
$definition->addMethodCall('addListener', [$event['event'], [new ServiceClosureArgument(new Reference($id)), $event['method']], $priority]);
$dispatcherDefinition = $globalDispatcherDefinition;
if (isset($event['dispatcher'])) {
$dispatcherDefinition = $container->getDefinition($event['dispatcher']);
}
$dispatcherDefinition->addMethodCall('addListener', [$event['event'], [new ServiceClosureArgument(new Reference($id)), $event['method']], $priority]);
if (isset($this->hotPathEvents[$event['event']])) {
$container->getDefinition($id)->addTag($this->hotPathTagName);
} elseif (isset($this->noPreloadEvents[$event['event']])) {
++$noPreload;
}
}
if ($noPreload && \count($events) === $noPreload) {
$container->getDefinition($id)->addTag($this->noPreloadTagName);
}
}
$extractingDispatcher = new ExtractingEventDispatcher();
foreach ($container->findTaggedServiceIds($this->subscriberTag, true) as $id => $attributes) {
foreach ($container->findTaggedServiceIds($this->subscriberTag, true) as $id => $tags) {
$def = $container->getDefinition($id);
// We must assume that the class value has been correctly filled, even if the service is created by a factory
@@ -115,17 +155,38 @@ class RegisterListenersPass implements CompilerPassInterface
}
$class = $r->name;
$dispatcherDefinitions = [];
foreach ($tags as $attributes) {
if (!isset($attributes['dispatcher']) || isset($dispatcherDefinitions[$attributes['dispatcher']])) {
continue;
}
$dispatcherDefinitions[$attributes['dispatcher']] = $container->getDefinition($attributes['dispatcher']);
}
if (!$dispatcherDefinitions) {
$dispatcherDefinitions = [$globalDispatcherDefinition];
}
$noPreload = 0;
ExtractingEventDispatcher::$aliases = $aliases;
ExtractingEventDispatcher::$subscriber = $class;
$extractingDispatcher->addSubscriber($extractingDispatcher);
foreach ($extractingDispatcher->listeners as $args) {
$args[1] = [new ServiceClosureArgument(new Reference($id)), $args[1]];
$definition->addMethodCall('addListener', $args);
foreach ($dispatcherDefinitions as $dispatcherDefinition) {
$dispatcherDefinition->addMethodCall('addListener', $args);
}
if (isset($this->hotPathEvents[$args[0]])) {
$container->getDefinition($id)->addTag($this->hotPathTagName);
} elseif (isset($this->noPreloadEvents[$args[0]])) {
++$noPreload;
}
}
if ($noPreload && \count($extractingDispatcher->listeners) === $noPreload) {
$container->getDefinition($id)->addTag($this->noPreloadTagName);
}
$extractingDispatcher->listeners = [];
ExtractingEventDispatcher::$aliases = [];
}
@@ -141,7 +202,6 @@ class RegisterListenersPass implements CompilerPassInterface
|| !($type = $m->getParameters()[0]->getType()) instanceof \ReflectionNamedType
|| $type->isBuiltin()
|| Event::class === ($name = $type->getName())
|| LegacyEvent::class === $name
) {
throw new InvalidArgumentException(sprintf('Service "%s" must define the "event" attribute on "%s" tags.', $id, $this->listenerTag));
}
@@ -160,7 +220,7 @@ class ExtractingEventDispatcher extends EventDispatcher implements EventSubscrib
public static $aliases = [];
public static $subscriber;
public function addListener($eventName, $listener, $priority = 0)
public function addListener(string $eventName, $listener, int $priority = 0)
{
$this->listeners[] = [$eventName, $listener[1], $priority];
}

View File

@@ -1,38 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\EventDispatcher;
/**
* @deprecated since Symfony 4.3, use "Symfony\Contracts\EventDispatcher\Event" instead
*/
class Event
{
private $propagationStopped = false;
/**
* @return bool Whether propagation was already stopped for this event
*
* @deprecated since Symfony 4.3, use "Symfony\Contracts\EventDispatcher\Event" instead
*/
public function isPropagationStopped()
{
return $this->propagationStopped;
}
/**
* @deprecated since Symfony 4.3, use "Symfony\Contracts\EventDispatcher\Event" instead
*/
public function stopPropagation()
{
$this->propagationStopped = true;
}
}

View File

@@ -13,7 +13,6 @@ namespace Symfony\Component\EventDispatcher;
use Psr\EventDispatcher\StoppableEventInterface;
use Symfony\Component\EventDispatcher\Debug\WrappedListener;
use Symfony\Contracts\EventDispatcher\Event as ContractsEvent;
/**
* The EventDispatcherInterface is the central point of Symfony's event listener system.
@@ -45,25 +44,12 @@ class EventDispatcher implements EventDispatcherInterface
/**
* {@inheritdoc}
*
* @param string|null $eventName
*/
public function dispatch($event/* , string $eventName = null */)
public function dispatch(object $event, string $eventName = null): object
{
$eventName = 1 < \func_num_args() ? func_get_arg(1) : null;
$eventName = $eventName ?? \get_class($event);
if (\is_object($event)) {
$eventName = $eventName ?? \get_class($event);
} elseif (\is_string($event) && (null === $eventName || $eventName instanceof ContractsEvent || $eventName instanceof Event)) {
@trigger_error(sprintf('Calling the "%s::dispatch()" method with the event name as the first argument is deprecated since Symfony 4.3, pass it as the second argument and provide the event object as the first argument instead.', EventDispatcherInterface::class), \E_USER_DEPRECATED);
$swap = $event;
$event = $eventName ?? new Event();
$eventName = $swap;
} else {
throw new \TypeError(sprintf('Argument 1 passed to "%s::dispatch()" must be an object, "%s" given.', EventDispatcherInterface::class, \is_object($event) ? \get_class($event) : \gettype($event)));
}
if (null !== $this->optimized && null !== $eventName) {
if (null !== $this->optimized) {
$listeners = $this->optimized[$eventName] ?? (empty($this->listeners[$eventName]) ? [] : $this->optimizeListeners($eventName));
} else {
$listeners = $this->getListeners($eventName);
@@ -79,7 +65,7 @@ class EventDispatcher implements EventDispatcherInterface
/**
* {@inheritdoc}
*/
public function getListeners($eventName = null)
public function getListeners(string $eventName = null)
{
if (null !== $eventName) {
if (empty($this->listeners[$eventName])) {
@@ -105,7 +91,7 @@ class EventDispatcher implements EventDispatcherInterface
/**
* {@inheritdoc}
*/
public function getListenerPriority($eventName, $listener)
public function getListenerPriority(string $eventName, $listener)
{
if (empty($this->listeners[$eventName])) {
return null;
@@ -134,7 +120,7 @@ class EventDispatcher implements EventDispatcherInterface
/**
* {@inheritdoc}
*/
public function hasListeners($eventName = null)
public function hasListeners(string $eventName = null)
{
if (null !== $eventName) {
return !empty($this->listeners[$eventName]);
@@ -152,7 +138,7 @@ class EventDispatcher implements EventDispatcherInterface
/**
* {@inheritdoc}
*/
public function addListener($eventName, $listener, $priority = 0)
public function addListener(string $eventName, $listener, int $priority = 0)
{
$this->listeners[$eventName][$priority][] = $listener;
unset($this->sorted[$eventName], $this->optimized[$eventName]);
@@ -161,7 +147,7 @@ class EventDispatcher implements EventDispatcherInterface
/**
* {@inheritdoc}
*/
public function removeListener($eventName, $listener)
public function removeListener(string $eventName, $listener)
{
if (empty($this->listeners[$eventName])) {
return;
@@ -233,34 +219,14 @@ class EventDispatcher implements EventDispatcherInterface
* @param string $eventName The name of the event to dispatch
* @param object $event The event object to pass to the event handlers/listeners
*/
protected function callListeners(iterable $listeners, string $eventName, $event)
protected function callListeners(iterable $listeners, string $eventName, object $event)
{
if ($event instanceof Event) {
$this->doDispatch($listeners, $eventName, $event);
return;
}
$stoppable = $event instanceof ContractsEvent || $event instanceof StoppableEventInterface;
$stoppable = $event instanceof StoppableEventInterface;
foreach ($listeners as $listener) {
if ($stoppable && $event->isPropagationStopped()) {
break;
}
// @deprecated: the ternary operator is part of a BC layer and should be removed in 5.0
$listener($listener instanceof WrappedListener ? new LegacyEventProxy($event) : $event, $eventName, $this);
}
}
/**
* @deprecated since Symfony 4.3, use callListeners() instead
*/
protected function doDispatch($listeners, $eventName, Event $event)
{
foreach ($listeners as $listener) {
if ($event->isPropagationStopped()) {
break;
}
$listener($event, $eventName, $this);
}
}

View File

@@ -25,12 +25,10 @@ interface EventDispatcherInterface extends ContractsEventDispatcherInterface
/**
* Adds an event listener that listens on the specified events.
*
* @param string $eventName The event to listen on
* @param callable $listener The listener
* @param int $priority The higher this value, the earlier an event
* listener will be triggered in the chain (defaults to 0)
* @param int $priority The higher this value, the earlier an event
* listener will be triggered in the chain (defaults to 0)
*/
public function addListener($eventName, $listener, $priority = 0);
public function addListener(string $eventName, callable $listener, int $priority = 0);
/**
* Adds an event subscriber.
@@ -42,41 +40,31 @@ interface EventDispatcherInterface extends ContractsEventDispatcherInterface
/**
* Removes an event listener from the specified events.
*
* @param string $eventName The event to remove a listener from
* @param callable $listener The listener to remove
*/
public function removeListener($eventName, $listener);
public function removeListener(string $eventName, callable $listener);
public function removeSubscriber(EventSubscriberInterface $subscriber);
/**
* Gets the listeners of a specific event or all listeners sorted by descending priority.
*
* @param string|null $eventName The name of the event
*
* @return array The event listeners for the specified event, or all event listeners by event name
* @return array<callable[]|callable>
*/
public function getListeners($eventName = null);
public function getListeners(string $eventName = null);
/**
* Gets the listener priority for a specific event.
*
* Returns null if the event or the listener does not exist.
*
* @param string $eventName The name of the event
* @param callable $listener The listener
*
* @return int|null The event listener priority
* @return int|null
*/
public function getListenerPriority($eventName, $listener);
public function getListenerPriority(string $eventName, callable $listener);
/**
* Checks whether an event has any registered listeners.
*
* @param string|null $eventName The name of the event
*
* @return bool true if the specified event has any listeners, false otherwise
* @return bool
*/
public function hasListeners($eventName = null);
public function hasListeners(string $eventName = null);
}

View File

@@ -43,7 +43,7 @@ interface EventSubscriberInterface
* The code must not depend on runtime state as it will only be called at compile time.
* All logic depending on runtime state must be put into the individual methods handling the events.
*
* @return array<string, mixed> The event names to listen to
* @return array<string, string|array{0: string, 1: int}|list<array{0: string, 1?: int}>>
*/
public static function getSubscribedEvents();
}

View File

@@ -11,12 +11,17 @@
namespace Symfony\Component\EventDispatcher;
use Symfony\Contracts\EventDispatcher\Event;
/**
* Event encapsulation class.
*
* Encapsulates events thus decoupling the observer from the subject they encapsulate.
*
* @author Drak <drak@zikula.org>
*
* @implements \ArrayAccess<string, mixed>
* @implements \IteratorAggregate<string, mixed>
*/
class GenericEvent extends Event implements \ArrayAccess, \IteratorAggregate
{
@@ -38,7 +43,7 @@ class GenericEvent extends Event implements \ArrayAccess, \IteratorAggregate
/**
* Getter for subject property.
*
* @return mixed The observer subject
* @return mixed
*/
public function getSubject()
{
@@ -48,13 +53,11 @@ class GenericEvent extends Event implements \ArrayAccess, \IteratorAggregate
/**
* Get argument by key.
*
* @param string $key Key
*
* @return mixed Contents of array key
* @return mixed
*
* @throws \InvalidArgumentException if key is not found
*/
public function getArgument($key)
public function getArgument(string $key)
{
if ($this->hasArgument($key)) {
return $this->arguments[$key];
@@ -66,12 +69,11 @@ class GenericEvent extends Event implements \ArrayAccess, \IteratorAggregate
/**
* Add argument to event.
*
* @param string $key Argument name
* @param mixed $value Value
* @param mixed $value Value
*
* @return $this
*/
public function setArgument($key, $value)
public function setArgument(string $key, $value)
{
$this->arguments[$key] = $value;
@@ -91,8 +93,6 @@ class GenericEvent extends Event implements \ArrayAccess, \IteratorAggregate
/**
* Set args property.
*
* @param array $args Arguments
*
* @return $this
*/
public function setArguments(array $args = [])
@@ -105,11 +105,9 @@ class GenericEvent extends Event implements \ArrayAccess, \IteratorAggregate
/**
* Has argument.
*
* @param string $key Key of arguments array
*
* @return bool
*/
public function hasArgument($key)
public function hasArgument(string $key)
{
return \array_key_exists($key, $this->arguments);
}
@@ -174,7 +172,7 @@ class GenericEvent extends Event implements \ArrayAccess, \IteratorAggregate
/**
* IteratorAggregate for iterating over the object like an array.
*
* @return \ArrayIterator
* @return \ArrayIterator<string, mixed>
*/
#[\ReturnTypeWillChange]
public function getIterator()

View File

@@ -22,32 +22,21 @@ class ImmutableEventDispatcher implements EventDispatcherInterface
public function __construct(EventDispatcherInterface $dispatcher)
{
$this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher);
$this->dispatcher = $dispatcher;
}
/**
* {@inheritdoc}
*
* @param string|null $eventName
*/
public function dispatch($event/* , string $eventName = null */)
public function dispatch(object $event, string $eventName = null): object
{
$eventName = 1 < \func_num_args() ? func_get_arg(1) : null;
if (\is_scalar($event)) {
// deprecated
$swap = $event;
$event = $eventName ?? new Event();
$eventName = $swap;
}
return $this->dispatcher->dispatch($event, $eventName);
}
/**
* {@inheritdoc}
*/
public function addListener($eventName, $listener, $priority = 0)
public function addListener(string $eventName, $listener, int $priority = 0)
{
throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
}
@@ -63,7 +52,7 @@ class ImmutableEventDispatcher implements EventDispatcherInterface
/**
* {@inheritdoc}
*/
public function removeListener($eventName, $listener)
public function removeListener(string $eventName, $listener)
{
throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
}
@@ -79,7 +68,7 @@ class ImmutableEventDispatcher implements EventDispatcherInterface
/**
* {@inheritdoc}
*/
public function getListeners($eventName = null)
public function getListeners(string $eventName = null)
{
return $this->dispatcher->getListeners($eventName);
}
@@ -87,7 +76,7 @@ class ImmutableEventDispatcher implements EventDispatcherInterface
/**
* {@inheritdoc}
*/
public function getListenerPriority($eventName, $listener)
public function getListenerPriority(string $eventName, $listener)
{
return $this->dispatcher->getListenerPriority($eventName, $listener);
}
@@ -95,7 +84,7 @@ class ImmutableEventDispatcher implements EventDispatcherInterface
/**
* {@inheritdoc}
*/
public function hasListeners($eventName = null)
public function hasListeners(string $eventName = null)
{
return $this->dispatcher->hasListeners($eventName);
}

View File

@@ -11,137 +11,21 @@
namespace Symfony\Component\EventDispatcher;
use Psr\EventDispatcher\StoppableEventInterface;
use Symfony\Contracts\EventDispatcher\Event as ContractsEvent;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface as ContractsEventDispatcherInterface;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
trigger_deprecation('symfony/event-dispatcher', '5.1', '%s is deprecated, use the event dispatcher without the proxy.', LegacyEventDispatcherProxy::class);
/**
* A helper class to provide BC/FC with the legacy signature of EventDispatcherInterface::dispatch().
*
* This class should be deprecated in Symfony 5.1
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @deprecated since Symfony 5.1
*/
final class LegacyEventDispatcherProxy implements EventDispatcherInterface
final class LegacyEventDispatcherProxy
{
private $dispatcher;
public static function decorate(?ContractsEventDispatcherInterface $dispatcher): ?ContractsEventDispatcherInterface
public static function decorate(?EventDispatcherInterface $dispatcher): ?EventDispatcherInterface
{
if (null === $dispatcher) {
return null;
}
$r = new \ReflectionMethod($dispatcher, 'dispatch');
$param2 = $r->getParameters()[1] ?? null;
if (!$param2 || !$param2->hasType() || $param2->getType()->isBuiltin()) {
return $dispatcher;
}
@trigger_error(sprintf('The signature of the "%s::dispatch()" method should be updated to "dispatch($event, string $eventName = null)", not doing so is deprecated since Symfony 4.3.', $r->class), \E_USER_DEPRECATED);
$self = new self();
$self->dispatcher = $dispatcher;
return $self;
}
/**
* {@inheritdoc}
*
* @param string|null $eventName
*
* @return object
*/
public function dispatch($event/* , string $eventName = null */)
{
$eventName = 1 < \func_num_args() ? func_get_arg(1) : null;
if (\is_object($event)) {
$eventName = $eventName ?? \get_class($event);
} elseif (\is_string($event) && (null === $eventName || $eventName instanceof ContractsEvent || $eventName instanceof Event)) {
@trigger_error(sprintf('Calling the "%s::dispatch()" method with the event name as the first argument is deprecated since Symfony 4.3, pass it as the second argument and provide the event object as the first argument instead.', ContractsEventDispatcherInterface::class), \E_USER_DEPRECATED);
$swap = $event;
$event = $eventName ?? new Event();
$eventName = $swap;
} else {
throw new \TypeError(sprintf('Argument 1 passed to "%s::dispatch()" must be an object, "%s" given.', ContractsEventDispatcherInterface::class, \is_object($event) ? \get_class($event) : \gettype($event)));
}
$listeners = $this->getListeners($eventName);
$stoppable = $event instanceof Event || $event instanceof ContractsEvent || $event instanceof StoppableEventInterface;
foreach ($listeners as $listener) {
if ($stoppable && $event->isPropagationStopped()) {
break;
}
$listener($event, $eventName, $this);
}
return $event;
}
/**
* {@inheritdoc}
*/
public function addListener($eventName, $listener, $priority = 0)
{
return $this->dispatcher->addListener($eventName, $listener, $priority);
}
/**
* {@inheritdoc}
*/
public function addSubscriber(EventSubscriberInterface $subscriber)
{
return $this->dispatcher->addSubscriber($subscriber);
}
/**
* {@inheritdoc}
*/
public function removeListener($eventName, $listener)
{
return $this->dispatcher->removeListener($eventName, $listener);
}
/**
* {@inheritdoc}
*/
public function removeSubscriber(EventSubscriberInterface $subscriber)
{
return $this->dispatcher->removeSubscriber($subscriber);
}
/**
* {@inheritdoc}
*/
public function getListeners($eventName = null): array
{
return $this->dispatcher->getListeners($eventName);
}
/**
* {@inheritdoc}
*/
public function getListenerPriority($eventName, $listener): ?int
{
return $this->dispatcher->getListenerPriority($eventName, $listener);
}
/**
* {@inheritdoc}
*/
public function hasListeners($eventName = null): bool
{
return $this->dispatcher->hasListeners($eventName);
}
/**
* Proxies all method calls to the original event dispatcher.
*/
public function __call($method, $arguments)
{
return $this->dispatcher->{$method}(...$arguments);
return $dispatcher;
}
}

View File

@@ -1,62 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\EventDispatcher;
use Psr\EventDispatcher\StoppableEventInterface;
use Symfony\Contracts\EventDispatcher\Event as ContractsEvent;
/**
* @internal to be removed in 5.0.
*/
final class LegacyEventProxy extends Event
{
private $event;
/**
* @param object $event
*/
public function __construct($event)
{
$this->event = $event;
}
/**
* @return object $event
*/
public function getEvent()
{
return $this->event;
}
public function isPropagationStopped(): bool
{
if (!$this->event instanceof ContractsEvent && !$this->event instanceof StoppableEventInterface) {
return false;
}
return $this->event->isPropagationStopped();
}
public function stopPropagation()
{
if (!$this->event instanceof ContractsEvent) {
return;
}
$this->event->stopPropagation();
}
public function __call($name, $args)
{
return $this->event->{$name}(...$args);
}
}

View File

@@ -16,26 +16,27 @@
}
],
"require": {
"php": ">=7.1.3",
"symfony/event-dispatcher-contracts": "^1.1",
"php": ">=7.2.5",
"symfony/deprecation-contracts": "^2.1|^3",
"symfony/event-dispatcher-contracts": "^2|^3",
"symfony/polyfill-php80": "^1.16"
},
"require-dev": {
"symfony/dependency-injection": "^3.4|^4.0|^5.0",
"symfony/expression-language": "^3.4|^4.0|^5.0",
"symfony/config": "^3.4|^4.0|^5.0",
"symfony/error-handler": "~3.4|~4.4",
"symfony/http-foundation": "^3.4|^4.0|^5.0",
"symfony/service-contracts": "^1.1|^2",
"symfony/stopwatch": "^3.4|^4.0|^5.0",
"symfony/dependency-injection": "^4.4|^5.0|^6.0",
"symfony/expression-language": "^4.4|^5.0|^6.0",
"symfony/config": "^4.4|^5.0|^6.0",
"symfony/error-handler": "^4.4|^5.0|^6.0",
"symfony/http-foundation": "^4.4|^5.0|^6.0",
"symfony/service-contracts": "^1.1|^2|^3",
"symfony/stopwatch": "^4.4|^5.0|^6.0",
"psr/log": "^1|^2|^3"
},
"conflict": {
"symfony/dependency-injection": "<3.4"
"symfony/dependency-injection": "<4.4"
},
"provide": {
"psr/event-dispatcher-implementation": "1.0",
"symfony/event-dispatcher-implementation": "1.1"
"symfony/event-dispatcher-implementation": "2.0"
},
"suggest": {
"symfony/dependency-injection": "",