Skip to content

Commit

Permalink
feature #28920 [EventDispatcher] swap arguments of dispatch() to allo…
Browse files Browse the repository at this point in the history
…w registering events by FQCN (nicolas-grekas)

This PR was merged into the 4.3-dev branch.

Discussion
----------

[EventDispatcher] swap arguments of dispatch() to allow registering events by FQCN

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | yes
| Tests pass?   | yes
| Fixed tickets | -
| License       | MIT
| Doc PR        | -

PR green and ready. From UPGRADE files:

 EventDispatcher
---------------

 * The signature of the `EventDispatcherInterface::dispatch()` method should be updated to `dispatch($event, string $eventName = null)`, not doing so is deprecated

HttpKernel
----------

 * Renamed `FilterControllerArgumentsEvent` to `ControllerArgumentsEvent`
 * Renamed `FilterControllerEvent` to `ControllerEvent`
 * Renamed `FilterResponseEvent` to `ResponseEvent`
 * Renamed `GetResponseEvent` to `RequestEvent`
 * Renamed `GetResponseForControllerResultEvent` to `ViewEvent`
 * Renamed `GetResponseForExceptionEvent` to `ExceptionEvent`
 * Renamed `PostResponseEvent` to `TerminateEvent`

Security
---------

 * The `ListenerInterface` is deprecated, turn your listeners into callables instead.
 * The `Firewall::handleRequest()` method is deprecated, use `Firewall::callListeners()` instead.

Commits
-------

75369da [EventDispatcher] swap arguments of dispatch() to allow registering events by FQCN
  • Loading branch information
fabpot committed Mar 20, 2019
2 parents 81bf2ab + 75369da commit 1479a26
Show file tree
Hide file tree
Showing 163 changed files with 1,649 additions and 658 deletions.
16 changes: 15 additions & 1 deletion UPGRADE-4.3.md
Expand Up @@ -21,6 +21,11 @@ Config

* Deprecated using environment variables with `cannotBeEmpty()` if the value is validated with `validate()`

EventDispatcher
---------------

* The signature of the `EventDispatcherInterface::dispatch()` method should be updated to `dispatch($event, string $eventName = null)`, not doing so is deprecated

Form
----

Expand Down Expand Up @@ -55,7 +60,14 @@ HttpFoundation
HttpKernel
----------

* renamed `Client` to `HttpKernelBrowser`
* Renamed `Client` to `HttpKernelBrowser`
* Renamed `FilterControllerArgumentsEvent` to `ControllerArgumentsEvent`
* Renamed `FilterControllerEvent` to `ControllerEvent`
* Renamed `FilterResponseEvent` to `ResponseEvent`
* Renamed `GetResponseEvent` to `RequestEvent`
* Renamed `GetResponseForControllerResultEvent` to `ViewEvent`
* Renamed `GetResponseForExceptionEvent` to `ExceptionEvent`
* Renamed `PostResponseEvent` to `TerminateEvent`

Messenger
---------
Expand All @@ -81,6 +93,8 @@ Security
Use the `getReachableRoleNames()` method instead.
* The `getRoles()` method of the `TokenInterface` is deprecated. Tokens must implement the `getRoleNames()`
method instead and return roles as strings.
* The `ListenerInterface` is deprecated, turn your listeners into callables instead.
* The `Firewall::handleRequest()` method is deprecated, use `Firewall::callListeners()` instead.
* The `AbstractToken::serialize()`, `AbstractToken::unserialize()`,
`AuthenticationException::serialize()` and `AuthenticationException::unserialize()`
methods are now final, use `getState()` and `setState()` instead.
Expand Down
10 changes: 10 additions & 0 deletions UPGRADE-5.0.md
Expand Up @@ -70,6 +70,7 @@ EventDispatcher
---------------

* The `TraceableEventDispatcherInterface` has been removed.
* The signature of the `EventDispatcherInterface::dispatch()` method has been updated to `dispatch($event, string $eventName = null)`

Filesystem
----------
Expand Down Expand Up @@ -206,6 +207,13 @@ HttpKernel
* Removed the first and second constructor argument of `ConfigDataCollector`
* Removed `ConfigDataCollector::getApplicationName()`
* Removed `ConfigDataCollector::getApplicationVersion()`
* Removed `FilterControllerArgumentsEvent`, use `ControllerArgumentsEvent` instead
* Removed `FilterControllerEvent`, use `ControllerEvent` instead
* Removed `FilterResponseEvent`, use `ResponseEvent` instead
* Removed `GetResponseEvent`, use `RequestEvent` instead
* Removed `GetResponseForControllerResultEvent`, use `ViewEvent` instead
* Removed `GetResponseForExceptionEvent`, use `ExceptionEvent` instead
* Removed `PostResponseEvent`, use `TerminateEvent` instead

Messenger
---------
Expand Down Expand Up @@ -262,6 +270,8 @@ Security
* `SimpleAuthenticatorInterface`, `SimpleFormAuthenticatorInterface`, `SimplePreAuthenticatorInterface`,
`SimpleAuthenticationProvider`, `SimpleAuthenticationHandler`, `SimpleFormAuthenticationListener` and
`SimplePreAuthenticationListener` have been removed. Use Guard instead.
* The `ListenerInterface` has been removed, turn your listeners into callables instead.
* The `Firewall::handleRequest()` method has been removed, use `Firewall::callListeners()` instead.
* `\Serializable` interface has been removed from `AbstractToken` and `AuthenticationException`,
thus `serialize()` and `unserialize()` aren't available.
Use `getState()` and `setState()` instead.
Expand Down
Expand Up @@ -63,7 +63,7 @@ public function testOnSubmitDoNothing()
$submittedData = ['test'];
$event = new FormEvent($this->getForm(), $submittedData);

$this->dispatcher->dispatch(FormEvents::SUBMIT, $event);
$this->dispatcher->dispatch($event, FormEvents::SUBMIT);

$this->assertTrue($this->collection->contains('test'));
$this->assertSame(1, $this->collection->count());
Expand All @@ -74,7 +74,7 @@ public function testOnSubmitNullClearCollection()
$submittedData = [];
$event = new FormEvent($this->getForm(), $submittedData);

$this->dispatcher->dispatch(FormEvents::SUBMIT, $event);
$this->dispatcher->dispatch($event, FormEvents::SUBMIT);

$this->assertTrue($this->collection->isEmpty());
}
Expand Down
2 changes: 2 additions & 0 deletions src/Symfony/Bridge/Monolog/Handler/ChromePhpHandler.php
Expand Up @@ -19,6 +19,8 @@
* ChromePhpHandler.
*
* @author Christophe Coevoet <stof@notk.org>
*
* @final since Symfony 4.3
*/
class ChromePhpHandler extends BaseChromePhpHandler
{
Expand Down
2 changes: 2 additions & 0 deletions src/Symfony/Bridge/Monolog/Handler/FirePHPHandler.php
Expand Up @@ -19,6 +19,8 @@
* FirePHPHandler.
*
* @author Jordi Boggiano <j.boggiano@seld.be>
*
* @final since Symfony 4.3
*/
class FirePHPHandler extends BaseFirePHPHandler
{
Expand Down
2 changes: 2 additions & 0 deletions src/Symfony/Bridge/Monolog/Handler/SwiftMailerHandler.php
Expand Up @@ -19,6 +19,8 @@
* Extended SwiftMailerHandler that flushes mail queue if necessary.
*
* @author Philipp Kräutli <pkraeutli@astina.ch>
*
* @final since Symfony 4.3
*/
class SwiftMailerHandler extends BaseSwiftMailerHandler
{
Expand Down
2 changes: 2 additions & 0 deletions src/Symfony/Bridge/Monolog/Processor/WebProcessor.php
Expand Up @@ -20,6 +20,8 @@
* WebProcessor override to read from the HttpFoundation's Request.
*
* @author Jordi Boggiano <j.boggiano@seld.be>
*
* @final since Symfony 4.3
*/
class WebProcessor extends BaseWebProcessor implements EventSubscriberInterface
{
Expand Down
Expand Up @@ -196,12 +196,12 @@ public function testLogsFromListeners()
});

$event = new ConsoleCommandEvent(new Command('foo'), $this->getMockBuilder('Symfony\Component\Console\Input\InputInterface')->getMock(), $output);
$dispatcher->dispatch(ConsoleEvents::COMMAND, $event);
$dispatcher->dispatch($event, ConsoleEvents::COMMAND);
$this->assertContains('Before command message.', $out = $output->fetch());
$this->assertContains('After command message.', $out);

$event = new ConsoleTerminateEvent(new Command('foo'), $this->getMockBuilder('Symfony\Component\Console\Input\InputInterface')->getMock(), $output, 0);
$dispatcher->dispatch(ConsoleEvents::TERMINATE, $event);
$dispatcher->dispatch($event, ConsoleEvents::TERMINATE);
$this->assertContains('Before terminate message.', $out = $output->fetch());
$this->assertContains('After terminate message.', $out);
}
Expand Down
Expand Up @@ -15,6 +15,7 @@
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Monolog\Processor\WebProcessor;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\RequestEvent;

class WebProcessorTest extends TestCase
{
Expand Down Expand Up @@ -87,7 +88,7 @@ private function createRequestEvent($additionalServerParameters = []): array
$request->server->replace($server);
$request->headers->replace($server);

$event = $this->getMockBuilder('Symfony\Component\HttpKernel\Event\GetResponseEvent')
$event = $this->getMockBuilder(RequestEvent::class)
->disableOriginalConstructor()
->getMock();
$event->expects($this->any())
Expand Down
4 changes: 1 addition & 3 deletions src/Symfony/Bridge/Monolog/composer.json
Expand Up @@ -19,11 +19,10 @@
"php": "^7.1.3",
"monolog/monolog": "~1.19",
"symfony/contracts": "^1.0",
"symfony/http-kernel": "~3.4|~4.0"
"symfony/http-kernel": "^4.3"
},
"require-dev": {
"symfony/console": "~3.4|~4.0",
"symfony/event-dispatcher": "~3.4|~4.0",
"symfony/security-core": "~3.4|~4.0",
"symfony/var-dumper": "~3.4|~4.0"
},
Expand All @@ -34,7 +33,6 @@
"suggest": {
"symfony/http-kernel": "For using the debugging handlers together with the response life cycle of the HTTP kernel.",
"symfony/console": "For the possibility to show log messages in console commands depending on verbosity settings.",
"symfony/event-dispatcher": "Needed when using log messages in console commands.",
"symfony/var-dumper": "For using the debugging handlers like the console handler or the log server handler."
},
"autoload": {
Expand Down
32 changes: 32 additions & 0 deletions src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml
Expand Up @@ -4,6 +4,38 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd">

<parameters>
<!-- this parameter is used at compile time in RegisterListenersPass -->
<parameter key="event_dispatcher.event_aliases" type="collection">
<parameter key="Symfony\Component\Console\Event\ConsoleCommandEvent">console.command</parameter>
<parameter key="Symfony\Component\Console\Event\ConsoleErrorEvent">console.error</parameter>
<parameter key="Symfony\Component\Console\Event\ConsoleTerminateEvent">console.terminate</parameter>
<parameter key="Symfony\Component\Form\Event\PreSubmitEvent">form.pre_submit</parameter>
<parameter key="Symfony\Component\Form\Event\SubmitEvent">form.submit</parameter>
<parameter key="Symfony\Component\Form\Event\PostSubmitEvent">form.post_submit</parameter>
<parameter key="Symfony\Component\Form\Event\PreSetDataEvent">form.pre_set_data</parameter>
<parameter key="Symfony\Component\Form\Event\PostSetDataEvent">form.post_set_data</parameter>
<parameter key="Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent">kernel.controller_arguments</parameter>
<parameter key="Symfony\Component\HttpKernel\Event\ControllerEvent">kernel.controller</parameter>
<parameter key="Symfony\Component\HttpKernel\Event\ResponseEvent">kernel.response</parameter>
<parameter key="Symfony\Component\HttpKernel\Event\FinishRequestEvent">kernel.finish_request</parameter>
<parameter key="Symfony\Component\HttpKernel\Event\RequestEvent">kernel.request</parameter>
<parameter key="Symfony\Component\HttpKernel\Event\ViewEvent">kernel.view</parameter>
<parameter key="Symfony\Component\HttpKernel\Event\ExceptionEvent">kernel.exception</parameter>
<parameter key="Symfony\Component\HttpKernel\Event\TerminateEvent">kernel.terminate</parameter>
<parameter key="Symfony\Component\Security\Core\Event\AuthenticationSuccessEvent">security.authentication.success</parameter>
<parameter key="Symfony\Component\Security\Core\Event\AuthenticationFailureEvent">security.authentication.failure</parameter>
<parameter key="Symfony\Component\Security\Http\Event\InteractiveLoginEvent">security.interactive_login</parameter>
<parameter key="Symfony\Component\Security\Http\Event\SwitchUserEvent">security.switch_user</parameter>
<parameter key="Symfony\Component\Workflow\Event\GuardEvent">workflow.guard</parameter>
<parameter key="Symfony\Component\Workflow\Event\LeaveEvent">workflow.leave</parameter>
<parameter key="Symfony\Component\Workflow\Event\TransitionEvent">workflow.transition</parameter>
<parameter key="Symfony\Component\Workflow\Event\EnterEvent">workflow.enter</parameter>
<parameter key="Symfony\Component\Workflow\Event\EnteredEvent">workflow.entered</parameter>
<parameter key="Symfony\Component\Workflow\Event\CompletedEvent">workflow.completed</parameter>
<parameter key="Symfony\Component\Workflow\Event\AnnounceEvent">workflow.announce</parameter>
</parameter>
</parameters>
<services>
<defaults public="false" />

Expand Down
Expand Up @@ -15,7 +15,7 @@
use Symfony\Bundle\FrameworkBundle\EventListener\ResolveControllerNameSubscriber;
use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;

class ResolveControllerNameSubscriberTest extends TestCase
Expand All @@ -33,7 +33,7 @@ public function testReplacesControllerAttribute()
$request->attributes->set('_controller', 'AppBundle:Starting:format');

$subscriber = new ResolveControllerNameSubscriber($parser);
$subscriber->onKernelRequest(new GetResponseEvent($httpKernel, $request, HttpKernelInterface::MASTER_REQUEST));
$subscriber->onKernelRequest(new RequestEvent($httpKernel, $request, HttpKernelInterface::MASTER_REQUEST));
$this->assertEquals('App\\Final\\Format::methodName', $request->attributes->get('_controller'));
}

Expand All @@ -51,7 +51,7 @@ public function testSkipsOtherControllerFormats($controller)
$request->attributes->set('_controller', $controller);

$subscriber = new ResolveControllerNameSubscriber($parser);
$subscriber->onKernelRequest(new GetResponseEvent($httpKernel, $request, HttpKernelInterface::MASTER_REQUEST));
$subscriber->onKernelRequest(new RequestEvent($httpKernel, $request, HttpKernelInterface::MASTER_REQUEST));
$this->assertEquals($controller, $request->attributes->get('_controller'));
}

Expand Down
1 change: 0 additions & 1 deletion src/Symfony/Bundle/FrameworkBundle/composer.json
Expand Up @@ -22,7 +22,6 @@
"symfony/config": "~4.2",
"symfony/contracts": "^1.0.2",
"symfony/dependency-injection": "^4.3",
"symfony/event-dispatcher": "^4.1",
"symfony/http-foundation": "^4.3",
"symfony/http-kernel": "^4.3",
"symfony/polyfill-mbstring": "~1.0",
Expand Down
Expand Up @@ -12,7 +12,7 @@
namespace Symfony\Bundle\SecurityBundle\Debug;

use Symfony\Bundle\SecurityBundle\EventListener\FirewallListener;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\Event\RequestEvent;

/**
* Firewall collecting called listeners.
Expand All @@ -28,11 +28,11 @@ public function getWrappedListeners()
return $this->wrappedListeners;
}

protected function handleRequest(GetResponseEvent $event, $listeners)
protected function callListeners(RequestEvent $event, iterable $listeners)
{
foreach ($listeners as $listener) {
$wrappedListener = new WrappedListener($listener);
$wrappedListener->handle($event);
$wrappedListener($event);
$this->wrappedListeners[] = $wrappedListener->getInfo();

if ($event->hasResponse()) {
Expand Down
23 changes: 18 additions & 5 deletions src/Symfony/Bundle/SecurityBundle/Debug/WrappedListener.php
Expand Up @@ -11,24 +11,32 @@

namespace Symfony\Bundle\SecurityBundle\Debug;

use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\Security\Http\Firewall\LegacyListenerTrait;
use Symfony\Component\Security\Http\Firewall\ListenerInterface;
use Symfony\Component\VarDumper\Caster\ClassStub;

/**
* Wraps a security listener for calls record.
*
* @author Robin Chalas <robin.chalas@gmail.com>
*
* @internal since Symfony 4.3
*/
final class WrappedListener implements ListenerInterface
{
use LegacyListenerTrait;

private $response;
private $listener;
private $time;
private $stub;
private static $hasVarDumper;

public function __construct(ListenerInterface $listener)
/**
* @param callable $listener
*/
public function __construct($listener)
{
$this->listener = $listener;

Expand All @@ -40,10 +48,15 @@ public function __construct(ListenerInterface $listener)
/**
* {@inheritdoc}
*/
public function handle(GetResponseEvent $event)
public function __invoke(RequestEvent $event)
{
$startTime = microtime(true);
$this->listener->handle($event);
if (\is_callable($this->listener)) {
($this->listener)($event);
} else {
@trigger_error(sprintf('Calling the "%s::handle()" method from the firewall is deprecated since Symfony 4.3, implement "__invoke()" instead.', \get_class($this)), E_USER_DEPRECATED);
$this->listener->handle($event);
}
$this->time = microtime(true) - $startTime;
$this->response = $event->getResponse();
}
Expand All @@ -56,7 +69,7 @@ public function __call($method, $arguments)
return $this->listener->{$method}(...$arguments);
}

public function getWrappedListener(): ListenerInterface
public function getWrappedListener()
{
return $this->listener;
}
Expand Down
Expand Up @@ -15,6 +15,7 @@
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpKernel\Event\FinishRequestEvent;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Security\Http\Firewall;
use Symfony\Component\Security\Http\FirewallMapInterface;
use Symfony\Component\Security\Http\Logout\LogoutUrlGenerator;
Expand All @@ -35,7 +36,10 @@ public function __construct(FirewallMapInterface $map, EventDispatcherInterface
parent::__construct($map, $dispatcher);
}

public function onKernelRequest(GetResponseEvent $event)
/**
* @internal
*/
public function configureLogoutUrlGenerator(GetResponseEvent $event)
{
if (!$event->isMasterRequest()) {
return;
Expand All @@ -44,10 +48,11 @@ public function onKernelRequest(GetResponseEvent $event)
if ($this->map instanceof FirewallMap && $config = $this->map->getFirewallConfig($event->getRequest())) {
$this->logoutUrlGenerator->setCurrentFirewall($config->getName(), $config->getContext());
}

parent::onKernelRequest($event);
}

/**
* @internal since Symfony 4.3
*/
public function onKernelFinishRequest(FinishRequestEvent $event)
{
if ($event->isMasterRequest()) {
Expand All @@ -56,4 +61,18 @@ public function onKernelFinishRequest(FinishRequestEvent $event)

parent::onKernelFinishRequest($event);
}

/**
* {@inheritdoc}
*/
public static function getSubscribedEvents()
{
return [
KernelEvents::REQUEST => [
['configureLogoutUrlGenerator', 8],
['onKernelRequest', 8],
],
KernelEvents::FINISH_REQUEST => 'onKernelFinishRequest',
];
}
}

0 comments on commit 1479a26

Please sign in to comment.