Security update for Core, with self-updated composer
[yaffs-website] / vendor / symfony / http-kernel / Controller / ControllerResolver.php
index a1cff53535dc1a155941d00971cfb1bb6e99f994..f51a5a8efb1c17ce65acd9dd1afa8a72e78d2311 100644 (file)
@@ -23,7 +23,7 @@ use Symfony\Component\HttpFoundation\Request;
  *
  * @author Fabien Potencier <fabien@symfony.com>
  */
-class ControllerResolver implements ControllerResolverInterface
+class ControllerResolver implements ArgumentResolverInterface, ControllerResolverInterface
 {
     private $logger;
 
@@ -95,7 +95,7 @@ class ControllerResolver implements ControllerResolverInterface
         $callable = $this->createController($controller);
 
         if (!is_callable($callable)) {
-            throw new \InvalidArgumentException(sprintf('Controller "%s" for URI "%s" is not callable.', $controller, $request->getPathInfo()));
+            throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable. %s', $request->getPathInfo(), $this->getControllerError($callable)));
         }
 
         return $callable;
@@ -103,9 +103,13 @@ class ControllerResolver implements ControllerResolverInterface
 
     /**
      * {@inheritdoc}
+     *
+     * @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.
      */
     public function getArguments(Request $request, $controller)
     {
+        @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);
+
         if (is_array($controller)) {
             $r = new \ReflectionMethod($controller[0], $controller[1]);
         } elseif (is_object($controller) && !$controller instanceof \Closure) {
@@ -124,9 +128,13 @@ class ControllerResolver implements ControllerResolverInterface
      * @param \ReflectionParameter[] $parameters
      *
      * @return array The arguments to use when calling the action
+     *
+     * @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.
      */
     protected function doGetArguments(Request $request, $controller, array $parameters)
     {
+        @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);
+
         $attributes = $request->attributes->all();
         $arguments = array();
         foreach ($parameters as $param) {
@@ -193,4 +201,65 @@ class ControllerResolver implements ControllerResolverInterface
     {
         return new $class();
     }
+
+    private function getControllerError($callable)
+    {
+        if (is_string($callable)) {
+            if (false !== strpos($callable, '::')) {
+                $callable = explode('::', $callable);
+            }
+
+            if (class_exists($callable) && !method_exists($callable, '__invoke')) {
+                return sprintf('Class "%s" does not have a method "__invoke".', $callable);
+            }
+
+            if (!function_exists($callable)) {
+                return sprintf('Function "%s" does not exist.', $callable);
+            }
+        }
+
+        if (!is_array($callable)) {
+            return sprintf('Invalid type for controller given, expected string or array, got "%s".', gettype($callable));
+        }
+
+        if (2 !== count($callable)) {
+            return sprintf('Invalid format for controller, expected array(controller, method) or controller::method.');
+        }
+
+        list($controller, $method) = $callable;
+
+        if (is_string($controller) && !class_exists($controller)) {
+            return sprintf('Class "%s" does not exist.', $controller);
+        }
+
+        $className = is_object($controller) ? get_class($controller) : $controller;
+
+        if (method_exists($controller, $method)) {
+            return sprintf('Method "%s" on class "%s" should be public and non-abstract.', $method, $className);
+        }
+
+        $collection = get_class_methods($controller);
+
+        $alternatives = array();
+
+        foreach ($collection as $item) {
+            $lev = levenshtein($method, $item);
+
+            if ($lev <= strlen($method) / 3 || false !== strpos($item, $method)) {
+                $alternatives[] = $item;
+            }
+        }
+
+        asort($alternatives);
+
+        $message = sprintf('Expected method "%s" on class "%s"', $method, $className);
+
+        if (count($alternatives) > 0) {
+            $message .= sprintf(', did you mean "%s"?', implode('", "', $alternatives));
+        } else {
+            $message .= sprintf('. Available methods: "%s".', implode('", "', $collection));
+        }
+
+        return $message;
+    }
 }