Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 27 additions & 5 deletions src/Illuminate/Routing/RouteCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ protected function addLookups($route)
// If the route has a name, we will add it to the name look-up table, so that we
// will quickly be able to find the route associated with a name and not have
// to iterate through every route every time we need to find a named route.
if ($name = $route->getName()) {
if (($name = $route->getName()) && ! $this->inNameLookup($name)) {
$this->nameList[$name] = $route;
}

Expand All @@ -88,7 +88,7 @@ protected function addLookups($route)
// processing a request and easily generate URLs to the given controllers.
$action = $route->getAction();

if (isset($action['controller'])) {
if (($controller = $action['controller'] ?? null) && ! $this->inActionLookup($controller)) {
$this->addToActionList($action, $route);
}
}
Expand All @@ -105,6 +105,28 @@ protected function addToActionList($action, $route)
$this->actionList[trim($action['controller'], '\\')] = $route;
}

/**
* Determine if the given controller is in the action lookup table.
*
* @param string $controller
* @return bool
*/
protected function inActionLookup($controller)
{
return array_key_exists($controller, $this->actionList);
}

/**
* Determine if the given name is in the name lookup table.
*
* @param string $name
* @return bool
*/
protected function inNameLookup($name)
{
return array_key_exists($name, $this->nameList);
}

/**
* Refresh the name look-up table.
*
Expand All @@ -117,8 +139,8 @@ public function refreshNameLookups()
$this->nameList = [];

foreach ($this->allRoutes as $route) {
if ($route->getName()) {
$this->nameList[$route->getName()] = $route;
if (($name = $route->getName()) && ! $this->inNameLookup($name)) {
$this->nameList[$name] = $route;
}
}
}
Expand All @@ -135,7 +157,7 @@ public function refreshActionLookups()
$this->actionList = [];

foreach ($this->allRoutes as $route) {
if (isset($route->getAction()['controller'])) {
if (($controller = $route->getAction()['controller'] ?? null) && ! $this->inActionLookup($controller)) {
$this->addToActionList($route->getAction(), $route);
}
}
Expand Down
32 changes: 32 additions & 0 deletions tests/Integration/Routing/CompiledRouteCollectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,38 @@ public function testRouteCollectionCanRetrieveByAction()
$this->assertSame($action, Arr::except($route->getAction(), 'as'));
}

public function testCompiledAndNonCompiledUrlResolutionHasSamePrecedenceForActions()
{
@unlink(__DIR__.'/Fixtures/cache/routes-v7.php');
$this->app->useBootstrapPath(__DIR__.'/Fixtures');
$app = (static function () {
$refresh = true;

return require __DIR__.'/Fixtures/app.php';
})();
$app['router']->get('/foo/{bar}', ['FooController', 'show']);
$app['router']->get('/foo/{bar}/{baz}', ['FooController', 'show']);
$app['router']->getRoutes()->refreshActionLookups();

$this->assertSame('foo/{bar}', $app['router']->getRoutes()->getByAction('FooController@show')->uri);

$this->artisan('route:cache')->assertExitCode(0);
require __DIR__.'/Fixtures/cache/routes-v7.php';

$this->assertSame('foo/{bar}', $app['router']->getRoutes()->getByAction('FooController@show')->uri);

unlink(__DIR__.'/Fixtures/cache/routes-v7.php');
}

public function testCompiledAndNonCompiledUrlResolutionHasSamePrecedenceForNames()
{
$this->router->get('/foo/{bar}', ['FooController', 'show'])->name('foo.show');
$this->router->get('/foo/{bar}/{baz}', ['FooController', 'show'])->name('foo.show');
$this->router->getRoutes()->refreshNameLookups();

$this->assertSame('foo/{bar}', $this->router->getRoutes()->getByName('foo.show')->uri);
}

public function testRouteCollectionCanGetIterator()
{
$this->routeCollection->add($this->newRoute('GET', 'foo/index', [
Expand Down
18 changes: 18 additions & 0 deletions tests/Integration/Routing/Fixtures/app.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace Illuminate\Tests\Integration\Routing\Fixtures;

use Illuminate\Foundation\Application;

if (! class_exists(AppCache::class)) {
class AppCache
{
public static $app;
}
}

if (isset($refresh)) {
return AppCache::$app = Application::configure(basePath: __DIR__)->create();
} else {
return AppCache::$app ??= Application::configure(basePath: __DIR__)->create();
}
Comment on lines +1 to +18
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a little weird; I know.

When routes are cached, a new application instance is resolved.

This file allows us to capture the app instance created to add routes to it.

2 changes: 2 additions & 0 deletions tests/Integration/Routing/Fixtures/bootstrap/cache/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*
!.gitignore
2 changes: 2 additions & 0 deletions tests/Integration/Routing/Fixtures/cache/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*
!.gitignore
7 changes: 7 additions & 0 deletions tests/Routing/RouteRegistrarTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,8 @@ public function testCanSetShallowOptionOnRegisteredResource()
public function testCanSetScopedOptionOnRegisteredResource()
{
$this->router->resource('users.tasks', RouteRegistrarControllerStub::class)->scoped();
$this->router->getRoutes()->refreshNameLookups();

$this->assertSame(
['user' => null],
$this->router->getRoutes()->getByName('users.tasks.index')->bindingFields()
Expand All @@ -731,6 +733,7 @@ public function testCanSetScopedOptionOnRegisteredResource()
$this->router->resource('users.tasks', RouteRegistrarControllerStub::class)->scoped([
'task' => 'slug',
]);
$this->router->getRoutes()->refreshNameLookups();
$this->assertSame(
['user' => null],
$this->router->getRoutes()->getByName('users.tasks.index')->bindingFields()
Expand Down Expand Up @@ -904,6 +907,7 @@ public function testCanSetMiddlewareForSpecifiedMethodsOnRegisteredResource()
->middlewareFor('index', RouteRegistrarMiddlewareStub::class)
->middlewareFor(['create', 'store'], 'one')
->middlewareFor(['edit'], ['one', 'two']);
$this->router->getRoutes()->refreshNameLookups();

$this->assertEquals($this->router->getRoutes()->getByName('users.index')->gatherMiddleware(), ['default', RouteRegistrarMiddlewareStub::class]);
$this->assertEquals($this->router->getRoutes()->getByName('users.create')->gatherMiddleware(), ['default', 'one']);
Expand All @@ -918,6 +922,7 @@ public function testCanSetMiddlewareForSpecifiedMethodsOnRegisteredResource()
->middlewareFor(['create', 'store'], 'one')
->middlewareFor(['edit'], ['one', 'two'])
->middleware('default');
$this->router->getRoutes()->refreshNameLookups();

$this->assertEquals($this->router->getRoutes()->getByName('users.index')->gatherMiddleware(), [RouteRegistrarMiddlewareStub::class, 'default']);
$this->assertEquals($this->router->getRoutes()->getByName('users.create')->gatherMiddleware(), ['one', 'default']);
Expand Down Expand Up @@ -1448,6 +1453,7 @@ public function testCanSetMiddlewareForSpecifiedMethodsOnRegisteredSingletonReso
->middlewareFor('show', RouteRegistrarMiddlewareStub::class)
->middlewareFor(['create', 'store'], 'one')
->middlewareFor(['edit'], ['one', 'two']);
$this->router->getRoutes()->refreshNameLookups();

$this->assertEquals($this->router->getRoutes()->getByName('users.create')->gatherMiddleware(), ['default', 'one']);
$this->assertEquals($this->router->getRoutes()->getByName('users.store')->gatherMiddleware(), ['default', 'one']);
Expand All @@ -1463,6 +1469,7 @@ public function testCanSetMiddlewareForSpecifiedMethodsOnRegisteredSingletonReso
->middlewareFor(['create', 'store'], 'one')
->middlewareFor(['edit'], ['one', 'two'])
->middleware('default');
$this->router->getRoutes()->refreshNameLookups();

$this->assertEquals($this->router->getRoutes()->getByName('users.create')->gatherMiddleware(), ['one', 'default']);
$this->assertEquals($this->router->getRoutes()->getByName('users.store')->gatherMiddleware(), ['one', 'default']);
Expand Down