Skip to content

Commit 8df7de3

Browse files
timacdonaldtegos
authored andcommitted
Ensure cached and uncached routes share same precedence when resolving actions and names (laravel#56920)
* Ensure cached and uncached routes share same precedence * formatting * Formatting * formatting * Fix tests
1 parent 98b527a commit 8df7de3

File tree

6 files changed

+88
-5
lines changed

6 files changed

+88
-5
lines changed

src/Illuminate/Routing/RouteCollection.php

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ protected function addLookups($route)
9191
// If the route has a name, we will add it to the name look-up table, so that we
9292
// will quickly be able to find the route associated with a name and not have
9393
// to iterate through every route every time we need to find a named route.
94-
if ($name = $route->getName()) {
94+
if (($name = $route->getName()) && ! $this->inNameLookup($name)) {
9595
$this->nameList[$name] = $route;
9696
}
9797

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

103-
if (isset($action['controller'])) {
103+
if (($controller = $action['controller'] ?? null) && ! $this->inActionLookup($controller)) {
104104
$this->addToActionList($action, $route);
105105
}
106106
}
@@ -117,6 +117,28 @@ protected function addToActionList($action, $route)
117117
$this->actionList[trim($action['controller'], '\\')] = $route;
118118
}
119119

120+
/**
121+
* Determine if the given controller is in the action lookup table.
122+
*
123+
* @param string $controller
124+
* @return bool
125+
*/
126+
protected function inActionLookup($controller)
127+
{
128+
return array_key_exists($controller, $this->actionList);
129+
}
130+
131+
/**
132+
* Determine if the given name is in the name lookup table.
133+
*
134+
* @param string $name
135+
* @return bool
136+
*/
137+
protected function inNameLookup($name)
138+
{
139+
return array_key_exists($name, $this->nameList);
140+
}
141+
120142
/**
121143
* Refresh the name look-up table.
122144
*
@@ -129,8 +151,8 @@ public function refreshNameLookups()
129151
$this->nameList = [];
130152

131153
foreach ($this->allRoutes as $route) {
132-
if ($route->getName()) {
133-
$this->nameList[$route->getName()] = $route;
154+
if (($name = $route->getName()) && ! $this->inNameLookup($name)) {
155+
$this->nameList[$name] = $route;
134156
}
135157
}
136158
}
@@ -147,7 +169,7 @@ public function refreshActionLookups()
147169
$this->actionList = [];
148170

149171
foreach ($this->allRoutes as $route) {
150-
if (isset($route->getAction()['controller'])) {
172+
if (($controller = $route->getAction()['controller'] ?? null) && ! $this->inActionLookup($controller)) {
151173
$this->addToActionList($route->getAction(), $route);
152174
}
153175
}

tests/Integration/Routing/CompiledRouteCollectionTest.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,38 @@ public function testRouteCollectionCanRetrieveByAction()
9494
$this->assertSame($action, Arr::except($route->getAction(), 'as'));
9595
}
9696

97+
public function testCompiledAndNonCompiledUrlResolutionHasSamePrecedenceForActions()
98+
{
99+
@unlink(__DIR__.'/Fixtures/cache/routes-v7.php');
100+
$this->app->useBootstrapPath(__DIR__.'/Fixtures');
101+
$app = (static function () {
102+
$refresh = true;
103+
104+
return require __DIR__.'/Fixtures/app.php';
105+
})();
106+
$app['router']->get('/foo/{bar}', ['FooController', 'show']);
107+
$app['router']->get('/foo/{bar}/{baz}', ['FooController', 'show']);
108+
$app['router']->getRoutes()->refreshActionLookups();
109+
110+
$this->assertSame('foo/{bar}', $app['router']->getRoutes()->getByAction('FooController@show')->uri);
111+
112+
$this->artisan('route:cache')->assertExitCode(0);
113+
require __DIR__.'/Fixtures/cache/routes-v7.php';
114+
115+
$this->assertSame('foo/{bar}', $app['router']->getRoutes()->getByAction('FooController@show')->uri);
116+
117+
unlink(__DIR__.'/Fixtures/cache/routes-v7.php');
118+
}
119+
120+
public function testCompiledAndNonCompiledUrlResolutionHasSamePrecedenceForNames()
121+
{
122+
$this->router->get('/foo/{bar}', ['FooController', 'show'])->name('foo.show');
123+
$this->router->get('/foo/{bar}/{baz}', ['FooController', 'show'])->name('foo.show');
124+
$this->router->getRoutes()->refreshNameLookups();
125+
126+
$this->assertSame('foo/{bar}', $this->router->getRoutes()->getByName('foo.show')->uri);
127+
}
128+
97129
public function testRouteCollectionCanGetIterator()
98130
{
99131
$this->routeCollection->add($this->newRoute('GET', 'foo/index', [
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace Illuminate\Tests\Integration\Routing\Fixtures;
4+
5+
use Illuminate\Foundation\Application;
6+
7+
if (! class_exists(AppCache::class)) {
8+
class AppCache
9+
{
10+
public static $app;
11+
}
12+
}
13+
14+
if (isset($refresh)) {
15+
return AppCache::$app = Application::configure(basePath: __DIR__)->create();
16+
} else {
17+
return AppCache::$app ??= Application::configure(basePath: __DIR__)->create();
18+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*
2+
!.gitignore
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*
2+
!.gitignore

tests/Routing/RouteRegistrarTest.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,8 @@ public function testCanSetShallowOptionOnRegisteredResource()
719719
public function testCanSetScopedOptionOnRegisteredResource()
720720
{
721721
$this->router->resource('users.tasks', RouteRegistrarControllerStub::class)->scoped();
722+
$this->router->getRoutes()->refreshNameLookups();
723+
722724
$this->assertSame(
723725
['user' => null],
724726
$this->router->getRoutes()->getByName('users.tasks.index')->bindingFields()
@@ -731,6 +733,7 @@ public function testCanSetScopedOptionOnRegisteredResource()
731733
$this->router->resource('users.tasks', RouteRegistrarControllerStub::class)->scoped([
732734
'task' => 'slug',
733735
]);
736+
$this->router->getRoutes()->refreshNameLookups();
734737
$this->assertSame(
735738
['user' => null],
736739
$this->router->getRoutes()->getByName('users.tasks.index')->bindingFields()
@@ -904,6 +907,7 @@ public function testCanSetMiddlewareForSpecifiedMethodsOnRegisteredResource()
904907
->middlewareFor('index', RouteRegistrarMiddlewareStub::class)
905908
->middlewareFor(['create', 'store'], 'one')
906909
->middlewareFor(['edit'], ['one', 'two']);
910+
$this->router->getRoutes()->refreshNameLookups();
907911

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

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

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

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

0 commit comments

Comments
 (0)