[ Index ]

PHP Cross Reference of phpBB-3.3.14-deutsch

title

Body

[close]

/vendor/symfony/http-kernel/Controller/ -> ControllerResolver.php (source)

   1  <?php
   2  
   3  /*
   4   * This file is part of the Symfony package.
   5   *
   6   * (c) Fabien Potencier <fabien@symfony.com>
   7   *
   8   * For the full copyright and license information, please view the LICENSE
   9   * file that was distributed with this source code.
  10   */
  11  
  12  namespace Symfony\Component\HttpKernel\Controller;
  13  
  14  use Psr\Log\LoggerInterface;
  15  use Symfony\Component\HttpFoundation\Request;
  16  
  17  /**
  18   * This implementation uses the '_controller' request attribute to determine
  19   * the controller to execute and uses the request attributes to determine
  20   * the controller method arguments.
  21   *
  22   * @author Fabien Potencier <fabien@symfony.com>
  23   */
  24  class ControllerResolver implements ArgumentResolverInterface, ControllerResolverInterface
  25  {
  26      private $logger;
  27  
  28      /**
  29       * If the ...$arg functionality is available.
  30       *
  31       * Requires at least PHP 5.6.0 or HHVM 3.9.1
  32       *
  33       * @var bool
  34       */
  35      private $supportsVariadic;
  36  
  37      /**
  38       * If scalar types exists.
  39       *
  40       * @var bool
  41       */
  42      private $supportsScalarTypes;
  43  
  44      public function __construct(LoggerInterface $logger = null)
  45      {
  46          $this->logger = $logger;
  47  
  48          $this->supportsVariadic = method_exists('ReflectionParameter', 'isVariadic');
  49          $this->supportsScalarTypes = method_exists('ReflectionParameter', 'getType');
  50      }
  51  
  52      /**
  53       * {@inheritdoc}
  54       *
  55       * This method looks for a '_controller' request attribute that represents
  56       * the controller name (a string like ClassName::MethodName).
  57       */
  58      public function getController(Request $request)
  59      {
  60          if (!$controller = $request->attributes->get('_controller')) {
  61              if (null !== $this->logger) {
  62                  $this->logger->warning('Unable to look for the controller as the "_controller" parameter is missing.');
  63              }
  64  
  65              return false;
  66          }
  67  
  68          if (\is_array($controller)) {
  69              return $controller;
  70          }
  71  
  72          if (\is_object($controller)) {
  73              if (method_exists($controller, '__invoke')) {
  74                  return $controller;
  75              }
  76  
  77              throw new \InvalidArgumentException(sprintf('Controller "%s" for URI "%s" is not callable.', \get_class($controller), $request->getPathInfo()));
  78          }
  79  
  80          if (\is_string($controller) && false === strpos($controller, ':')) {
  81              if (method_exists($controller, '__invoke')) {
  82                  return $this->instantiateController($controller);
  83              } elseif (\function_exists($controller)) {
  84                  return $controller;
  85              }
  86          }
  87  
  88          try {
  89              $callable = $this->createController($controller);
  90          } catch (\InvalidArgumentException $e) {
  91              throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable: ', $request->getPathInfo()).$e->getMessage(), 0, $e);
  92          }
  93  
  94          return $callable;
  95      }
  96  
  97      /**
  98       * {@inheritdoc}
  99       *
 100       * @deprecated This method is deprecated as of 3.1 and will be removed in 4.0. Implement the ArgumentResolverInterface and inject it in the HttpKernel instead.
 101       */
 102      public function getArguments(Request $request, $controller)
 103      {
 104          @trigger_error(sprintf('The "%s()" method is deprecated as of 3.1 and will be removed in 4.0. Implement the %s and inject it in the HttpKernel instead.', __METHOD__, ArgumentResolverInterface::class), \E_USER_DEPRECATED);
 105  
 106          if (\is_array($controller)) {
 107              $r = new \ReflectionMethod($controller[0], $controller[1]);
 108          } elseif (\is_object($controller) && !$controller instanceof \Closure) {
 109              $r = new \ReflectionObject($controller);
 110              $r = $r->getMethod('__invoke');
 111          } else {
 112              $r = new \ReflectionFunction($controller);
 113          }
 114  
 115          return $this->doGetArguments($request, $controller, $r->getParameters());
 116      }
 117  
 118      /**
 119       * @param callable               $controller
 120       * @param \ReflectionParameter[] $parameters
 121       *
 122       * @return array The arguments to use when calling the action
 123       *
 124       * @deprecated This method is deprecated as of 3.1 and will be removed in 4.0. Implement the ArgumentResolverInterface and inject it in the HttpKernel instead.
 125       */
 126      protected function doGetArguments(Request $request, $controller, array $parameters)
 127      {
 128          @trigger_error(sprintf('The "%s()" method is deprecated as of 3.1 and will be removed in 4.0. Implement the %s and inject it in the HttpKernel instead.', __METHOD__, ArgumentResolverInterface::class), \E_USER_DEPRECATED);
 129  
 130          $attributes = $request->attributes->all();
 131          $arguments = [];
 132          foreach ($parameters as $param) {
 133              if (\array_key_exists($param->name, $attributes)) {
 134                  if ($this->supportsVariadic && $param->isVariadic() && \is_array($attributes[$param->name])) {
 135                      $arguments = array_merge($arguments, array_values($attributes[$param->name]));
 136                  } else {
 137                      $arguments[] = $attributes[$param->name];
 138                  }
 139              } elseif ($this->typeMatchesRequestClass($param, $request)) {
 140                  $arguments[] = $request;
 141              } elseif ($param->isDefaultValueAvailable()) {
 142                  $arguments[] = $param->getDefaultValue();
 143              } elseif ($this->supportsScalarTypes && $param->hasType() && $param->allowsNull()) {
 144                  $arguments[] = null;
 145              } else {
 146                  if (\is_array($controller)) {
 147                      $repr = sprintf('%s::%s()', \get_class($controller[0]), $controller[1]);
 148                  } elseif (\is_object($controller)) {
 149                      $repr = \get_class($controller);
 150                  } else {
 151                      $repr = $controller;
 152                  }
 153  
 154                  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));
 155              }
 156          }
 157  
 158          return $arguments;
 159      }
 160  
 161      /**
 162       * Returns a callable for the given controller.
 163       *
 164       * @param string $controller A Controller string
 165       *
 166       * @return callable A PHP callable
 167       *
 168       * @throws \InvalidArgumentException When the controller cannot be created
 169       */
 170      protected function createController($controller)
 171      {
 172          if (false === strpos($controller, '::')) {
 173              throw new \InvalidArgumentException(sprintf('Unable to find controller "%s".', $controller));
 174          }
 175  
 176          list($class, $method) = explode('::', $controller, 2);
 177  
 178          if (!class_exists($class)) {
 179              throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $class));
 180          }
 181  
 182          $controller = [$this->instantiateController($class), $method];
 183  
 184          if (!\is_callable($controller)) {
 185              throw new \InvalidArgumentException($this->getControllerError($controller));
 186          }
 187  
 188          return $controller;
 189      }
 190  
 191      /**
 192       * Returns an instantiated controller.
 193       *
 194       * @param string $class A class name
 195       *
 196       * @return object
 197       */
 198      protected function instantiateController($class)
 199      {
 200          return new $class();
 201      }
 202  
 203      private function getControllerError($callable)
 204      {
 205          if (\is_string($callable)) {
 206              if (false !== strpos($callable, '::')) {
 207                  $callable = explode('::', $callable);
 208              }
 209  
 210              if (class_exists($callable) && !method_exists($callable, '__invoke')) {
 211                  return sprintf('Class "%s" does not have a method "__invoke".', $callable);
 212              }
 213  
 214              if (!\function_exists($callable)) {
 215                  return sprintf('Function "%s" does not exist.', $callable);
 216              }
 217          }
 218  
 219          if (!\is_array($callable)) {
 220              return sprintf('Invalid type for controller given, expected string or array, got "%s".', \gettype($callable));
 221          }
 222  
 223          if (2 !== \count($callable)) {
 224              return 'Invalid format for controller, expected [controller, method] or controller::method.';
 225          }
 226  
 227          list($controller, $method) = $callable;
 228  
 229          if (\is_string($controller) && !class_exists($controller)) {
 230              return sprintf('Class "%s" does not exist.', $controller);
 231          }
 232  
 233          $className = \is_object($controller) ? \get_class($controller) : $controller;
 234  
 235          if (method_exists($controller, $method)) {
 236              return sprintf('Method "%s" on class "%s" should be public and non-abstract.', $method, $className);
 237          }
 238  
 239          $collection = get_class_methods($controller);
 240  
 241          $alternatives = [];
 242  
 243          foreach ($collection as $item) {
 244              $lev = levenshtein($method, $item);
 245  
 246              if ($lev <= \strlen($method) / 3 || false !== strpos($item, $method)) {
 247                  $alternatives[] = $item;
 248              }
 249          }
 250  
 251          asort($alternatives);
 252  
 253          $message = sprintf('Expected method "%s" on class "%s"', $method, $className);
 254  
 255          if (\count($alternatives) > 0) {
 256              $message .= sprintf(', did you mean "%s"?', implode('", "', $alternatives));
 257          } else {
 258              $message .= sprintf('. Available methods: "%s".', implode('", "', $collection));
 259          }
 260  
 261          return $message;
 262      }
 263  
 264      /**
 265       * @return bool
 266       */
 267      private function typeMatchesRequestClass(\ReflectionParameter $param, Request $request)
 268      {
 269          if (!method_exists($param, 'getType')) {
 270              return $param->getClass() && $param->getClass()->isInstance($request);
 271          }
 272  
 273          if (!($type = $param->getType()) || $type->isBuiltin()) {
 274              return false;
 275          }
 276  
 277          $class = new \ReflectionClass($type instanceof \ReflectionNamedType ? $type->getName() : (string) $type);
 278  
 279          return $class && $class->isInstance($request);
 280      }
 281  }


Generated: Mon Nov 25 19:05:08 2024 Cross-referenced by PHPXref 0.7.1