feature #18440 Add the kernel.controller_arguments event (stof)
This PR was merged into the 3.1-dev branch.
Discussion
----------
Add the kernel.controller_arguments event
| Q | A
| ------------- | ---
| Branch? | master
| Bug fix? | no
| New feature? | yes
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets | #18362
| License | MIT
| Doc PR | https://github.com/symfony/symfony-docs/pull/6434
I'm not sure this can be integrated in 3.1 due to the feature freeze, but it would be great if it is, as it is a must-have to be able to make the ``@Security`` annotation compatible with the new argument resolver system (as we need to be able to run the security assertion after the resolving).
I made the arguments mutable here for consistency with ``kernel.controller`` (and @fabpot replied LGTM in the RFC when I suggested it).
Commits
-------
af02e2a
Add the kernel.controller_arguments event
This commit is contained in:
commit
eb40f161d7
@ -12,6 +12,7 @@ CHANGELOG
|
||||
* added `Symfony\Component\HttpKernel\Controller\ArgumentResolver`
|
||||
* added `Symfony\Component\HttpKernel\DataCollector\RequestDataCollector::getMethod()`
|
||||
* added `Symfony\Component\HttpKernel\DataCollector\RequestDataCollector::getRedirect()`
|
||||
* added the `kernel.controller_arguments` event, triggered after controller arguments have been resolved
|
||||
|
||||
3.0.0
|
||||
-----
|
||||
|
@ -61,7 +61,7 @@ class TraceableEventDispatcher extends BaseTraceableEventDispatcher
|
||||
protected function postDispatch($eventName, Event $event)
|
||||
{
|
||||
switch ($eventName) {
|
||||
case KernelEvents::CONTROLLER:
|
||||
case KernelEvents::CONTROLLER_ARGUMENTS:
|
||||
$this->stopwatch->start('controller', 'section');
|
||||
break;
|
||||
case KernelEvents::RESPONSE:
|
||||
|
@ -0,0 +1,55 @@
|
||||
<?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\HttpKernel\Event;
|
||||
|
||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Allows filtering of controller arguments.
|
||||
*
|
||||
* You can call getController() to retrieve the controller and getArguments
|
||||
* to retrieve the current arguments. With setArguments() you can replace
|
||||
* arguments that are used to call the controller.
|
||||
*
|
||||
* Arguments set in the event must be compatible with the signature of the
|
||||
* controller.
|
||||
*
|
||||
* @author Christophe Coevoet <stof@notk.org>
|
||||
*/
|
||||
class FilterControllerArgumentsEvent extends FilterControllerEvent
|
||||
{
|
||||
private $arguments;
|
||||
|
||||
public function __construct(HttpKernelInterface $kernel, callable $controller, array $arguments, Request $request, $requestType)
|
||||
{
|
||||
parent::__construct($kernel, $controller, $request, $requestType);
|
||||
|
||||
$this->arguments = $arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getArguments()
|
||||
{
|
||||
return $this->arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arguments
|
||||
*/
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$this->arguments = $arguments;
|
||||
}
|
||||
}
|
@ -53,8 +53,6 @@ class FilterControllerEvent extends KernelEvent
|
||||
* Sets a new controller.
|
||||
*
|
||||
* @param callable $controller
|
||||
*
|
||||
* @throws \LogicException
|
||||
*/
|
||||
public function setController(callable $controller)
|
||||
{
|
||||
|
@ -14,6 +14,7 @@ namespace Symfony\Component\HttpKernel;
|
||||
use Symfony\Component\HttpKernel\Controller\ArgumentResolver;
|
||||
use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface;
|
||||
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
|
||||
use Symfony\Component\HttpKernel\Event\FilterControllerArgumentsEvent;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
|
||||
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
|
||||
@ -138,6 +139,11 @@ class HttpKernel implements HttpKernelInterface, TerminableInterface
|
||||
// controller arguments
|
||||
$arguments = $this->argumentResolver->getArguments($request, $controller);
|
||||
|
||||
$event = new FilterControllerArgumentsEvent($this, $controller, $arguments, $request, $type);
|
||||
$this->dispatcher->dispatch(KernelEvents::CONTROLLER_ARGUMENTS, $event);
|
||||
$controller = $event->getController();
|
||||
$arguments = $event->getArguments();
|
||||
|
||||
// call controller
|
||||
$response = call_user_func_array($controller, $arguments);
|
||||
|
||||
|
@ -76,6 +76,19 @@ final class KernelEvents
|
||||
*/
|
||||
const CONTROLLER = 'kernel.controller';
|
||||
|
||||
/**
|
||||
* The CONTROLLER_ARGUMENTS event occurs once controller arguments have been resolved.
|
||||
*
|
||||
* This event allows you to change the arguments that will be passed to
|
||||
* the controller. The event listener method receives a
|
||||
* Symfony\Component\HttpKernel\Event\FilterControllerArgumentsEvent instance.
|
||||
*
|
||||
* @Event
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const CONTROLLER_ARGUMENTS = 'kernel.controller_arguments';
|
||||
|
||||
/**
|
||||
* The RESPONSE event occurs once a response was created for
|
||||
* replying to a request.
|
||||
|
@ -34,6 +34,7 @@ class TraceableEventDispatcherTest extends \PHPUnit_Framework_TestCase
|
||||
'__section__',
|
||||
'kernel.request',
|
||||
'kernel.controller',
|
||||
'kernel.controller_arguments',
|
||||
'controller',
|
||||
'kernel.response',
|
||||
'kernel.terminate',
|
||||
|
@ -15,6 +15,7 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface;
|
||||
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
|
||||
use Symfony\Component\HttpKernel\Event\FilterControllerArgumentsEvent;
|
||||
use Symfony\Component\HttpKernel\HttpKernel;
|
||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
@ -233,6 +234,42 @@ class HttpKernelTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEquals('foo', $kernel->handle(new Request())->getContent());
|
||||
}
|
||||
|
||||
public function testHandleAllowChangingControllerArguments()
|
||||
{
|
||||
$dispatcher = new EventDispatcher();
|
||||
$dispatcher->addListener(KernelEvents::CONTROLLER_ARGUMENTS, function (FilterControllerArgumentsEvent $event) {
|
||||
$event->setArguments(array('foo'));
|
||||
});
|
||||
|
||||
$kernel = $this->getHttpKernel($dispatcher, function ($content) { return new Response($content); });
|
||||
|
||||
$this->assertResponseEquals(new Response('foo'), $kernel->handle(new Request()));
|
||||
}
|
||||
|
||||
public function testHandleAllowChangingControllerAndArguments()
|
||||
{
|
||||
$dispatcher = new EventDispatcher();
|
||||
$dispatcher->addListener(KernelEvents::CONTROLLER_ARGUMENTS, function (FilterControllerArgumentsEvent $event) {
|
||||
$oldController = $event->getController();
|
||||
$oldArguments = $event->getArguments();
|
||||
|
||||
$newController = function ($id) use ($oldController, $oldArguments) {
|
||||
$response = call_user_func_array($oldController, $oldArguments);
|
||||
|
||||
$response->headers->set('X-Id', $id);
|
||||
|
||||
return $response;
|
||||
};
|
||||
|
||||
$event->setController($newController);
|
||||
$event->setArguments(array('bar'));
|
||||
});
|
||||
|
||||
$kernel = $this->getHttpKernel($dispatcher, function ($content) { return new Response($content); }, null, array('foo'));
|
||||
|
||||
$this->assertResponseEquals(new Response('foo', 200, array('X-Id' => 'bar')), $kernel->handle(new Request()));
|
||||
}
|
||||
|
||||
public function testTerminate()
|
||||
{
|
||||
$dispatcher = new EventDispatcher();
|
||||
@ -265,7 +302,7 @@ class HttpKernelTest extends \PHPUnit_Framework_TestCase
|
||||
$kernel->handle($request, HttpKernelInterface::MASTER_REQUEST);
|
||||
}
|
||||
|
||||
private function getHttpKernel(EventDispatcherInterface $eventDispatcher, $controller = null, RequestStack $requestStack = null)
|
||||
private function getHttpKernel(EventDispatcherInterface $eventDispatcher, $controller = null, RequestStack $requestStack = null, array $arguments = array())
|
||||
{
|
||||
if (null === $controller) {
|
||||
$controller = function () { return new Response('Hello'); };
|
||||
@ -281,7 +318,7 @@ class HttpKernelTest extends \PHPUnit_Framework_TestCase
|
||||
$argumentResolver
|
||||
->expects($this->any())
|
||||
->method('getArguments')
|
||||
->will($this->returnValue(array()));
|
||||
->will($this->returnValue($arguments));
|
||||
|
||||
return new HttpKernel($eventDispatcher, $controllerResolver, $requestStack, $argumentResolver);
|
||||
}
|
||||
|
Reference in New Issue
Block a user