Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[8.x] Adds support for specifying a route group controller #40276

Merged
merged 7 commits into from
Jan 13, 2022
4 changes: 4 additions & 0 deletions src/Illuminate/Routing/RouteGroup.php
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
2 changes: 2 additions & 0 deletions src/Illuminate/Routing/RouteRegistrar.php
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -58,6 +59,7 @@ class RouteRegistrar
*/
protected $allowedAttributes = [
'as',
'controller',
'domain',
'middleware',
'name',
Expand Down
32 changes: 29 additions & 3 deletions src/Illuminate/Routing/Router.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 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']);
}

Expand All @@ -544,6 +545,31 @@ 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);

if (! isset($group['controller'])) {
return $class;
}

if (class_exists($class)) {
return $class;
}

if (strpos($class, '@') !== false) {
return $class;
}

return $group['controller'].'@'.$class;
}

/**
* Create a new Route object.
*
Expand Down
83 changes: 83 additions & 0 deletions tests/Routing/RouteRegistrarTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -346,6 +348,79 @@ 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 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 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) {
$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) {
Expand Down Expand Up @@ -848,6 +923,14 @@ public function destroy()
}
}

class InvokableRouteRegistrarControllerStub
{
public function __invoke()
{
return 'controller';
}
}

class RouteRegistrarMiddlewareStub
{
//
Expand Down