PageRenderTime 38ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/core/lib/Drupal/Core/Controller/ControllerResolver.php

http://github.com/drupal/drupal
PHP | 168 lines | 88 code | 18 blank | 62 comment | 19 complexity | 11947b4a3fa28ae2f8130b32a7d32c06 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
  1. <?php
  2. namespace Drupal\Core\Controller;
  3. use Drupal\Core\DependencyInjection\ClassResolverInterface;
  4. use Drupal\Core\Routing\RouteMatch;
  5. use Drupal\Core\Routing\RouteMatchInterface;
  6. use Psr\Http\Message\ServerRequestInterface;
  7. use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface;
  8. use Symfony\Component\HttpFoundation\Request;
  9. use Symfony\Component\HttpKernel\Controller\ControllerResolver as BaseControllerResolver;
  10. /**
  11. * ControllerResolver to enhance controllers beyond Symfony's basic handling.
  12. *
  13. * It adds two behaviors:
  14. *
  15. * - When creating a new object-based controller that implements
  16. * ContainerAwareInterface, inject the container into it. While not always
  17. * necessary, that allows a controller to vary the services it needs at
  18. * runtime.
  19. *
  20. * - By default, a controller name follows the class::method notation. This
  21. * class adds the possibility to use a service from the container as a
  22. * controller by using a service:method notation (Symfony uses the same
  23. * convention).
  24. */
  25. class ControllerResolver extends BaseControllerResolver implements ControllerResolverInterface {
  26. /**
  27. * The class resolver.
  28. *
  29. * @var \Drupal\Core\DependencyInjection\ClassResolverInterface
  30. */
  31. protected $classResolver;
  32. /**
  33. * The PSR-7 converter.
  34. *
  35. * @var \Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface
  36. */
  37. protected $httpMessageFactory;
  38. /**
  39. * Constructs a new ControllerResolver.
  40. *
  41. * @param \Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface $http_message_factory
  42. * The PSR-7 converter.
  43. * @param \Drupal\Core\DependencyInjection\ClassResolverInterface $class_resolver
  44. * The class resolver.
  45. */
  46. public function __construct(HttpMessageFactoryInterface $http_message_factory, ClassResolverInterface $class_resolver) {
  47. $this->httpMessageFactory = $http_message_factory;
  48. $this->classResolver = $class_resolver;
  49. }
  50. /**
  51. * {@inheritdoc}
  52. */
  53. public function getControllerFromDefinition($controller, $path = '') {
  54. if (is_array($controller) || (is_object($controller) && method_exists($controller, '__invoke'))) {
  55. return $controller;
  56. }
  57. if (strpos($controller, ':') === FALSE) {
  58. if (function_exists($controller)) {
  59. return $controller;
  60. }
  61. return $this->classResolver->getInstanceFromDefinition($controller);
  62. }
  63. $callable = $this->createController($controller);
  64. if (!is_callable($callable)) {
  65. throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable.', $path));
  66. }
  67. return $callable;
  68. }
  69. /**
  70. * {@inheritdoc}
  71. */
  72. public function getController(Request $request) {
  73. if (!$controller = $request->attributes->get('_controller')) {
  74. return FALSE;
  75. }
  76. return $this->getControllerFromDefinition($controller, $request->getPathInfo());
  77. }
  78. /**
  79. * Returns a callable for the given controller.
  80. *
  81. * @param string $controller
  82. * A Controller string.
  83. *
  84. * @return mixed
  85. * A PHP callable.
  86. *
  87. * @throws \LogicException
  88. * If the controller cannot be parsed.
  89. *
  90. * @throws \InvalidArgumentException
  91. * If the controller class does not exist.
  92. */
  93. protected function createController($controller) {
  94. // Controller in the service:method notation.
  95. $count = substr_count($controller, ':');
  96. if ($count == 1) {
  97. list($class_or_service, $method) = explode(':', $controller, 2);
  98. }
  99. // Controller in the class::method notation.
  100. elseif (strpos($controller, '::') !== FALSE) {
  101. list($class_or_service, $method) = explode('::', $controller, 2);
  102. }
  103. else {
  104. throw new \LogicException(sprintf('Unable to parse the controller name "%s".', $controller));
  105. }
  106. $controller = $this->classResolver->getInstanceFromDefinition($class_or_service);
  107. return [$controller, $method];
  108. }
  109. /**
  110. * {@inheritdoc}
  111. */
  112. protected function doGetArguments(Request $request, $controller, array $parameters) {
  113. // Note this duplicates the deprecation message of
  114. // Symfony\Component\HttpKernel\Controller\ControllerResolver::getArguments()
  115. // to ensure it is removed in Drupal 9.
  116. @trigger_error(sprintf('%s is deprecated as of 8.6.0 and will be removed in 9.0. Inject the "http_kernel.controller.argument_resolver" service instead.', __METHOD__, ArgumentResolverInterface::class), E_USER_DEPRECATED);
  117. $attributes = $request->attributes->all();
  118. $arguments = [];
  119. foreach ($parameters as $param) {
  120. if (array_key_exists($param->name, $attributes)) {
  121. $arguments[] = $attributes[$param->name];
  122. }
  123. elseif ($param->getClass() && $param->getClass()->isInstance($request)) {
  124. $arguments[] = $request;
  125. }
  126. elseif ($param->getClass() && $param->getClass()->name === ServerRequestInterface::class) {
  127. $arguments[] = $this->httpMessageFactory->createRequest($request);
  128. }
  129. elseif ($param->getClass() && ($param->getClass()->name == RouteMatchInterface::class || is_subclass_of($param->getClass()->name, RouteMatchInterface::class))) {
  130. $arguments[] = RouteMatch::createFromRequest($request);
  131. }
  132. elseif ($param->isDefaultValueAvailable()) {
  133. $arguments[] = $param->getDefaultValue();
  134. }
  135. else {
  136. if (is_array($controller)) {
  137. $repr = sprintf('%s::%s()', get_class($controller[0]), $controller[1]);
  138. }
  139. elseif (is_object($controller)) {
  140. $repr = get_class($controller);
  141. }
  142. else {
  143. $repr = $controller;
  144. }
  145. 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).', $repr, $param->name));
  146. }
  147. }
  148. return $arguments;
  149. }
  150. }