From dad177a7faa487b6a12314d9d9ad1806a7d11a0a Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Tue, 27 Oct 2020 17:37:00 +0000 Subject: [PATCH 1/2] Fixed instance style callable routes --- src/Illuminate/Routing/RouteAction.php | 20 ++++++++++++++++++-- src/Illuminate/Support/Reflector.php | 25 +++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Routing/RouteAction.php b/src/Illuminate/Routing/RouteAction.php index a1839758cf9e..44a414a93be4 100644 --- a/src/Illuminate/Routing/RouteAction.php +++ b/src/Illuminate/Routing/RouteAction.php @@ -3,6 +3,7 @@ namespace Illuminate\Routing; use Illuminate\Support\Arr; +use Illuminate\Support\Reflector; use Illuminate\Support\Str; use LogicException; use UnexpectedValueException; @@ -28,7 +29,7 @@ public static function parse($uri, $action) // If the action is already a Closure instance, we will just set that instance // as the "uses" property, because there is nothing else we need to do when // it is available. Otherwise we will need to find it in the action list. - if (is_callable($action, true)) { + if (static::isCallable($action)) { return ! is_array($action) ? ['uses' => $action] : [ 'uses' => $action[0].'@'.$action[1], 'controller' => $action[0].'@'.$action[1], @@ -73,10 +74,25 @@ protected static function missingAction($uri) protected static function findCallable(array $action) { return Arr::first($action, function ($value, $key) { - return is_callable($value) && is_numeric($key); + return static::isCallable($value) && is_numeric($key); }); } + /** + * Determine if the given action is callable as a route. + * + * @param mixed $action + * @return bool + */ + public static function isCallable($action) + { + if (! is_array($action)) { + return is_callable($action); + } + + return isset($action[0], $action[1]) && is_string($action[0]) && is_string($action[1]) && Reflector::isMethodCallable($action[0], $action[1]); + } + /** * Make an action for an invokable controller. * diff --git a/src/Illuminate/Support/Reflector.php b/src/Illuminate/Support/Reflector.php index fb597f5141f1..db6a2a75a8fc 100644 --- a/src/Illuminate/Support/Reflector.php +++ b/src/Illuminate/Support/Reflector.php @@ -3,6 +3,7 @@ namespace Illuminate\Support; use ReflectionClass; +use ReflectionMethod; use ReflectionNamedType; class Reflector @@ -51,4 +52,28 @@ public static function isParameterSubclassOf($parameter, $className) ? (new ReflectionClass($paramClassName))->isSubclassOf($className) : false; } + + /** + * Determine if the class method is callable. + * + * @param string $class + * @param string $method + * @return bool + */ + public static function isMethodCallable($class, $method) + { + if (! class_exists($class)) { + return false; + } + + if (method_exists($class, $method)) { + return (new ReflectionMethod($class, $method))->isPublic(); + } + + if (method_exists($class, '__call')) { + return (new ReflectionMethod($class, '__call'))->isPublic(); + } + + return false; + } } From 25a1d76ae7a55636b7a3a1e88427f0d3b0b5ef4a Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Tue, 27 Oct 2020 19:12:56 +0100 Subject: [PATCH 2/2] Add test --- tests/Routing/RouteRegistrarTest.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/Routing/RouteRegistrarTest.php b/tests/Routing/RouteRegistrarTest.php index e48d4a4985e7..78db4bb4c0ee 100644 --- a/tests/Routing/RouteRegistrarTest.php +++ b/tests/Routing/RouteRegistrarTest.php @@ -129,6 +129,15 @@ public function testCanRegisterRouteWithControllerAction() $this->seeMiddleware('controller-middleware'); } + public function testCanRegisterRouteWithControllerActionArray() + { + $this->router->middleware('controller-middleware') + ->get('users', [RouteRegistrarControllerStub::class, 'index']); + + $this->seeResponse('controller', Request::create('users', 'GET')); + $this->seeMiddleware('controller-middleware'); + } + public function testCanRegisterRouteWithArrayAndControllerAction() { $this->router->middleware('controller-middleware')->put('users', [