diff --git a/src/Middleware.php b/src/Middleware.php index dc8ec23e..7b821fd9 100644 --- a/src/Middleware.php +++ b/src/Middleware.php @@ -4,6 +4,7 @@ use Closure; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Redirect; use Symfony\Component\HttpFoundation\Response; class Middleware @@ -82,57 +83,57 @@ public function handle(Request $request, Closure $next) }); Inertia::share($this->share($request)); - Inertia::setRootView($this->rootView($request)); $response = $next($request); - $response = $this->checkVersion($request, $response); - return $this->changeRedirectCode($request, $response); + if (! $request->header('X-Inertia')) { + return $response; + } + + if ($request->method() === 'GET' && $request->header('X-Inertia-Version', '') !== Inertia::getVersion()) { + $response = $this->onVersionChange($request, $response); + } + + if ($response->isOk() && empty($response->getContent())) { + $response = $this->onEmptyResponse($request, $response); + } + + if ($response->getStatusCode() === 302 && in_array($request->method(), ['PUT', 'PATCH', 'DELETE'])) { + $response->setStatusCode(303); + } + + return $response; } /** - * In the event that the assets change, initiate a - * client-side location visit to force an update. + * Determines what to do when an Inertia action returned with no response. + * By default, we'll redirect the user back to where they came from. * * @param Request $request * @param Response $response * @return Response */ - public function checkVersion(Request $request, Response $response) + public function onEmptyResponse(Request $request, Response $response): Response { - if ($request->header('X-Inertia') && - $request->method() === 'GET' && - $request->header('X-Inertia-Version', '') !== Inertia::getVersion() - ) { - if ($request->hasSession()) { - $request->session()->reflash(); - } - - return Inertia::location($request->fullUrl()); - } - - return $response; + return Redirect::back(); } /** - * Changes the status code during redirects, ensuring they are made as - * GET requests, preventing "MethodNotAllowedHttpException" errors. + * Determines what to do when the Inertia asset version has changed. + * By default, we'll initiate a client-side location visit to force an update. * * @param Request $request * @param Response $response * @return Response */ - public function changeRedirectCode(Request $request, Response $response) + public function onVersionChange(Request $request, Response $response): Response { - if ($request->header('X-Inertia') && - $response->getStatusCode() === 302 && - in_array($request->method(), ['PUT', 'PATCH', 'DELETE']) - ) { - $response->setStatusCode(303); + if ($request->hasSession()) { + $request->session()->reflash(); } - return $response; + return Inertia::location($request->fullUrl()); } /** @@ -142,7 +143,7 @@ public function changeRedirectCode(Request $request, Response $response) * @param Request $request * @return object */ - public function resolveValidationErrors(Request $request) + protected function resolveValidationErrors(Request $request) { if (! $request->session()->has('errors')) { return (object) []; diff --git a/stubs/middleware.stub b/stubs/middleware.stub index 3d656586..8cac58af 100644 --- a/stubs/middleware.stub +++ b/stubs/middleware.stub @@ -40,4 +40,17 @@ class {{ class }} extends Middleware // ]); } + + /** + * Determines what to do when an Inertia action returned with no response. + * By default, we'll redirect the user back to where they came from. + * + * @param Request $request + * @param Response $response + * @return Response + */ + public function onEmptyResponse(Request $request, Response $response): Response + { + return parent::onEmptyResponse($request, $response); + } } diff --git a/tests/MiddlewareTest.php b/tests/MiddlewareTest.php index 8f62dad8..abfde5d4 100644 --- a/tests/MiddlewareTest.php +++ b/tests/MiddlewareTest.php @@ -14,6 +14,60 @@ class MiddlewareTest extends TestCase { + public function test_no_response_value_by_default_means_automatically_redirecting_back_for_inertia_requests(): void + { + $fooCalled = false; + Route::middleware(Middleware::class)->put('/', function () use (&$fooCalled) { + $fooCalled = true; + }); + + $response = $this + ->from('/foo') + ->put('/', [], [ + 'X-Inertia' => 'true', + 'Content-Type' => 'application/json', + ]); + + $response->assertRedirect('/foo'); + $response->assertStatus(303); + $this->assertTrue($fooCalled); + } + + public function test_no_response_value_can_be_customized_by_overriding_the_middleware_method(): void + { + Route::middleware(ExampleMiddleware::class)->get('/', function () { + // Do nothing.. + }); + + $this->expectException(\LogicException::class); + $this->expectExceptionMessage('An empty Inertia response was returned.'); + + $this + ->withoutExceptionHandling() + ->from('/foo') + ->get('/', [ + 'X-Inertia' => 'true', + 'Content-Type' => 'application/json', + ]); + } + + public function test_no_response_means_no_response_for_non_inertia_requests(): void + { + $fooCalled = false; + Route::middleware(Middleware::class)->put('/', function () use (&$fooCalled) { + $fooCalled = true; + }); + + $response = $this + ->from('/foo') + ->put('/', [], [ + 'Content-Type' => 'application/json', + ]); + + $response->assertNoContent(200); + $this->assertTrue($fooCalled); + } + public function test_the_version_is_optional(): void { $this->prepareMockEndpoint(); diff --git a/tests/Stubs/ExampleMiddleware.php b/tests/Stubs/ExampleMiddleware.php index 05db3a43..fb9db76f 100644 --- a/tests/Stubs/ExampleMiddleware.php +++ b/tests/Stubs/ExampleMiddleware.php @@ -4,6 +4,7 @@ use Illuminate\Http\Request; use Inertia\Middleware; +use Symfony\Component\HttpFoundation\Response; class ExampleMiddleware extends Middleware { @@ -48,4 +49,17 @@ public function share(Request $request): array { return array_merge(parent::share($request), $this->shared); } + + /** + * Determines what to do when an Inertia action returned with no response. + * By default, we'll redirect the user back to where they came from. + * + * @param Request $request + * @param Response $response + * @return Response + */ + public function onEmptyResponse(Request $request, Response $response): Response + { + throw new \LogicException('An empty Inertia response was returned.'); + } }