PageRenderTime 28ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerResolver.php

https://github.com/brainfg/symfony
PHP | 216 lines | 116 code | 30 blank | 70 comment | 20 complexity | 159add5050a079696bfaae5c09a213b6 MD5 | raw file
Possible License(s): ISC
  1. <?php
  2. namespace Symfony\Bundle\FrameworkBundle\Controller;
  3. use Symfony\Component\HttpKernel\Log\LoggerInterface;
  4. use Symfony\Component\HttpKernel\Controller\ControllerResolver as BaseControllerResolver;
  5. use Symfony\Component\HttpKernel\HttpKernelInterface;
  6. use Symfony\Component\HttpFoundation\Request;
  7. use Symfony\Component\EventDispatcher\Event;
  8. use Symfony\Component\DependencyInjection\ContainerInterface;
  9. use Symfony\Bundle\FrameworkBundle\Controller\ControllerNameConverter;
  10. use Symfony\Component\DependencyInjection\ContainerAwareInterface;
  11. /*
  12. * This file is part of the Symfony framework.
  13. *
  14. * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
  15. *
  16. * This source file is subject to the MIT license that is bundled
  17. * with this source code in the file LICENSE.
  18. */
  19. /**
  20. * ControllerResolver.
  21. *
  22. * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  23. */
  24. class ControllerResolver extends BaseControllerResolver
  25. {
  26. protected $container;
  27. protected $converter;
  28. protected $esiSupport;
  29. /**
  30. * Constructor.
  31. *
  32. * @param ContainerInterface $container A ContainerInterface instance
  33. * @param ControllerNameConverter $converter A ControllerNameConverter instance
  34. * @param LoggerInterface $logger A LoggerInterface instance
  35. */
  36. public function __construct(ContainerInterface $container, ControllerNameConverter $converter, LoggerInterface $logger = null)
  37. {
  38. $this->container = $container;
  39. $this->converter = $converter;
  40. $this->esiSupport = $container->has('esi') && $container->getEsiService()->hasSurrogateEsiCapability($container->getRequestService());
  41. parent::__construct($logger);
  42. }
  43. /**
  44. * Returns a callable for the given controller.
  45. *
  46. * @param string $controller A Controller string
  47. *
  48. * @return mixed A PHP callable
  49. */
  50. protected function createController($controller)
  51. {
  52. if (false === strpos($controller, '::')) {
  53. $count = substr_count($controller, ':');
  54. if (2 == $count) {
  55. // controller in the a:b:c notation then
  56. $controller = $this->converter->fromShortNotation($controller);
  57. } elseif (1 == $count) {
  58. // controller in the service:method notation
  59. list($service, $method) = explode(':', $controller);
  60. return array($this->container->get($service), $method);
  61. } else {
  62. throw new \LogicException(sprintf('Unable to parse the controller name "%s".', $controller));
  63. }
  64. }
  65. list($class, $method) = explode('::', $controller);
  66. if (!class_exists($class)) {
  67. throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $class));
  68. }
  69. $controller = new $class();
  70. if ($controller instanceof ContainerAwareInterface) {
  71. $controller->setContainer($this->container);
  72. }
  73. return array($controller, $method);
  74. }
  75. /**
  76. * Forwards the request to another controller.
  77. *
  78. * @param string $controller The controller name (a string like BlogBundle:Post:index)
  79. * @param array $attributes An array of request attributes
  80. * @param array $query An array of request query parameters
  81. *
  82. * @return Response A Response instance
  83. */
  84. public function forward($controller, array $attributes = array(), array $query = array())
  85. {
  86. $attributes['_controller'] = $controller;
  87. $subRequest = $this->container->getRequestService()->duplicate($query, null, $attributes);
  88. return $this->container->get('kernel')->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
  89. }
  90. /**
  91. * Renders a Controller and returns the Response content.
  92. *
  93. * Note that this method generates an esi:include tag only when both the standalone
  94. * option is set to true and the request has ESI capability (@see Symfony\Component\HttpKernel\Cache\ESI).
  95. *
  96. * Available options:
  97. *
  98. * * attributes: An array of request attributes (only when the first argument is a controller)
  99. * * query: An array of request query parameters (only when the first argument is a controller)
  100. * * ignore_errors: true to return an empty string in case of an error
  101. * * alt: an alternative controller to execute in case of an error (can be a controller, a URI, or an array with the controller, the attributes, and the query arguments)
  102. * * standalone: whether to generate an esi:include tag or not when ESI is supported
  103. * * comment: a comment to add when returning an esi:include tag
  104. *
  105. * @param string $controller A controller name to execute (a string like BlogBundle:Post:index), or a relative URI
  106. * @param array $options An array of options
  107. *
  108. * @return string The Response content
  109. */
  110. public function render($controller, array $options = array())
  111. {
  112. $options = array_merge(array(
  113. 'attributes' => array(),
  114. 'query' => array(),
  115. 'ignore_errors' => !$this->container->getParameter('kernel.debug'),
  116. 'alt' => array(),
  117. 'standalone' => false,
  118. 'comment' => '',
  119. ), $options);
  120. if (!is_array($options['alt'])) {
  121. $options['alt'] = array($options['alt']);
  122. }
  123. if ($this->esiSupport && $options['standalone']) {
  124. $uri = $this->generateInternalUri($controller, $options['attributes'], $options['query']);
  125. $alt = '';
  126. if ($options['alt']) {
  127. $alt = $this->generateInternalUri($options['alt'][0], isset($options['alt'][1]) ? $options['alt'][1] : array(), isset($options['alt'][2]) ? $options['alt'][2] : array());
  128. }
  129. return $this->container->getEsiService()->renderTag($uri, $alt, $options['ignore_errors'], $options['comment']);
  130. }
  131. $request = $this->container->getRequestService();
  132. // controller or URI?
  133. if (0 === strpos($controller, '/')) {
  134. $subRequest = Request::create($controller, 'get', array(), $request->cookies->all(), array(), $request->server->all());
  135. $subRequest->setSession($request->getSession());
  136. } else {
  137. $options['attributes']['_controller'] = $controller;
  138. $options['attributes']['_format'] = $request->getRequestFormat();
  139. $subRequest = $request->duplicate($options['query'], null, $options['attributes']);
  140. }
  141. try {
  142. $response = $this->container->getKernelService()->handle($subRequest, HttpKernelInterface::SUB_REQUEST, true);
  143. if (200 != $response->getStatusCode()) {
  144. throw new \RuntimeException(sprintf('Error when rendering "%s" (Status code is %s).', $request->getUri(), $response->getStatusCode()));
  145. }
  146. return $response->getContent();
  147. } catch (\Exception $e) {
  148. if ($options['alt']) {
  149. $alt = $options['alt'];
  150. unset($options['alt']);
  151. $options['attributes'] = isset($alt[1]) ? $alt[1] : array();
  152. $options['query'] = isset($alt[2]) ? $alt[2] : array();
  153. return $this->render($alt[0], $options);
  154. }
  155. if (!$options['ignore_errors']) {
  156. throw $e;
  157. }
  158. }
  159. }
  160. /**
  161. * Generates an internal URI for a given controller.
  162. *
  163. * This method uses the "_internal" route, which should be available.
  164. *
  165. * @param string $controller A controller name to execute (a string like BlogBundle:Post:index), or a relative URI
  166. * @param array $attributes An array of request attributes
  167. * @param array $query An array of request query parameters
  168. *
  169. * @return string An internal URI
  170. */
  171. public function generateInternalUri($controller, array $attributes = array(), array $query = array())
  172. {
  173. if (0 === strpos($controller, '/')) {
  174. return $controller;
  175. }
  176. $uri = $this->container->getRouterService()->generate('_internal', array(
  177. 'controller' => $controller,
  178. 'path' => $attributes ? http_build_query($attributes) : 'none',
  179. '_format' => $this->container->getRequestService()->getRequestFormat(),
  180. ), true);
  181. if ($query) {
  182. $uri = $uri.'?'.http_build_query($query);
  183. }
  184. return $uri;
  185. }
  186. }