[WebBundle] introduced a ControllerManager class
This commit is contained in:
parent
e715bc3d45
commit
3749c59041
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['path'] = Escaper::unescape($options['path']);
|
||||||
$options['query'] = Escaper::unescape($options['query']);
|
$options['query'] = Escaper::unescape($options['query']);
|
||||||
|
|
||||||
return $this->doRender($controller, $options);
|
return $this->container->getControllerManagerService()->render($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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,8 +2,9 @@
|
|||||||
|
|
||||||
namespace Symfony\Framework\WebBundle\Listener;
|
namespace Symfony\Framework\WebBundle\Listener;
|
||||||
|
|
||||||
|
use Symfony\Framework\WebBundle\Controller\ControllerManager;
|
||||||
use Symfony\Foundation\LoggerInterface;
|
use Symfony\Foundation\LoggerInterface;
|
||||||
use Symfony\Components\DependencyInjection\ContainerInterface;
|
use Symfony\Components\EventDispatcher\EventDispatcher;
|
||||||
use Symfony\Components\EventDispatcher\Event;
|
use Symfony\Components\EventDispatcher\Event;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -25,108 +26,48 @@ use Symfony\Components\EventDispatcher\Event;
|
|||||||
*/
|
*/
|
||||||
class ControllerLoader
|
class ControllerLoader
|
||||||
{
|
{
|
||||||
protected $container;
|
protected $manager;
|
||||||
|
protected $dispatcher;
|
||||||
protected $logger;
|
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;
|
$this->logger = $logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function register()
|
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)
|
public function resolve(Event $event)
|
||||||
{
|
{
|
||||||
$request = $event->getParameter('request');
|
$request = $event->getParameter('request');
|
||||||
|
|
||||||
if (!$controller = $request->path->get('_controller')) {
|
if (!$controller = $request->path->get('_controller')) {
|
||||||
if (null !== $this->logger) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$controller = $this->findController($controller);
|
list($controller, $method) = $this->manager->findController($controller);
|
||||||
$controller[0]->setRequest($request);
|
$controller->setRequest($request);
|
||||||
|
|
||||||
$r = new \ReflectionObject($controller[0]);
|
$arguments = $this->manager->getMethodArguments($request->path->all(), $controller, $method);
|
||||||
$arguments = $this->getMethodArguments($r->getMethod($controller[1]), $request->path->all(), sprintf('%s::%s()', get_class($controller[0]), $controller[1]));
|
|
||||||
|
|
||||||
$event->setReturnValue(array($controller, $arguments));
|
$event->setReturnValue(array(array($controller, $method), $arguments));
|
||||||
|
|
||||||
return true;
|
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>
|
<parameters>
|
||||||
<parameter key="request_parser.class">Symfony\Framework\WebBundle\Listener\RequestParser</parameter>
|
<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="controller_loader.class">Symfony\Framework\WebBundle\Listener\ControllerLoader</parameter>
|
||||||
<parameter key="router.class">Symfony\Components\Routing\Router</parameter>
|
<parameter key="router.class">Symfony\Components\Routing\Router</parameter>
|
||||||
<parameter key="response_filter.class">Symfony\Framework\WebBundle\Listener\ResponseFilter</parameter>
|
<parameter key="response_filter.class">Symfony\Framework\WebBundle\Listener\ResponseFilter</parameter>
|
||||||
@ -17,9 +18,15 @@
|
|||||||
</parameters>
|
</parameters>
|
||||||
|
|
||||||
<services>
|
<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%">
|
<service id="controller_loader" class="%controller_loader.class%">
|
||||||
<annotation name="kernel.listener" event="core.load_controller" method="resolve" />
|
<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" />
|
<argument type="service" id="logger" on-invalid="ignore" />
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user