diff --git a/src/Inertia.php b/src/Inertia.php index a967ed8f..b2afeda9 100644 --- a/src/Inertia.php +++ b/src/Inertia.php @@ -6,6 +6,7 @@ /** * @method static void setRootView(string $name) + * @method static void setUrlResolver(?callable $urlResolver) * @method static void share(string|array|\Illuminate\Contracts\Support\Arrayable $key, mixed $value = null) * @method static mixed getShared(string|null $key = null, mixed $default = null) * @method static void flushShared() diff --git a/src/Middleware.php b/src/Middleware.php index e6dd334d..49c9cde2 100644 --- a/src/Middleware.php +++ b/src/Middleware.php @@ -70,6 +70,16 @@ public function rootView(Request $request) return $this->rootView; } + /** + * Sets the url resolver that is used to resolve the current url in the response. + * + * @return callable(Request):string|null + */ + public function urlResolver(Request $request): ?callable + { + return null; + } + /** * Handle the incoming request. * @@ -83,6 +93,7 @@ public function handle(Request $request, Closure $next) Inertia::share($this->share($request)); Inertia::setRootView($this->rootView($request)); + Inertia::setUrlResolver($this->urlResolver($request)); $response = $next($request); $response->headers->set('Vary', 'X-Inertia'); diff --git a/src/Response.php b/src/Response.php index 953a8e52..ffafd2b4 100644 --- a/src/Response.php +++ b/src/Response.php @@ -24,16 +24,18 @@ class Response implements Responsable protected $rootView; protected $version; protected $viewData = []; + protected $urlResolver; /** * @param array|Arrayable $props */ - public function __construct(string $component, $props, string $rootView = 'app', string $version = '') + public function __construct(string $component, $props, string $rootView = 'app', string $version = '', ?callable $urlResolver = null) { $this->component = $component; $this->props = $props instanceof Arrayable ? $props->toArray() : $props; $this->rootView = $rootView; $this->version = $version; + $this->urlResolver = $urlResolver; } /** @@ -96,10 +98,14 @@ public function toResponse($request) $props = $this->resolvePropertyInstances($props, $request); + $url = $this->urlResolver + ? ($this->urlResolver)($request) + : $request->getBaseUrl() . $request->getRequestUri(); + $page = [ 'component' => $this->component, 'props' => $props, - 'url' => $request->getBaseUrl().$request->getRequestUri(), + 'url' => $url, 'version' => $this->version, ]; diff --git a/src/ResponseFactory.php b/src/ResponseFactory.php index a7632572..81aef281 100644 --- a/src/ResponseFactory.php +++ b/src/ResponseFactory.php @@ -20,6 +20,9 @@ class ResponseFactory /** @var string */ protected $rootView = 'app'; + /** @var callable(\Illuminate\Http\Request):string|null */ + protected $urlResolver = null; + /** @var array */ protected $sharedProps = []; @@ -31,6 +34,14 @@ public function setRootView(string $name): void $this->rootView = $name; } + /** + * @param callable(\Illuminate\Http\Request):string|null $urlResolver + */ + public function setUrlResolver(?callable $urlResolver): void + { + $this->urlResolver = $urlResolver; + } + /** * @param string|array|Arrayable $key * @param mixed $value @@ -100,7 +111,8 @@ public function render(string $component, $props = []): Response $component, array_merge($this->sharedProps, $props), $this->rootView, - $this->getVersion() + $this->getVersion(), + $this->urlResolver ); } diff --git a/tests/MiddlewareTest.php b/tests/MiddlewareTest.php index 027cd93d..d077295d 100644 --- a/tests/MiddlewareTest.php +++ b/tests/MiddlewareTest.php @@ -239,6 +239,31 @@ public function rootView(Request $request): string $response->assertViewIs('welcome'); } + public function test_middleware_can_change_the_url_resolver_by_overriding_the_urlresolver_method(): void + { + $this->prepareMockEndpoint(null, [], new class() extends Middleware { + public function version(Request $request) + { + return ''; + } + + public function urlResolver(Request $request): ?callable + { + return function (Request $request) { + return 'https://inertiajs.com'.$request->getRequestUri(); + }; + } + }); + + $response = $this->get('/', [ + 'X-Inertia' => 'true', + ]); + $response->assertOk(); + $response->assertJson([ + 'url' => 'https://inertiajs.com/', + ]); + } + private function prepareMockEndpoint($version = null, $shared = [], $middleware = null): \Illuminate\Routing\Route { if (is_null($middleware)) { diff --git a/tests/ResponseFactoryTest.php b/tests/ResponseFactoryTest.php index 482c64fe..97bd96a5 100644 --- a/tests/ResponseFactoryTest.php +++ b/tests/ResponseFactoryTest.php @@ -160,7 +160,7 @@ public function test_can_create_lazy_prop(): void $this->assertInstanceOf(LazyProp::class, $lazyProp); } - public function test_will_accept_arrayabe_props() + public function test_will_accept_arrayabe_props(): void { Route::middleware([StartSession::class, ExampleMiddleware::class])->get('/', function () { Inertia::share('foo', 'bar'); @@ -184,4 +184,22 @@ public function toArray() ], ]); } + + public function test_the_url_resolver_is_used_when_constructing_a_response(): void + { + Route::middleware([StartSession::class, ExampleMiddleware::class])->get('/', function () { + Inertia::setUrlResolver(function (\Illuminate\Http\Request $request) { + return 'https://inertiajs.com'.$request->getRequestUri(); + }); + + return Inertia::render('User/Edit'); + }); + + $response = $this->withoutExceptionHandling()->get('/', [ + 'X-Inertia' => 'true', + ]); + + $response->assertSuccessful(); + $response->assertJson(['url' => 'https://inertiajs.com/']); + } } diff --git a/tests/ResponseTest.php b/tests/ResponseTest.php index 456e7707..706a53c6 100644 --- a/tests/ResponseTest.php +++ b/tests/ResponseTest.php @@ -361,4 +361,21 @@ public function test_responsable_with_invalid_key(): void $page['props']['resource'] ); } + + public function test_url_resolver(): void + { + $request = Request::create('/user/123', 'GET'); + $request->headers->add(['X-Inertia' => 'true']); + + $urlResolver = function (Request $request) { + return 'https://inertiajs.com'.$request->getRequestUri(); + }; + + $user = ['name' => 'Jonathan']; + $response = new Response('User/Edit', ['user' => $user], 'app', '123', $urlResolver); + $response = $response->toResponse($request); + $page = $response->getData(); + + $this->assertSame('https://inertiajs.com/user/123', $page->url); + } }