changed HttpKernel workflow to allow more flexibility
This commit is contained in:
parent
3ec9005680
commit
e35d345204
@ -3,7 +3,7 @@
|
||||
namespace Symfony\Bundle\FrameworkBundle\Controller;
|
||||
|
||||
use Symfony\Components\HttpKernel\LoggerInterface;
|
||||
use Symfony\Components\HttpKernel\Controller\ControllerManagerInterface;
|
||||
use Symfony\Components\HttpKernel\Controller\ControllerResolverInterface;
|
||||
use Symfony\Components\HttpKernel\HttpKernelInterface;
|
||||
use Symfony\Components\HttpFoundation\Request;
|
||||
use Symfony\Components\EventDispatcher\Event;
|
||||
@ -19,13 +19,13 @@ use Symfony\Components\DependencyInjection\ContainerInterface;
|
||||
*/
|
||||
|
||||
/**
|
||||
* ControllerManager.
|
||||
* ControllerResolver.
|
||||
*
|
||||
* @package Symfony
|
||||
* @subpackage Bundle_FrameworkBundle
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
class ControllerManager implements ControllerManagerInterface
|
||||
class ControllerResolver implements ControllerResolverInterface
|
||||
{
|
||||
protected $container;
|
||||
protected $logger;
|
||||
@ -122,7 +122,7 @@ class ControllerManager implements ControllerManagerInterface
|
||||
* @param \Symfony\Components\HttpFoundation\Request $request A Request instance
|
||||
*
|
||||
* @return mixed|Boolean A PHP callable representing the Controller,
|
||||
* or false if this manager is not able to determine the controller
|
||||
* or false if this resolver is not able to determine the controller
|
||||
*
|
||||
* @throws \InvalidArgumentException|\LogicException If the controller can't be found
|
||||
*/
|
||||
@ -190,10 +190,9 @@ class ControllerManager implements ControllerManagerInterface
|
||||
*
|
||||
* @throws \RuntimeException When value for argument given is not provided
|
||||
*/
|
||||
public function getMethodArguments(Request $request, $controller)
|
||||
public function getArguments(Request $request, $controller)
|
||||
{
|
||||
$event = $this->container->get('event_dispatcher')->filter(new Event($this, 'controller_manager.filter_controller_arguments', array('controller' => $controller, 'request' => $request)), $request->attributes->all());
|
||||
$attributes = $event->getReturnValue();
|
||||
$attributes = $request->attributes->all();
|
||||
|
||||
list($controller, $method) = $controller;
|
||||
|
@ -83,7 +83,7 @@
|
||||
|
||||
<service id="templating.helper.actions" class="%templating.helper.actions.class%">
|
||||
<annotation name="templating.helper" alias="actions" />
|
||||
<argument type="service" id="controller_manager" />
|
||||
<argument type="service" id="controller_resolver" />
|
||||
</service>
|
||||
|
||||
<service id="templating.loader" alias="templating.loader.filesystem" />
|
||||
|
@ -6,8 +6,7 @@
|
||||
|
||||
<parameters>
|
||||
<parameter key="request_listener.class">Symfony\Bundle\FrameworkBundle\RequestListener</parameter>
|
||||
<parameter key="controller_manager.class">Symfony\Bundle\FrameworkBundle\Controller\ControllerManager</parameter>
|
||||
<parameter key="controller_loader_listener.class">Symfony\Components\HttpKernel\Controller\ControllerLoaderListener</parameter>
|
||||
<parameter key="controller_resolver.class">Symfony\Bundle\FrameworkBundle\Controller\ControllerResolver</parameter>
|
||||
<parameter key="response_listener.class">Symfony\Components\HttpKernel\ResponseListener</parameter>
|
||||
<parameter key="exception_listener.class">Symfony\Bundle\FrameworkBundle\Controller\ExceptionListener</parameter>
|
||||
<parameter key="exception_listener.controller">FrameworkBundle:Exception:exception</parameter>
|
||||
@ -16,17 +15,11 @@
|
||||
</parameters>
|
||||
|
||||
<services>
|
||||
<service id="controller_manager" class="%controller_manager.class%">
|
||||
<service id="controller_resolver" class="%controller_resolver.class%">
|
||||
<argument type="service" id="service_container" />
|
||||
<argument type="service" id="logger" on-invalid="ignore" />
|
||||
</service>
|
||||
|
||||
<service id="controller_loader_listener" class="%controller_loader_listener.class%">
|
||||
<annotation name="kernel.listener" />
|
||||
<argument type="service" id="controller_manager" />
|
||||
<argument type="service" id="logger" on-invalid="ignore" />
|
||||
</service>
|
||||
|
||||
<service id="request_listener" class="%request_listener.class%">
|
||||
<annotation name="kernel.listener" />
|
||||
<argument type="service" id="service_container" />
|
||||
|
@ -4,7 +4,7 @@ namespace Symfony\Bundle\FrameworkBundle\Templating\Helper;
|
||||
|
||||
use Symfony\Components\Templating\Helper\Helper;
|
||||
use Symfony\Components\OutputEscaper\Escaper;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\ControllerManager;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\ControllerResolver;
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony framework.
|
||||
@ -24,16 +24,16 @@ use Symfony\Bundle\FrameworkBundle\Controller\ControllerManager;
|
||||
*/
|
||||
class ActionsHelper extends Helper
|
||||
{
|
||||
protected $manager;
|
||||
protected $resolver;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Constructor $container A ContainerInterface instance
|
||||
*/
|
||||
public function __construct(ControllerManager $manager)
|
||||
public function __construct(ControllerResolver $resolver)
|
||||
{
|
||||
$this->manager = $manager;
|
||||
$this->resolver = $resolver;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -55,7 +55,7 @@ class ActionsHelper extends Helper
|
||||
* @param string $controller A controller name to execute (a string like BlogBundle:Post:index), or a relative URI
|
||||
* @param array $options An array of options
|
||||
*
|
||||
* @see Symfony\Bundle\FrameworkBundle\Controller\ControllerManager::render()
|
||||
* @see Symfony\Bundle\FrameworkBundle\Controller\ControllerResolver::render()
|
||||
*/
|
||||
public function render($controller, array $options = array())
|
||||
{
|
||||
@ -69,7 +69,7 @@ class ActionsHelper extends Helper
|
||||
$options['query'] = Escaper::unescape($options['query']);
|
||||
}
|
||||
|
||||
return $this->manager->render($controller, $options);
|
||||
return $this->resolver->render($controller, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,65 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Components\HttpKernel\Controller;
|
||||
|
||||
use Symfony\Components\EventDispatcher\EventDispatcher;
|
||||
use Symfony\Components\EventDispatcher\Event;
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ControllerLoaderListener listen to the core.load_controller and finds the controller
|
||||
* to execute based on the request parameters.
|
||||
*
|
||||
* @package Symfony
|
||||
* @subpackage Bundle_FrameworkBundle
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
class ControllerLoaderListener
|
||||
{
|
||||
protected $manager;
|
||||
|
||||
public function __construct(ControllerManagerInterface $manager)
|
||||
{
|
||||
$this->manager = $manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a core.load_controller listener.
|
||||
*
|
||||
* @param Symfony\Components\EventDispatcher\EventDispatcher $dispatcher An EventDispatcher instance
|
||||
*/
|
||||
public function register(EventDispatcher $dispatcher)
|
||||
{
|
||||
$dispatcher->connect('core.load_controller', array($this, 'resolve'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the Controller associated with the given Request.
|
||||
*
|
||||
* @param Event $event An Event instance
|
||||
*
|
||||
* @return Boolean true if the controller has been found, false otherwise
|
||||
*/
|
||||
public function resolve(Event $event)
|
||||
{
|
||||
$request = $event->getParameter('request');
|
||||
|
||||
if (false === $controller = $this->manager->getController($request)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$arguments = $this->manager->getMethodArguments($request, $controller);
|
||||
|
||||
$event->setReturnValue(array($controller, $arguments));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@ use Symfony\Components\HttpFoundation\Request;
|
||||
*/
|
||||
|
||||
/**
|
||||
* A ControllerManagerInterface implementation knows how to determine the
|
||||
* A ControllerResolverInterface implementation knows how to determine the
|
||||
* controller to execute based on a Request object.
|
||||
*
|
||||
* It can also determine the arguments to pass to the Controller.
|
||||
@ -25,21 +25,21 @@ use Symfony\Components\HttpFoundation\Request;
|
||||
* @subpackage Bundle_FrameworkBundle
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
interface ControllerManagerInterface
|
||||
interface ControllerResolverInterface
|
||||
{
|
||||
/**
|
||||
* Returns the Controller instance associated with a Request.
|
||||
*
|
||||
* As several managers can exist for a single application, a manager must
|
||||
* As several resolvers can exist for a single application, a resolver must
|
||||
* return false when it is not able to determine the controller.
|
||||
*
|
||||
* The manager must only throw an exception when it should be able to load
|
||||
* The resolver must only throw an exception when it should be able to load
|
||||
* controller but cannot because of some errors made by the developer.
|
||||
*
|
||||
* @param \Symfony\Components\HttpFoundation\Request $request A Request instance
|
||||
*
|
||||
* @return mixed|Boolean A PHP callable representing the Controller,
|
||||
* or false if this manager is not able to determine the controller
|
||||
* or false if this resolver is not able to determine the controller
|
||||
*
|
||||
* @throws \InvalidArgumentException|\LogicException If the controller can't be found
|
||||
*/
|
||||
@ -53,5 +53,5 @@ interface ControllerManagerInterface
|
||||
*
|
||||
* @throws \RuntimeException When value for argument given is not provided
|
||||
*/
|
||||
public function getMethodArguments(Request $request, $controller);
|
||||
public function getArguments(Request $request, $controller);
|
||||
}
|
@ -4,6 +4,7 @@ namespace Symfony\Components\HttpKernel;
|
||||
|
||||
use Symfony\Components\EventDispatcher\Event;
|
||||
use Symfony\Components\EventDispatcher\EventDispatcher;
|
||||
use Symfony\Components\HttpKernel\Controller\ControllerResolverInterface;
|
||||
use Symfony\Components\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Components\HttpFoundation\Request;
|
||||
use Symfony\Components\HttpFoundation\Response;
|
||||
@ -27,16 +28,19 @@ use Symfony\Components\HttpFoundation\Response;
|
||||
class HttpKernel implements HttpKernelInterface
|
||||
{
|
||||
protected $dispatcher;
|
||||
protected $resolver;
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param EventDispatcher $dispatcher An event dispatcher instance
|
||||
* @param \Symfony\Components\EventDispatcher\EventDispatcher $dispatcher An event dispatcher instance
|
||||
* @param \Symfony\Components\HttpKernel\Controller\ControllerResolverInterface $resolver A ControllerResolverInterface instance
|
||||
*/
|
||||
public function __construct(EventDispatcher $dispatcher)
|
||||
public function __construct(EventDispatcher $dispatcher, ControllerResolverInterface $resolver)
|
||||
{
|
||||
$this->dispatcher = $dispatcher;
|
||||
$this->resolver = $resolver;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -55,11 +59,11 @@ class HttpKernel implements HttpKernelInterface
|
||||
* All exceptions are caught, and a core.exception event is notified
|
||||
* for user management.
|
||||
*
|
||||
* @param Request $request A Request instance
|
||||
* @param integer $type The type of the request (one of HttpKernelInterface::MASTER_REQUEST, HttpKernelInterface::FORWARDED_REQUEST, or HttpKernelInterface::EMBEDDED_REQUEST)
|
||||
* @param Boolean $raw Whether to catch exceptions or not
|
||||
* @param \Symfony\Components\HttpFoundation\Request $request A Request instance
|
||||
* @param integer $type The type of the request (one of HttpKernelInterface::MASTER_REQUEST, HttpKernelInterface::FORWARDED_REQUEST, or HttpKernelInterface::EMBEDDED_REQUEST)
|
||||
* @param Boolean $raw Whether to catch exceptions or not
|
||||
*
|
||||
* @return Response A Response instance
|
||||
* @return \Symfony\Components\HttpFoundation\Response A Response instance
|
||||
*
|
||||
* @throws \Exception When an Exception occurs during processing
|
||||
* and couldn't be caught by event processing or $raw is true
|
||||
@ -100,13 +104,13 @@ class HttpKernel implements HttpKernelInterface
|
||||
*
|
||||
* Exceptions are not caught.
|
||||
*
|
||||
* @param Request $request A Request instance
|
||||
* @param integer $type The type of the request (one of HttpKernelInterface::MASTER_REQUEST, HttpKernelInterface::FORWARDED_REQUEST, or HttpKernelInterface::EMBEDDED_REQUEST)
|
||||
* @param \Symfony\Components\HttpFoundation\Request $request A Request instance
|
||||
* @param integer $type The type of the request (one of HttpKernelInterface::MASTER_REQUEST, HttpKernelInterface::FORWARDED_REQUEST, or HttpKernelInterface::EMBEDDED_REQUEST)
|
||||
*
|
||||
* @return Response A Response instance
|
||||
* @return \Symfony\Components\HttpFoundation\Response A Response instance
|
||||
*
|
||||
* @throws \LogicException If one of the listener does not behave as expected
|
||||
* @throws NotFoundHttpException When controller cannot be found
|
||||
* @throws \LogicException If one of the listener does not behave as expected
|
||||
* @throws \Symfony\Components\HttpKernel\Exception\NotFoundHttpException When controller cannot be found
|
||||
*/
|
||||
protected function handleRaw(Request $request, $type = self::MASTER_REQUEST)
|
||||
{
|
||||
@ -117,30 +121,23 @@ class HttpKernel implements HttpKernelInterface
|
||||
}
|
||||
|
||||
// load controller
|
||||
$event = $this->dispatcher->notifyUntil(new Event($this, 'core.load_controller', array('request_type' => $type, 'request' => $request)));
|
||||
if (!$event->isProcessed()) {
|
||||
if (false === $controller = $this->resolver->getController($request)) {
|
||||
throw new NotFoundHttpException('Unable to find the controller.');
|
||||
}
|
||||
|
||||
list($controller, $arguments) = $event->getReturnValue();
|
||||
$event = $this->dispatcher->filter(new Event($this, 'core.controller', array('request' => $request)), $controller);
|
||||
$controller = $event->getReturnValue();
|
||||
|
||||
// controller must be a callable
|
||||
if (!is_callable($controller)) {
|
||||
throw new \LogicException(sprintf('The controller must be a callable (%s).', var_export($controller, true)));
|
||||
}
|
||||
|
||||
// controller
|
||||
$event = $this->dispatcher->notifyUntil(new Event($this, 'core.controller', array('request_type' => $type, 'request' => $request, 'controller' => &$controller, 'arguments' => &$arguments)));
|
||||
if ($event->isProcessed()) {
|
||||
try {
|
||||
return $this->filterResponse($event->getReturnValue(), $request, 'A "core.controller" listener returned a non response object.', $type);
|
||||
} catch (\Exception $e) {
|
||||
$retval = $event->getReturnValue();
|
||||
}
|
||||
} else {
|
||||
// call controller
|
||||
$retval = call_user_func_array($controller, $arguments);
|
||||
}
|
||||
// controller arguments
|
||||
$arguments = $this->resolver->getArguments($request, $controller);
|
||||
|
||||
// call controller
|
||||
$retval = call_user_func_array($controller, $arguments);
|
||||
|
||||
// view
|
||||
$event = $this->dispatcher->filter(new Event($this, 'core.view', array('request_type' => $type, 'request' => $request)), $retval);
|
||||
@ -151,7 +148,7 @@ class HttpKernel implements HttpKernelInterface
|
||||
/**
|
||||
* Handles a request that need to be embedded.
|
||||
*
|
||||
* @param Request $request A Request instance
|
||||
* @param \Symfony\Components\HttpFoundation\Request $request A Request instance
|
||||
* @param Boolean $raw Whether to catch exceptions or not
|
||||
*
|
||||
* @return string|false The Response content or false if there is a problem
|
||||
@ -182,11 +179,11 @@ class HttpKernel implements HttpKernelInterface
|
||||
/**
|
||||
* Filters a response object.
|
||||
*
|
||||
* @param Response $response A Response instance
|
||||
* @param string $message A error message in case the response is not a Response object
|
||||
* @param integer $type The type of the request (one of HttpKernelInterface::MASTER_REQUEST, HttpKernelInterface::FORWARDED_REQUEST, or HttpKernelInterface::EMBEDDED_REQUEST)
|
||||
* @param \Symfony\Components\HttpFoundation\Response $response A Response instance
|
||||
* @param string $message A error message in case the response is not a Response object
|
||||
* @param integer $type The type of the request (one of HttpKernelInterface::MASTER_REQUEST, HttpKernelInterface::FORWARDED_REQUEST, or HttpKernelInterface::EMBEDDED_REQUEST)
|
||||
*
|
||||
* @return Response The filtered Response instance
|
||||
* @return \Symfony\Components\HttpFoundation\Response The filtered Response instance
|
||||
*
|
||||
* @throws \RuntimeException if the passed object is not a Response instance
|
||||
*/
|
||||
|
@ -29,18 +29,18 @@ interface HttpKernelInterface
|
||||
/**
|
||||
* Handles a request to convert it to a response.
|
||||
*
|
||||
* @param Request $request A Request instance
|
||||
* @param integer $type The type of the request (one of HttpKernelInterface::MASTER_REQUEST, HttpKernelInterface::FORWARDED_REQUEST, or HttpKernelInterface::EMBEDDED_REQUEST)
|
||||
* @param Boolean $raw Whether to catch exceptions or not
|
||||
* @param \Symfony\Components\HttpFoundation\Request $request A Request instance
|
||||
* @param integer $type The type of the request (one of HttpKernelInterface::MASTER_REQUEST, HttpKernelInterface::FORWARDED_REQUEST, or HttpKernelInterface::EMBEDDED_REQUEST)
|
||||
* @param Boolean $raw Whether to catch exceptions or not
|
||||
*
|
||||
* @return Response $response A Response instance
|
||||
* @return \Symfony\Components\HttpFoundation\Response $response A Response instance
|
||||
*/
|
||||
public function handle(Request $request = null, $type = self::MASTER_REQUEST, $raw = false);
|
||||
|
||||
/**
|
||||
* Gets the Request instance associated with the master request.
|
||||
*
|
||||
* @return Request A Request instance
|
||||
* @return \Symfony\Components\HttpFoundation\Request A Request instance
|
||||
*/
|
||||
public function getRequest();
|
||||
}
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
<service id="http_kernel" class="%http_kernel.class%">
|
||||
<argument type="service" id="event_dispatcher" />
|
||||
<argument type="service" id="controller_resolver" />
|
||||
</service>
|
||||
|
||||
<service id="request" class="%request.class%">
|
||||
|
@ -15,9 +15,9 @@ use Symfony\Components\HttpKernel\HttpKernel;
|
||||
use Symfony\Components\HttpFoundation\Request;
|
||||
use Symfony\Components\HttpFoundation\Response;
|
||||
use Symfony\Components\EventDispatcher\EventDispatcher;
|
||||
use Symfony\Components\EventDispatcher\Event;
|
||||
use Symfony\Components\HttpKernel\Controller\ControllerResolverInterface;
|
||||
|
||||
class TestHttpKernel extends HttpKernel
|
||||
class TestHttpKernel extends HttpKernel implements ControllerResolverInterface
|
||||
{
|
||||
protected $body;
|
||||
protected $status;
|
||||
@ -33,15 +33,17 @@ class TestHttpKernel extends HttpKernel
|
||||
$this->customizer = $customizer;
|
||||
$this->called = false;
|
||||
|
||||
$this->dispatcher = new EventDispatcher();
|
||||
$this->dispatcher->connect('core.load_controller', array($this, 'loadController'));
|
||||
parent::__construct(new EventDispatcher(), $this);
|
||||
}
|
||||
|
||||
public function loadController(Event $event)
|
||||
public function getController(Request $request)
|
||||
{
|
||||
$event->setReturnValue(array(array($this, 'callController'), array($event['request'])));
|
||||
return array($this, 'callController');
|
||||
}
|
||||
|
||||
return true;
|
||||
public function getArguments(Request $request, $controller)
|
||||
{
|
||||
return array($request);
|
||||
}
|
||||
|
||||
public function callController(Request $request)
|
||||
|
@ -15,21 +15,23 @@ use Symfony\Components\HttpKernel\HttpKernel;
|
||||
use Symfony\Components\HttpFoundation\Request;
|
||||
use Symfony\Components\HttpFoundation\Response;
|
||||
use Symfony\Components\EventDispatcher\EventDispatcher;
|
||||
use Symfony\Components\EventDispatcher\Event;
|
||||
use Symfony\Components\HttpKernel\Controller\ControllerResolverInterface;
|
||||
|
||||
class TestHttpKernel extends HttpKernel
|
||||
class TestHttpKernel extends HttpKernel implements ControllerResolverInterface
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->dispatcher = new EventDispatcher();
|
||||
$this->dispatcher->connect('core.load_controller', array($this, 'loadController'));
|
||||
parent::__construct(new EventDispatcher(), $this);
|
||||
}
|
||||
|
||||
public function loadController(Event $event)
|
||||
public function getController(Request $request)
|
||||
{
|
||||
$event->setReturnValue(array(array($this, 'callController'), array($event['request'])));
|
||||
return array($this, 'callController');
|
||||
}
|
||||
|
||||
return true;
|
||||
public function getArguments(Request $request, $controller)
|
||||
{
|
||||
return array($request);
|
||||
}
|
||||
|
||||
public function callController(Request $request)
|
||||
|
Reference in New Issue
Block a user