vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php line 88

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