From bfdc308d6ead83946bc245c962de416e105701f8 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 10 Jul 2023 15:27:29 -0500 Subject: [PATCH] set route parameters --- src/FolioManager.php | 2 +- src/Pipeline/TransformModelBindings.php | 14 +++++++++++ src/RequestHandler.php | 2 +- src/Router.php | 11 +++++---- tests/Feature/RoutingTest.php | 31 +++++++++++++------------ tests/Unit/ModelBindingTest.php | 27 ++++++++++----------- 6 files changed, 52 insertions(+), 35 deletions(-) diff --git a/src/FolioManager.php b/src/FolioManager.php index f6f4cc4..2033c32 100644 --- a/src/FolioManager.php +++ b/src/FolioManager.php @@ -76,7 +76,7 @@ protected function handler(MountPath $mountPath): Closure public function middlewareFor(string $uri): array { foreach ($this->mountPaths as $mountPath) { - if (! $matchedView = (new Router($mountPath->path))->match($uri)) { + if (! $matchedView = (new Router($mountPath->path))->match(new Request, $uri)) { continue; } diff --git a/src/Pipeline/TransformModelBindings.php b/src/Pipeline/TransformModelBindings.php index cec95a7..4937630 100644 --- a/src/Pipeline/TransformModelBindings.php +++ b/src/Pipeline/TransformModelBindings.php @@ -3,10 +3,18 @@ namespace Laravel\Folio\Pipeline; use Closure; +use Illuminate\Http\Request; use Illuminate\Support\Str; class TransformModelBindings { + /** + * Create a new pipeline step instance. + */ + public function __construct(protected Request $request) + { + } + /** * Invoke the routing pipeline handler. */ @@ -57,6 +65,12 @@ public function __invoke(State $state, Closure $next): mixed $parent = $resolved; } + if ($this->request->route()) { + foreach ($view->data as $key => $value) { + $this->request->route()->setParameter($key, $value); + } + } + return $view; } diff --git a/src/RequestHandler.php b/src/RequestHandler.php index 67f7061..7fae357 100644 --- a/src/RequestHandler.php +++ b/src/RequestHandler.php @@ -28,7 +28,7 @@ public function __invoke(Request $request, string $uri): mixed { $matchedView = (new Router( $this->mountPath->path - ))->match($uri) ?? abort(404); + ))->match($request, $uri) ?? abort(404); return (new Pipeline(app())) ->send($request) diff --git a/src/Router.php b/src/Router.php index 471553d..ff54b50 100644 --- a/src/Router.php +++ b/src/Router.php @@ -2,18 +2,19 @@ namespace Laravel\Folio; +use Illuminate\Http\Request; use Illuminate\Pipeline\Pipeline; use Illuminate\Support\Arr; use Laravel\Folio\Pipeline\ContinueIterating; use Laravel\Folio\Pipeline\EnsureNoDirectoryTraversal; use Laravel\Folio\Pipeline\MatchDirectoryIndexViews; -use Laravel\Folio\Pipeline\MatchedView; use Laravel\Folio\Pipeline\MatchLiteralDirectories; use Laravel\Folio\Pipeline\MatchLiteralViews; use Laravel\Folio\Pipeline\MatchRootIndex; use Laravel\Folio\Pipeline\MatchWildcardDirectories; use Laravel\Folio\Pipeline\MatchWildcardViews; use Laravel\Folio\Pipeline\MatchWildcardViewsThatCaptureMultipleSegments; +use Laravel\Folio\Pipeline\MatchedView; use Laravel\Folio\Pipeline\SetMountPathOnMatchedView; use Laravel\Folio\Pipeline\State; use Laravel\Folio\Pipeline\StopIterating; @@ -37,12 +38,12 @@ public function __construct(array|string $mountPaths) /** * Match the given URI to a view via page based routing. */ - public function match(string $uri): ?MatchedView + public function match(Request $request, string $uri): ?MatchedView { $uri = strlen($uri) > 1 ? trim($uri, '/') : $uri; foreach ($this->mountPaths as $mountPath) { - if ($view = $this->matchAtPath($mountPath, $uri)) { + if ($view = $this->matchAtPath($mountPath, $request, $uri)) { return $view; } } @@ -53,7 +54,7 @@ public function match(string $uri): ?MatchedView /** * Resolve the given URI via page based routing at the given mount path. */ - protected function matchAtPath(string $mountPath, string $uri): ?MatchedView + protected function matchAtPath(string $mountPath, Request $request, string $uri): ?MatchedView { $state = new State( uri: $uri, @@ -66,7 +67,7 @@ protected function matchAtPath(string $mountPath, string $uri): ?MatchedView ->send($state->forIteration($i)) ->through([ new EnsureNoDirectoryTraversal, - new TransformModelBindings, + new TransformModelBindings($request), new SetMountPathOnMatchedView, // ... new MatchRootIndex, diff --git a/tests/Feature/RoutingTest.php b/tests/Feature/RoutingTest.php index 2827dfc..69dbd3e 100644 --- a/tests/Feature/RoutingTest.php +++ b/tests/Feature/RoutingTest.php @@ -1,6 +1,7 @@ router(); - expect(realpath(__DIR__.'/../tmp/views/index.blade.php'))->toEqual($router->match('/')->path) - ->and($router->match('/missing-view'))->toBeNull(); + expect(realpath(__DIR__.'/../tmp/views/index.blade.php'))->toEqual($router->match(new Request, '/')->path) + ->and($router->match(new Request, '/missing-view'))->toBeNull(); }); test('directory index views can be matched', function () { @@ -32,7 +33,7 @@ $router = $this->router(); - expect(realpath(__DIR__.'/../tmp/views/users/index.blade.php'))->toEqual($router->match('/users')->path); + expect(realpath(__DIR__.'/../tmp/views/users/index.blade.php'))->toEqual($router->match(new Request, '/users')->path); }); test('literal views can be matched', function () { @@ -43,7 +44,7 @@ $router = $this->router(); - expect(realpath(__DIR__.'/../tmp/views/profile.blade.php'))->toEqual($router->match('/profile')->path); + expect(realpath(__DIR__.'/../tmp/views/profile.blade.php'))->toEqual($router->match(new Request, '/profile')->path); }); test('wildcard views can be matched', function () { @@ -54,7 +55,7 @@ $router = $this->router(); - $resolved = $router->match('/1'); + $resolved = $router->match(new Request, '/1'); expect(realpath(__DIR__.'/../tmp/views/[id].blade.php'))->toEqual($resolved->path) ->and($resolved->data)->toEqual(['id' => 1]); @@ -69,11 +70,11 @@ $router = $this->router(); - $resolved = $router->match('/profile'); + $resolved = $router->match(new Request, '/profile'); expect(realpath(__DIR__.'/../tmp/views/profile.blade.php'))->toEqual($resolved->path) ->and($resolved->data)->toEqual([]) - ->and($router->match('/profile/missing-view'))->toBeNull(); + ->and($router->match(new Request, '/profile/missing-view'))->toBeNull(); }); test('literal views may be in directories', function () { @@ -85,7 +86,7 @@ $router = $this->router(); - expect(realpath(__DIR__.'/../tmp/views/users/profile.blade.php'))->toEqual($router->match('/users/profile')->path); + expect(realpath(__DIR__.'/../tmp/views/users/profile.blade.php'))->toEqual($router->match(new Request, '/users/profile')->path); }); test('wildcard views may be in directories', function () { @@ -97,7 +98,7 @@ $router = $this->router(); - $resolved = $router->match('/users/1'); + $resolved = $router->match(new Request, '/users/1'); expect(realpath(__DIR__.'/../tmp/views/users/[id].blade.php'))->toEqual($resolved->path); @@ -113,7 +114,7 @@ $router = $this->router(); - expect($router->match('/users/1'))->toBeNull(); + expect($router->match(new Request, '/users/1'))->toBeNull(); }); test('multisegment wildcard views can be matched', function () { @@ -123,7 +124,7 @@ $router = $this->router(); - $resolved = $router->match('/1/2/3'); + $resolved = $router->match(new Request, '/1/2/3'); expect(realpath(__DIR__.'/../tmp/views/[...id].blade.php'))->toEqual($resolved->path); @@ -140,7 +141,7 @@ $router = $this->router(); - $resolved = $router->match('/1/2/3'); + $resolved = $router->match(new Request, '/1/2/3'); expect(realpath(__DIR__.'/../tmp/views/[...id].blade.php'))->toEqual($resolved->path); @@ -158,7 +159,7 @@ $router = $this->router(); - $resolved = $router->match('/flights/1/connections'); + $resolved = $router->match(new Request, '/flights/1/connections'); expect(realpath(__DIR__.'/../tmp/views/flights/[id]/connections.blade.php'))->toEqual($resolved->path); @@ -180,7 +181,7 @@ $router = $this->router(); - $resolved = $router->match('/flights/1/connections/2/map'); + $resolved = $router->match(new Request, '/flights/1/connections/2/map'); expect(realpath(__DIR__.'/../tmp/views/flights/[id]/connections/[connectionId]/map.blade.php'))->toEqual($resolved->path) ->and($resolved->data)->toEqual(['id' => 1, 'connectionId' => 2]); @@ -189,5 +190,5 @@ it('ensures directory traversal is not possible', function () { $router = $this->router(); - $router->match('/../'); + $router->match(new Request, '/../'); })->throws(PossibleDirectoryTraversal::class); diff --git a/tests/Unit/ModelBindingTest.php b/tests/Unit/ModelBindingTest.php index fec1c02..2df6635 100644 --- a/tests/Unit/ModelBindingTest.php +++ b/tests/Unit/ModelBindingTest.php @@ -3,6 +3,7 @@ use Illuminate\Contracts\Routing\UrlRoutable; use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Filesystem\Filesystem; +use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; $purgeDirectories = function () { @@ -24,7 +25,7 @@ $router = $this->router(); - $view = $router->match('/users/1'); + $view = $router->match(new Request, '/users/1'); $this->assertTrue( $view->data['folioModelBindingTestClass'] instanceof FolioModelBindingTestClass @@ -43,7 +44,7 @@ $router = $this->router(); - $router->match('/users/_missing'); + $router->match(new Request, '/users/_missing'); })->throws(ModelNotFoundException::class); test('implicit model bindings with more than one binding in path', function () { @@ -60,7 +61,7 @@ $router = $this->router(); - $view = $router->match('/users/1/posts/2'); + $view = $router->match(new Request, '/users/1/posts/2'); $this->assertTrue( $view->data['first'] instanceof FolioModelBindingTestClass @@ -87,7 +88,7 @@ $router = $this->router(); - $view = $router->match('/users/1'); + $view = $router->match(new Request, '/users/1'); $this->assertEquals( 'slug', @@ -107,7 +108,7 @@ $router = $this->router(); - $view = $router->match('/users/1'); + $view = $router->match(new Request, '/users/1'); $this->assertEquals( '1', @@ -130,7 +131,7 @@ $router = $this->router(); - $view = $router->match('/users/1'); + $view = $router->match(new Request, '/users/1'); $this->assertEquals( $field, @@ -157,7 +158,7 @@ $router = $this->router(); - $view = $router->match('/users/abc'); + $view = $router->match(new Request, '/users/abc'); $this->assertEquals( 'ABC', @@ -175,7 +176,7 @@ $router = $this->router(); - $view = $router->match('/users/1/2/3'); + $view = $router->match(new Request, '/users/1/2/3'); $this->assertTrue(is_array($view->data['folioModelBindingTestClasses'])); $this->assertEquals('1', $view->data['folioModelBindingTestClasses'][0]->value); @@ -195,7 +196,7 @@ $router = $this->router(); - $view = $router->match('/users/1/2/3'); + $view = $router->match(new Request, '/users/1/2/3'); $this->assertTrue(is_array($view->data[$variable])); @@ -225,7 +226,7 @@ $router = $this->router(); - $view = $router->match('/users/1/posts/2'); + $view = $router->match(new Request, '/users/1/posts/2'); $this->assertEquals('1', $view->data['first']->value); @@ -259,7 +260,7 @@ $router = $this->router(); - $view = $router->match('/users/abc/posts/def'); + $view = $router->match(new Request, '/users/abc/posts/def'); $this->assertEquals('ABC', $view->data['first']->value); $this->assertEquals('DEF', $view->data['second']->value); @@ -281,7 +282,7 @@ $router = $this->router(); - $router->match('/users/1/posts/_missing'); + $router->match(new Request, '/users/1/posts/_missing'); })->throws(ModelNotFoundException::class); test('model bindings can be enums', function () { @@ -293,7 +294,7 @@ $router = $this->router(); - $view = $router->match('/categories/posts'); + $view = $router->match(new Request, '/categories/posts'); $this->assertEquals('posts', $view->data['category']->value);