diff --git a/src/Inertia.php b/src/Inertia.php index 104f03ac..1d0adb38 100644 --- a/src/Inertia.php +++ b/src/Inertia.php @@ -13,6 +13,7 @@ * @method static void flushShared() * @method static void version(\Closure|string|null $version) * @method static string getVersion() + * @method static void resolveUrlUsing(\Closure|null $urlResolver = null) * @method static \Inertia\OptionalProp optional(callable $callback) * @method static \Inertia\LazyProp lazy(callable $callback) * @method static \Inertia\DeferProp defer(callable $callback, string $group = 'default') diff --git a/src/Middleware.php b/src/Middleware.php index ba4d9a34..0ad48add 100644 --- a/src/Middleware.php +++ b/src/Middleware.php @@ -69,6 +69,16 @@ public function rootView(Request $request) return $this->rootView; } + /** + * Defines a callback that returns the relative URL. + * + * @return Closure|null + */ + public function urlResolver() + { + return null; + } + /** * Handle the incoming request. * @@ -83,6 +93,10 @@ public function handle(Request $request, Closure $next) Inertia::share($this->share($request)); Inertia::setRootView($this->rootView($request)); + if ($urlResolver = $this->urlResolver()) { + Inertia::resolveUrlUsing($urlResolver); + } + $response = $next($request); $response->headers->set('Vary', Header::INERTIA); diff --git a/src/Response.php b/src/Response.php index 578698af..7df05252 100644 --- a/src/Response.php +++ b/src/Response.php @@ -36,17 +36,26 @@ class Response implements Responsable protected $cacheFor = []; + protected ?Closure $urlResolver = null; + /** * @param array|Arrayable $props */ - public function __construct(string $component, array $props, string $rootView = 'app', string $version = '', bool $encryptHistory = false) - { + public function __construct( + string $component, + array $props, + string $rootView = 'app', + string $version = '', + bool $encryptHistory = false, + ?Closure $urlResolver = null + ) { $this->component = $component; $this->props = $props instanceof Arrayable ? $props->toArray() : $props; $this->rootView = $rootView; $this->version = $version; $this->clearHistory = session()->pull('inertia.clear_history', false); $this->encryptHistory = $encryptHistory; + $this->urlResolver = $urlResolver; } /** @@ -365,11 +374,15 @@ public function isPartial(Request $request): bool */ protected function getUrl(Request $request): string { - $url = Str::start(Str::after($request->fullUrl(), $request->getSchemeAndHttpHost()), '/'); + $urlResolver = $this->urlResolver ?? function (Request $request) { + $url = Str::start(Str::after($request->fullUrl(), $request->getSchemeAndHttpHost()), '/'); + + $rawUri = Str::before($request->getRequestUri(), '?'); - $rawUri = Str::before($request->getRequestUri(), '?'); + return Str::endsWith($rawUri, '/') ? $this->finishUrlWithTrailingSlash($url) : $url; + }; - return Str::endsWith($rawUri, '/') ? $this->finishUrlWithTrailingSlash($url) : $url; + return App::call($urlResolver, ['request' => $request]); } /** diff --git a/src/ResponseFactory.php b/src/ResponseFactory.php index 74fd4e8b..31a8c335 100644 --- a/src/ResponseFactory.php +++ b/src/ResponseFactory.php @@ -31,6 +31,9 @@ class ResponseFactory protected $encryptHistory; + /** @var Closure|null */ + protected $urlResolver; + /*** * @param string $name The name of the root view * @return void @@ -93,6 +96,11 @@ public function getVersion(): string return (string) $version; } + public function resolveUrlUsing(?Closure $urlResolver = null): void + { + $this->urlResolver = $urlResolver; + } + public function clearHistory(): void { session(['inertia.clear_history' => true]); @@ -163,6 +171,7 @@ public function render(string $component, $props = []): Response $this->rootView, $this->getVersion(), $this->encryptHistory ?? config('inertia.history.encrypt', false), + $this->urlResolver, ); } diff --git a/tests/MiddlewareTest.php b/tests/MiddlewareTest.php index c00bf7b1..1aa89189 100644 --- a/tests/MiddlewareTest.php +++ b/tests/MiddlewareTest.php @@ -11,6 +11,7 @@ use Inertia\AlwaysProp; use Inertia\Inertia; use Inertia\Middleware; +use Inertia\Tests\Stubs\CustomUrlResolverMiddleware; use Inertia\Tests\Stubs\ExampleMiddleware; use LogicException; @@ -122,6 +123,21 @@ public function test_it_will_instruct_inertia_to_reload_on_a_version_mismatch(): self::assertEmpty($response->getContent()); } + public function test_the_url_can_be_resolved_with_a_custom_resolver() + { + $this->prepareMockEndpoint(middleware: new CustomUrlResolverMiddleware); + + $response = $this->withoutExceptionHandling()->get('/', [ + 'X-Inertia' => 'true', + ]); + + $response->assertSuccessful(); + $response->assertJson([ + 'component' => 'User/Edit', + 'url' => '/my-custom-url', + ]); + } + public function test_validation_errors_are_registered_as_of_default(): void { Route::middleware([StartSession::class, ExampleMiddleware::class])->get('/', function () { diff --git a/tests/ResponseFactoryTest.php b/tests/ResponseFactoryTest.php index 65e7df46..c2af15ad 100644 --- a/tests/ResponseFactoryTest.php +++ b/tests/ResponseFactoryTest.php @@ -127,6 +127,30 @@ public function test_the_version_can_be_a_closure(): void $response->assertJson(['component' => 'User/Edit']); } + public function test_the_url_can_be_resolved_with_a_custom_resolver() + { + Route::middleware([StartSession::class, ExampleMiddleware::class])->get('/', function () { + Inertia::resolveUrlUsing(function ($request, ResponseFactory $otherDependency) { + $this->assertInstanceOf(HttpRequest::class, $request); + $this->assertInstanceOf(ResponseFactory::class, $otherDependency); + + return '/my-custom-url'; + }); + + return Inertia::render('User/Edit'); + }); + + $response = $this->withoutExceptionHandling()->get('/', [ + 'X-Inertia' => 'true', + ]); + + $response->assertSuccessful(); + $response->assertJson([ + 'component' => 'User/Edit', + 'url' => '/my-custom-url', + ]); + } + public function test_shared_data_can_be_shared_from_anywhere(): void { Route::middleware([StartSession::class, ExampleMiddleware::class])->get('/', function () { diff --git a/tests/Stubs/CustomUrlResolverMiddleware.php b/tests/Stubs/CustomUrlResolverMiddleware.php new file mode 100644 index 00000000..f690b57b --- /dev/null +++ b/tests/Stubs/CustomUrlResolverMiddleware.php @@ -0,0 +1,21 @@ +