From ae06d48dfea40a2cb9ebd550d86966dc113850f1 Mon Sep 17 00:00:00 2001 From: Luke Downing Date: Thu, 6 Jan 2022 11:47:15 +0000 Subject: [PATCH 1/7] Adds support for specifying a route group controller. --- src/Illuminate/Routing/RouteGroup.php | 4 ++ src/Illuminate/Routing/RouteRegistrar.php | 2 + src/Illuminate/Routing/Router.php | 21 ++++++-- tests/Routing/RouteRegistrarTest.php | 66 ++++++++++++++++++++--- 4 files changed, 83 insertions(+), 10 deletions(-) diff --git a/src/Illuminate/Routing/RouteGroup.php b/src/Illuminate/Routing/RouteGroup.php index 4dad20d3da7b..18dbb5245b8f 100644 --- a/src/Illuminate/Routing/RouteGroup.php +++ b/src/Illuminate/Routing/RouteGroup.php @@ -20,6 +20,10 @@ public static function merge($new, $old, $prependExistingPrefix = true) unset($old['domain']); } + if (isset($new['controller'])) { + unset($old['controller']); + } + $new = array_merge(static::formatAs($new, $old), [ 'namespace' => static::formatNamespace($new, $old), 'prefix' => static::formatPrefix($new, $old, $prependExistingPrefix), diff --git a/src/Illuminate/Routing/RouteRegistrar.php b/src/Illuminate/Routing/RouteRegistrar.php index 46ba84c80892..64c1359bd61d 100644 --- a/src/Illuminate/Routing/RouteRegistrar.php +++ b/src/Illuminate/Routing/RouteRegistrar.php @@ -17,6 +17,7 @@ * @method \Illuminate\Routing\Route options(string $uri, \Closure|array|string|null $action = null) * @method \Illuminate\Routing\Route any(string $uri, \Closure|array|string|null $action = null) * @method \Illuminate\Routing\RouteRegistrar as(string $value) + * @method \Illuminate\Routing\RouteRegistrar controller(string $controller) * @method \Illuminate\Routing\RouteRegistrar domain(string $value) * @method \Illuminate\Routing\RouteRegistrar middleware(array|string|null $middleware) * @method \Illuminate\Routing\RouteRegistrar name(string $value) @@ -58,6 +59,7 @@ class RouteRegistrar */ protected $allowedAttributes = [ 'as', + 'controller', 'domain', 'middleware', 'name', diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index 64e32373ace6..f2618d67ff88 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -515,10 +515,11 @@ protected function convertToControllerAction($action) $action = ['uses' => $action]; } - // Here we'll merge any group "uses" statement if necessary so that the action - // has the proper clause for this property. Then we can simply set the name - // of the controller on the action and return the action array for usage. + // Here we'll merge any group "controller" and "uses" statements if necessary so that + // the action has the proper clause for this property. Then we can simply set the + // name of the controller on the action and return the action array for usage. if ($this->hasGroupStack()) { + $action['uses'] = $this->prependGroupController($action['uses']); $action['uses'] = $this->prependGroupNamespace($action['uses']); } @@ -544,6 +545,20 @@ protected function prependGroupNamespace($class) ? $group['namespace'].'\\'.$class : $class; } + /** + * Prepend the last group controller onto the use clause. + * + * @param string $class + * @return string + */ + protected function prependGroupController($class) + { + $group = end($this->groupStack); + + return isset($group['controller']) && strpos($class, '@') === false + ? $group['controller'].'@'.$class : $class; + } + /** * Create a new Route object. * diff --git a/tests/Routing/RouteRegistrarTest.php b/tests/Routing/RouteRegistrarTest.php index 4daf41f813f7..a1afb19807e0 100644 --- a/tests/Routing/RouteRegistrarTest.php +++ b/tests/Routing/RouteRegistrarTest.php @@ -3,9 +3,11 @@ namespace Illuminate\Tests\Routing; use BadMethodCallException; +use FooController; use Illuminate\Container\Container; use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Http\Request; +use Illuminate\Routing\Route; use Illuminate\Routing\Router; use Mockery as m; use PHPUnit\Framework\TestCase; @@ -14,7 +16,7 @@ class RouteRegistrarTest extends TestCase { /** - * @var \Illuminate\Routing\Router + * @var Router */ protected $router; @@ -346,6 +348,56 @@ public function testCanRegisterGroupWithDomainAndNamePrefix() $this->assertSame('api.users', $this->getRoute()->getName()); } + public function testCanRegisterGroupWithController() + { + $this->router->controller(RouteRegistrarControllerStub::class)->group(function ($router) { + $router->get('users', 'index'); + }); + + $this->assertSame( + RouteRegistrarControllerStub::class.'@index', + $this->getRoute()->getAction()['uses'] + ); + } + + public function testCanOverrideGroupControllerWithStringSyntax() + { + $this->router->controller(RouteRegistrarControllerStub::class)->group(function ($router) { + $router->get('users', 'UserController@index'); + }); + + $this->assertSame( + 'UserController@index', + $this->getRoute()->getAction()['uses'] + ); + } + + public function testWillUseTheLatestGroupController() + { + $this->router->controller(RouteRegistrarControllerStub::class)->group(function ($router) { + $router->group(['controller' => FooController::class], function ($router) { + $router->get('users', 'index'); + }); + }); + + $this->assertSame( + FooController::class.'@index', + $this->getRoute()->getAction()['uses'] + ); + } + + public function testCanOverrideGroupControllerWithArraySyntax() + { + $this->router->controller(RouteRegistrarControllerStub::class)->group(function ($router) { + $router->get('users', [FooController::class, 'index']); + }); + + $this->assertSame( + FooController::class.'@index', + $this->getRoute()->getAction()['uses'] + ); + } + public function testRouteGroupingWithoutPrefix() { $this->router->group([], function ($router) { @@ -733,7 +785,7 @@ public function testResourceWheres() $this->router->resource('users', RouteRegistrarControllerStub::class) ->where($wheres); - /** @var \Illuminate\Routing\Route $route */ + /** @var Route $route */ foreach ($this->router->getRoutes() as $route) { $this->assertEquals($wheres, $route->wheres); } @@ -746,7 +798,7 @@ public function testWhereNumberRegistration() $this->router->get('/{foo}/{bar}')->whereNumber(['foo', 'bar']); $this->router->get('/api/{bar}/{foo}')->whereNumber(['bar', 'foo']); - /** @var \Illuminate\Routing\Route $route */ + /** @var Route $route */ foreach ($this->router->getRoutes() as $route) { $this->assertEquals($wheres, $route->wheres); } @@ -759,7 +811,7 @@ public function testWhereAlphaRegistration() $this->router->get('/{foo}/{bar}')->whereAlpha(['foo', 'bar']); $this->router->get('/api/{bar}/{foo}')->whereAlpha(['bar', 'foo']); - /** @var \Illuminate\Routing\Route $route */ + /** @var Route $route */ foreach ($this->router->getRoutes() as $route) { $this->assertEquals($wheres, $route->wheres); } @@ -771,7 +823,7 @@ public function testWhereAlphaNumericRegistration() $this->router->get('/{foo}')->whereAlphaNumeric(['1a2b3c']); - /** @var \Illuminate\Routing\Route $route */ + /** @var Route $route */ foreach ($this->router->getRoutes() as $route) { $this->assertEquals($wheres, $route->wheres); } @@ -800,7 +852,7 @@ public function testCanSetRouteNameUsingNameAlias() /** * Get the last route registered with the router. * - * @return \Illuminate\Routing\Route + * @return Route */ protected function getRoute() { @@ -822,7 +874,7 @@ protected function seeMiddleware($middleware) * Assert that the last route has the given content. * * @param string $content - * @param \Illuminate\Http\Request $request + * @param Request $request * @return void */ protected function seeResponse($content, Request $request) From a9b9bb0e0ffe862ffdb391b473e8a1efd08a37b4 Mon Sep 17 00:00:00 2001 From: Luke Downing Date: Thu, 6 Jan 2022 12:49:32 +0000 Subject: [PATCH 2/7] Adds support for specifying a route group controller. --- tests/Routing/RouteRegistrarTest.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/Routing/RouteRegistrarTest.php b/tests/Routing/RouteRegistrarTest.php index a1afb19807e0..178e21a7ff57 100644 --- a/tests/Routing/RouteRegistrarTest.php +++ b/tests/Routing/RouteRegistrarTest.php @@ -372,6 +372,17 @@ public function testCanOverrideGroupControllerWithStringSyntax() ); } + public function testCanOverrideGroupControllerWithClosureSyntax() + { + $this->router->controller(RouteRegistrarControllerStub::class)->group(function ($router) { + $router->get('users', function () { + return 'hello world'; + }); + }); + + $this->seeResponse('hello world', Request::create('users', 'GET')); + } + public function testWillUseTheLatestGroupController() { $this->router->controller(RouteRegistrarControllerStub::class)->group(function ($router) { @@ -874,7 +885,7 @@ protected function seeMiddleware($middleware) * Assert that the last route has the given content. * * @param string $content - * @param Request $request + * @param Request $request * @return void */ protected function seeResponse($content, Request $request) From 804b6b66e765d9547ef0bb5be29ba7da133517b5 Mon Sep 17 00:00:00 2001 From: Luke Downing Date: Thu, 6 Jan 2022 12:53:09 +0000 Subject: [PATCH 3/7] Adds support for specifying a route group controller. --- tests/Routing/RouteRegistrarTest.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/Routing/RouteRegistrarTest.php b/tests/Routing/RouteRegistrarTest.php index 178e21a7ff57..08ac79a29012 100644 --- a/tests/Routing/RouteRegistrarTest.php +++ b/tests/Routing/RouteRegistrarTest.php @@ -16,7 +16,7 @@ class RouteRegistrarTest extends TestCase { /** - * @var Router + * @var \Illuminate\Routing\Router */ protected $router; @@ -796,7 +796,7 @@ public function testResourceWheres() $this->router->resource('users', RouteRegistrarControllerStub::class) ->where($wheres); - /** @var Route $route */ + /** @var \Illuminate\Routing\Route $route */ foreach ($this->router->getRoutes() as $route) { $this->assertEquals($wheres, $route->wheres); } @@ -809,7 +809,7 @@ public function testWhereNumberRegistration() $this->router->get('/{foo}/{bar}')->whereNumber(['foo', 'bar']); $this->router->get('/api/{bar}/{foo}')->whereNumber(['bar', 'foo']); - /** @var Route $route */ + /** @var \Illuminate\Routing\Route $route */ foreach ($this->router->getRoutes() as $route) { $this->assertEquals($wheres, $route->wheres); } @@ -822,7 +822,7 @@ public function testWhereAlphaRegistration() $this->router->get('/{foo}/{bar}')->whereAlpha(['foo', 'bar']); $this->router->get('/api/{bar}/{foo}')->whereAlpha(['bar', 'foo']); - /** @var Route $route */ + /** @var \Illuminate\Routing\Route $route */ foreach ($this->router->getRoutes() as $route) { $this->assertEquals($wheres, $route->wheres); } @@ -834,7 +834,7 @@ public function testWhereAlphaNumericRegistration() $this->router->get('/{foo}')->whereAlphaNumeric(['1a2b3c']); - /** @var Route $route */ + /** @var \Illuminate\Routing\Route $route */ foreach ($this->router->getRoutes() as $route) { $this->assertEquals($wheres, $route->wheres); } @@ -863,7 +863,7 @@ public function testCanSetRouteNameUsingNameAlias() /** * Get the last route registered with the router. * - * @return Route + * @return \Illuminate\Routing\Route */ protected function getRoute() { @@ -885,7 +885,7 @@ protected function seeMiddleware($middleware) * Assert that the last route has the given content. * * @param string $content - * @param Request $request + * @param \Illuminate\Http\Request $request $request * @return void */ protected function seeResponse($content, Request $request) From 67f379f3c3f81abd064e6e7a78301e4dfccd9d84 Mon Sep 17 00:00:00 2001 From: Luke Downing Date: Thu, 6 Jan 2022 12:53:31 +0000 Subject: [PATCH 4/7] Adds support for specifying a route group controller. --- tests/Routing/RouteRegistrarTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Routing/RouteRegistrarTest.php b/tests/Routing/RouteRegistrarTest.php index 08ac79a29012..3f1f42110ef0 100644 --- a/tests/Routing/RouteRegistrarTest.php +++ b/tests/Routing/RouteRegistrarTest.php @@ -885,7 +885,7 @@ protected function seeMiddleware($middleware) * Assert that the last route has the given content. * * @param string $content - * @param \Illuminate\Http\Request $request $request + * @param \Illuminate\Http\Request $request $request * @return void */ protected function seeResponse($content, Request $request) From 7b3712ffdf70ebd62df42ef0c67b83a3dea7ed11 Mon Sep 17 00:00:00 2001 From: Luke Downing Date: Thu, 6 Jan 2022 12:53:49 +0000 Subject: [PATCH 5/7] Adds support for specifying a route group controller. --- tests/Routing/RouteRegistrarTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Routing/RouteRegistrarTest.php b/tests/Routing/RouteRegistrarTest.php index 3f1f42110ef0..cfec7f905707 100644 --- a/tests/Routing/RouteRegistrarTest.php +++ b/tests/Routing/RouteRegistrarTest.php @@ -885,7 +885,7 @@ protected function seeMiddleware($middleware) * Assert that the last route has the given content. * * @param string $content - * @param \Illuminate\Http\Request $request $request + * @param \Illuminate\Http\Request $request * @return void */ protected function seeResponse($content, Request $request) From bcf51fb9243be7394e85ee807caef7eb0c318fcb Mon Sep 17 00:00:00 2001 From: Luke Downing Date: Fri, 7 Jan 2022 11:36:14 +0000 Subject: [PATCH 6/7] Adds support for overriding using invokable classes. --- src/Illuminate/Routing/Router.php | 15 +++++++++++++-- tests/Routing/RouteRegistrarTest.php | 20 ++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index f2618d67ff88..a5e31c4ca381 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -555,8 +555,19 @@ protected function prependGroupController($class) { $group = end($this->groupStack); - return isset($group['controller']) && strpos($class, '@') === false - ? $group['controller'].'@'.$class : $class; + if (! isset($group['controller'])) { + return $class; + } + + if (class_exists($class)) { + return $class; + } + + if (strpos($class, '@') !== false) { + return $class; + } + + return $group['controller'].'@'.$class; } /** diff --git a/tests/Routing/RouteRegistrarTest.php b/tests/Routing/RouteRegistrarTest.php index cfec7f905707..62825149f17d 100644 --- a/tests/Routing/RouteRegistrarTest.php +++ b/tests/Routing/RouteRegistrarTest.php @@ -383,6 +383,18 @@ public function testCanOverrideGroupControllerWithClosureSyntax() $this->seeResponse('hello world', Request::create('users', 'GET')); } + public function testCanOverrideGroupControllerWithInvokableControllerSyntax() + { + $this->router->controller(RouteRegistrarControllerStub::class)->group(function ($router) { + $router->get('users', InvokableRouteRegistrarControllerStub::class); + }); + + $this->assertSame( + InvokableRouteRegistrarControllerStub::class.'@__invoke', + $this->getRoute()->getAction()['uses'] + ); + } + public function testWillUseTheLatestGroupController() { $this->router->controller(RouteRegistrarControllerStub::class)->group(function ($router) { @@ -911,6 +923,14 @@ public function destroy() } } +class InvokableRouteRegistrarControllerStub +{ + public function __invoke() + { + return 'controller'; + } +} + class RouteRegistrarMiddlewareStub { // From c0cf4ab94b058d6155451c2b853cdeb2cfaad129 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 13 Jan 2022 12:40:21 -0600 Subject: [PATCH 7/7] formatting --- src/Illuminate/Routing/Router.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index a5e31c4ca381..26f6ec9ba28d 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -516,8 +516,8 @@ protected function convertToControllerAction($action) } // Here we'll merge any group "controller" and "uses" statements if necessary so that - // the action has the proper clause for this property. Then we can simply set the - // name of the controller on the action and return the action array for usage. + // the action has the proper clause for this property. Then, we can simply set the + // name of this controller on the action plus return the action array for usage. if ($this->hasGroupStack()) { $action['uses'] = $this->prependGroupController($action['uses']); $action['uses'] = $this->prependGroupNamespace($action['uses']);