[WebBundle] introduced a ControllerManager class
This commit is contained in:
parent
e715bc3d45
commit
3749c59041
@ -150,7 +150,7 @@ class HttpKernel implements HttpKernelInterface
|
||||
* Handles a request that need to be embedded.
|
||||
*
|
||||
* @param Request $request A Request instance
|
||||
* @param Boolean $raw Whether to catch exceptions or not
|
||||
* @param Boolean $raw Whether to catch exceptions or not
|
||||
*
|
||||
* @return string|false The Response content or false if there is a problem
|
||||
*
|
||||
@ -182,7 +182,7 @@ class HttpKernel implements HttpKernelInterface
|
||||
*
|
||||
* @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 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
|
||||
*
|
||||
|
150
src/Symfony/Framework/WebBundle/Controller/ControllerManager.php
Normal file
150
src/Symfony/Framework/WebBundle/Controller/ControllerManager.php
Normal file
@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Framework\WebBundle\Controller;
|
||||
|
||||
use Symfony\Foundation\LoggerInterface;
|
||||
use Symfony\Components\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Components\HttpKernel\HttpKernelInterface;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ControllerManager.
|
||||
*
|
||||
* @package Symfony
|
||||
* @subpackage Framework_WebBundle
|
||||
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*/
|
||||
class ControllerManager
|
||||
{
|
||||
protected $container;
|
||||
protected $logger;
|
||||
|
||||
public function __construct(ContainerInterface $container, LoggerInterface $logger = null)
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a Controller and returns the Response content.
|
||||
*
|
||||
* @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
|
||||
*
|
||||
* @return string The Response content
|
||||
*/
|
||||
public function render($controller, array $options = array())
|
||||
{
|
||||
$request = $this->container->getRequestService();
|
||||
|
||||
// controller or URI?
|
||||
if (0 === strpos($controller, '/')) {
|
||||
$subRequest = Request::create($controller, 'get', array(), $request->cookies->all(), array(), $request->server->all());
|
||||
} else {
|
||||
$options['path']['_controller'] = $controller;
|
||||
$options['path']['_format'] = $request->getRequestFormat();
|
||||
$subRequest = $request->duplicate($options['query'], null, $options['path']);
|
||||
}
|
||||
|
||||
try {
|
||||
return $this->container->getKernelService()->handle($subRequest, HttpKernelInterface::EMBEDDED_REQUEST, true);
|
||||
} catch (\Exception $e) {
|
||||
if ($options['alt']) {
|
||||
$alt = $options['alt'];
|
||||
unset($options['alt']);
|
||||
$options['path'] = isset($alt[1]) ? $alt[1] : array();
|
||||
$options['query'] = isset($alt[2]) ? $alt[2] : array();
|
||||
|
||||
return $this->render($alt[0], $options);
|
||||
}
|
||||
|
||||
if (!$options['ignore_errors']) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the Controller instance associated with the controller string
|
||||
*
|
||||
* @param string $controller A controller name (a string like BlogBundle:Post:index)
|
||||
*
|
||||
* @return array An array composed of the Controller instance and the Controller method
|
||||
*
|
||||
* @throws \InvalidArgumentException|\LogicException If the controller can't be found
|
||||
*/
|
||||
public function findController($controller)
|
||||
{
|
||||
list($bundle, $controller, $action) = explode(':', $controller);
|
||||
$class = null;
|
||||
$logs = array();
|
||||
foreach (array_keys($this->container->getParameter('kernel.bundle_dirs')) as $namespace) {
|
||||
$try = $namespace.'\\'.$bundle.'\\Controller\\'.$controller.'Controller';
|
||||
if (!class_exists($try)) {
|
||||
if (null !== $this->logger) {
|
||||
$logs[] = sprintf('Failed finding controller "%s:%s" from namespace "%s" (%s)', $bundle, $controller, $namespace, $try);
|
||||
}
|
||||
} else {
|
||||
if (!in_array($namespace.'\\'.$bundle.'\\Bundle', array_map(function ($bundle) { return get_class($bundle); }, $this->container->getKernelService()->getBundles()))) {
|
||||
throw new \LogicException(sprintf('To use the "%s" controller, you first need to enable the Bundle "%s" in your Kernel class.', $try, $namespace.'\\'.$bundle));
|
||||
}
|
||||
|
||||
$class = $try;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (null === $class) {
|
||||
if (null !== $this->logger) {
|
||||
foreach ($logs as $log) {
|
||||
$this->logger->info($log);
|
||||
}
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(sprintf('Unable to find controller "%s:%s".', $bundle, $controller));
|
||||
}
|
||||
|
||||
$controller = new $class($this->container);
|
||||
|
||||
$method = $action.'Action';
|
||||
if (!method_exists($controller, $method)) {
|
||||
throw new \InvalidArgumentException(sprintf('Method "%s::%s" does not exist.', $class, $method));
|
||||
}
|
||||
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->info(sprintf('Using controller "%s::%s"%s', $class, $method, isset($file) ? sprintf(' from file "%s"', $file) : ''));
|
||||
}
|
||||
|
||||
return array($controller, $method);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \RuntimeException When value for argument given is not provided
|
||||
*/
|
||||
public function getMethodArguments(array $path, $controller, $method)
|
||||
{
|
||||
$r = new \ReflectionObject($controller);
|
||||
|
||||
$arguments = array();
|
||||
foreach ($r->getMethod($method)->getParameters() as $param) {
|
||||
if (array_key_exists($param->getName(), $path)) {
|
||||
$arguments[] = $path[$param->getName()];
|
||||
} elseif ($param->isDefaultValueAvailable()) {
|
||||
$arguments[] = $param->getDefaultValue();
|
||||
} else {
|
||||
throw new \RuntimeException(sprintf('Controller "%s::%s()" requires that you provide a value for the "$%s" argument (because there is no default value or because there is a non optional argument after this one).', $controller, $method, $param->getName()));
|
||||
}
|
||||
}
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
}
|
@ -80,39 +80,7 @@ class ActionsHelper extends Helper
|
||||
$options['path'] = Escaper::unescape($options['path']);
|
||||
$options['query'] = Escaper::unescape($options['query']);
|
||||
|
||||
return $this->doRender($controller, $options);
|
||||
}
|
||||
|
||||
protected function doRender($controller, array $options = array())
|
||||
{
|
||||
// controller or URI?
|
||||
$request = $this->container->getRequestService();
|
||||
if (0 === strpos($controller, '/')) {
|
||||
// URI
|
||||
$subRequest = Request::create($controller, 'get', array(), $request->cookies->all(), array(), $request->server->all());
|
||||
} else {
|
||||
// controller
|
||||
$options['path']['_controller'] = $controller;
|
||||
$options['path']['_format'] = $request->getRequestFormat();
|
||||
$subRequest = $request->duplicate($options['query'], null, $options['path']);
|
||||
}
|
||||
|
||||
try {
|
||||
return $this->container->getKernelService()->handle($subRequest, HttpKernelInterface::EMBEDDED_REQUEST, true);
|
||||
} catch (\Exception $e) {
|
||||
if ($options['alt']) {
|
||||
$alt = $options['alt'];
|
||||
unset($options['alt']);
|
||||
$options['path'] = isset($alt[1]) ? $alt[1] : array();
|
||||
$options['query'] = isset($alt[2]) ? $alt[2] : array();
|
||||
|
||||
return $this->doRender($alt[0], $options);
|
||||
}
|
||||
|
||||
if (!$options['ignore_errors']) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
return $this->container->getControllerManagerService()->render($controller, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2,8 +2,9 @@
|
||||
|
||||
namespace Symfony\Framework\WebBundle\Listener;
|
||||
|
||||
use Symfony\Framework\WebBundle\Controller\ControllerManager;
|
||||
use Symfony\Foundation\LoggerInterface;
|
||||
use Symfony\Components\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Components\EventDispatcher\EventDispatcher;
|
||||
use Symfony\Components\EventDispatcher\Event;
|
||||
|
||||
/*
|
||||
@ -25,108 +26,48 @@ use Symfony\Components\EventDispatcher\Event;
|
||||
*/
|
||||
class ControllerLoader
|
||||
{
|
||||
protected $container;
|
||||
protected $manager;
|
||||
protected $dispatcher;
|
||||
protected $logger;
|
||||
|
||||
public function __construct(ContainerInterface $container, LoggerInterface $logger = null)
|
||||
public function __construct(EventDispatcher $dispatcher, ControllerManager $manager, LoggerInterface $logger = null)
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->dispatcher = $dispatcher;
|
||||
$this->manager = $manager;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
public function register()
|
||||
{
|
||||
$this->container->getEventDispatcherService()->connect('core.load_controller', array($this, 'resolve'));
|
||||
$this->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 (!$controller = $request->path->get('_controller')) {
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->err('Unable to look for the controller as the _controller parameter is missing');
|
||||
$this->logger->err('Unable to look for the controller as the "_controller" parameter is missing');
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$controller = $this->findController($controller);
|
||||
$controller[0]->setRequest($request);
|
||||
list($controller, $method) = $this->manager->findController($controller);
|
||||
$controller->setRequest($request);
|
||||
|
||||
$r = new \ReflectionObject($controller[0]);
|
||||
$arguments = $this->getMethodArguments($r->getMethod($controller[1]), $request->path->all(), sprintf('%s::%s()', get_class($controller[0]), $controller[1]));
|
||||
$arguments = $this->manager->getMethodArguments($request->path->all(), $controller, $method);
|
||||
|
||||
$event->setReturnValue(array($controller, $arguments));
|
||||
$event->setReturnValue(array(array($controller, $method), $arguments));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \InvalidArgumentException|\LogicException If controller can't be found
|
||||
*/
|
||||
public function findController($controller)
|
||||
{
|
||||
list($bundle, $controller, $action) = explode(':', $controller);
|
||||
$class = null;
|
||||
$logs = array();
|
||||
foreach (array_keys($this->container->getParameter('kernel.bundle_dirs')) as $namespace) {
|
||||
$try = $namespace.'\\'.$bundle.'\\Controller\\'.$controller.'Controller';
|
||||
if (!class_exists($try)) {
|
||||
if (null !== $this->logger) {
|
||||
$logs[] = sprintf('Failed finding controller "%s:%s" from namespace "%s" (%s)', $bundle, $controller, $namespace, $try);
|
||||
}
|
||||
} else {
|
||||
if (!in_array($namespace.'\\'.$bundle.'\\Bundle', array_map(function ($bundle) { return get_class($bundle); }, $this->container->getKernelService()->getBundles()))) {
|
||||
throw new \LogicException(sprintf('To use the "%s" controller, you first need to enable the Bundle "%s" in your Kernel class.', $try, $namespace.'\\'.$bundle));
|
||||
}
|
||||
|
||||
$class = $try;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (null === $class) {
|
||||
if (null !== $this->logger) {
|
||||
foreach ($logs as $log) {
|
||||
$this->logger->info($log);
|
||||
}
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(sprintf('Unable to find controller "%s:%s".', $bundle, $controller));
|
||||
}
|
||||
|
||||
$controller = new $class($this->container);
|
||||
|
||||
$method = $action.'Action';
|
||||
if (!method_exists($controller, $method)) {
|
||||
throw new \InvalidArgumentException(sprintf('Method "%s::%s" does not exist.', $class, $method));
|
||||
}
|
||||
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->info(sprintf('Using controller "%s::%s"%s', $class, $method, isset($file) ? sprintf(' from file "%s"', $file) : ''));
|
||||
}
|
||||
|
||||
return array($controller, $method);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \RuntimeException When value for argument given is not provided
|
||||
*/
|
||||
public function getMethodArguments(\ReflectionFunctionAbstract $r, array $parameters, $controller)
|
||||
{
|
||||
$arguments = array();
|
||||
foreach ($r->getParameters() as $param) {
|
||||
if (array_key_exists($param->getName(), $parameters)) {
|
||||
$arguments[] = $parameters[$param->getName()];
|
||||
} elseif ($param->isDefaultValueAvailable()) {
|
||||
$arguments[] = $param->getDefaultValue();
|
||||
} else {
|
||||
throw new \RuntimeException(sprintf('Controller "%s" requires that you provide a value for the "$%s" argument (because there is no default value or because there is a non optional argument after this one).', $controller, $param->getName()));
|
||||
}
|
||||
}
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
<parameters>
|
||||
<parameter key="request_parser.class">Symfony\Framework\WebBundle\Listener\RequestParser</parameter>
|
||||
<parameter key="controller_manager.class">Symfony\Framework\WebBundle\Controller\ControllerManager</parameter>
|
||||
<parameter key="controller_loader.class">Symfony\Framework\WebBundle\Listener\ControllerLoader</parameter>
|
||||
<parameter key="router.class">Symfony\Components\Routing\Router</parameter>
|
||||
<parameter key="response_filter.class">Symfony\Framework\WebBundle\Listener\ResponseFilter</parameter>
|
||||
@ -17,9 +18,15 @@
|
||||
</parameters>
|
||||
|
||||
<services>
|
||||
<service id="controller_manager" class="%controller_manager.class%">
|
||||
<argument type="service" id="service_container" />
|
||||
<argument type="service" id="logger" on-invalid="ignore" />
|
||||
</service>
|
||||
|
||||
<service id="controller_loader" class="%controller_loader.class%">
|
||||
<annotation name="kernel.listener" event="core.load_controller" method="resolve" />
|
||||
<argument type="service" id="service_container" />
|
||||
<argument type="service" id="event_dispatcher" />
|
||||
<argument type="service" id="controller_manager" />
|
||||
<argument type="service" id="logger" on-invalid="ignore" />
|
||||
</service>
|
||||
|
||||
|
Reference in New Issue
Block a user