diff --git a/Classes/Middleware/SiteBaseRedirectResolver.php b/Classes/Middleware/SiteBaseRedirectResolver.php new file mode 100644 index 00000000..a0727b7e --- /dev/null +++ b/Classes/Middleware/SiteBaseRedirectResolver.php @@ -0,0 +1,50 @@ +getAttribute('site'); + $siteConf = $site->getConfiguration(); + + if (!($siteConf['headless'] ?? false)) { + return $response; + } + + if ($response instanceof RedirectResponse) { + $urlUtility = GeneralUtility::makeInstance(UrlUtility::class)->withRequest($request); + return new JsonResponse([ + 'redirectUrl' => $urlUtility->prepareRelativeUrlIfPossible( + $urlUtility->getFrontendUrlWithSite( + $response->getHeader('location')[0] ?? '', + $site + ) + ), + 'statusCode' => $response->getStatusCode(), + ]); + } + + return $response; + } +} diff --git a/Configuration/RequestMiddlewares.php b/Configuration/RequestMiddlewares.php index f3deb9cb..e2084e54 100644 --- a/Configuration/RequestMiddlewares.php +++ b/Configuration/RequestMiddlewares.php @@ -10,6 +10,7 @@ use FriendsOfTYPO3\Headless\Middleware\ElementBodyResponseMiddleware; use FriendsOfTYPO3\Headless\Middleware\RedirectHandler; use FriendsOfTYPO3\Headless\Middleware\ShortcutAndMountPointRedirect; +use FriendsOfTYPO3\Headless\Middleware\SiteBaseRedirectResolver; use FriendsOfTYPO3\Headless\Middleware\UserIntMiddleware; use TYPO3\CMS\Core\Configuration\Features; use TYPO3\CMS\Core\Utility\GeneralUtility; @@ -31,7 +32,7 @@ if ($features->isFeatureEnabled('headless.elementBodyResponse')) { $middlewares['frontend']['headless/cms-frontend/element-body-response'] = [ 'after' => [ - 'typo3/cms-adminpanel/data-persister', + 'typo3/cms-frontend/content-length-headers', ], 'target' => ElementBodyResponseMiddleware::class, ]; @@ -60,6 +61,9 @@ 'typo3/cms-frontend/shortcut-and-mountpoint-redirect' => [ 'disabled' => true, ], + 'typo3/cms-frontend/base-redirect-resolver' => [ + 'target' => SiteBaseRedirectResolver::class, + ], 'headless/cms-redirects/redirecthandler' => [ 'target' => RedirectHandler::class, 'before' => [ diff --git a/Tests/Unit/Middleware/SiteBaseRedirectResolverTest.php b/Tests/Unit/Middleware/SiteBaseRedirectResolverTest.php new file mode 100644 index 00000000..6a25a431 --- /dev/null +++ b/Tests/Unit/Middleware/SiteBaseRedirectResolverTest.php @@ -0,0 +1,155 @@ + 'https://www.typo3.org', + 'headless' => true, + 'languages' => [ + [ + 'title' => 'English', + 'enabled' => true, + 'languageId' => 0, + 'base' => '/en-us', + 'typo3Language' => 'default', + 'locale' => 'en_US.UTF-8', + 'iso-639-1' => 'en', + 'navigationTitle' => 'English', + 'hreflang' => 'en-us', + 'direction' => 'ltr', + 'flag' => 'us', + ], + ]]); + + $siteFinder = $this->prophesize(SiteFinder::class); + $siteFinder->getSiteByPageId(1)->willReturn($site); + + $container = new Container(); + $urlUtility = GeneralUtility::makeInstance(UrlUtility::class, null, $this->prophesize(Resolver::class)->reveal(), $siteFinder->reveal()); + $container->set(UrlUtility::class, $urlUtility); + + GeneralUtility::setContainer($container); + + $resolver = new SiteBaseRedirectResolver(); + + $request = new ServerRequest(); + $request = $request->withAttribute('site', $site); + + $uri = new Uri('https://www.typo3.org/'); + + $request = $request->withUri($uri); + $request = $request->withAttribute('routing', new SiteRouteResult($uri, $site)); + + $response = $resolver->process($request, $this->prophesize(RequestHandler::class)->reveal()); + + self::assertSame(['redirectUrl' => 'https://www.typo3.org/en-us', 'statusCode' => 307], json_decode($response->getBody()->getContents(), true)); + + // language resolved + $uri = new Uri('https://www.typo3.org/en-us/'); + + $request = $request->withUri($uri); + $request = $request->withAttribute('routing', new SiteRouteResult($uri, $site)); + $request = $request->withAttribute('language', new SiteLanguage(0, 'en', new Uri('/en-us'), ['enabled' => true])); + + $handler = $this->prophesize(RequestHandler::class); + $handler->handle($request)->willReturn(new JsonResponse(['nextMiddleware' => true])); + + $response = $resolver->process($request, $handler->reveal()); + + self::assertSame(['nextMiddleware' => true], json_decode($response->getBody()->getContents(), true)); + + // handle initial data + $uri = new Uri('https://www.typo3.org/en-us/?type=834'); + + $request = $request->withUri($uri); + $request = $request->withAttribute('language', null); + + $handler = $this->prophesize(RequestHandler::class); + $handler->handle($request)->willReturn(new JsonResponse(['nextMiddleware' => true])); + + $response = $resolver->process($request, $handler->reveal()); + + self::assertSame(['redirectUrl' => 'https://www.typo3.org/en-us', 'statusCode' => 307], json_decode($response->getBody()->getContents(), true)); + + // handle non-headless domain + $site = new Site('test', 1, [ + 'base' => 'https://www.typo3.org', + 'headless' => false, + 'languages' => [ + [ + 'title' => 'English', + 'enabled' => true, + 'languageId' => 0, + 'base' => '/en-us', + 'typo3Language' => 'default', + 'locale' => 'en_US.UTF-8', + 'iso-639-1' => 'en', + 'navigationTitle' => 'English', + 'hreflang' => 'en-us', + 'direction' => 'ltr', + 'flag' => 'us', + ], + ]]); + + $siteFinder = $this->prophesize(SiteFinder::class); + $siteFinder->getSiteByPageId(1)->willReturn($site); + + $container = new Container(); + $urlUtility = GeneralUtility::makeInstance(UrlUtility::class, null, $this->prophesize(Resolver::class)->reveal(), $siteFinder->reveal()); + $container->set(UrlUtility::class, $urlUtility); + $errorController = $this->prophesize(ErrorController::class); + $errorController->pageNotFoundAction(Argument::any(), Argument::any(), Argument::any())->willReturn(new JsonResponse(['ErrorController' => true])); + + $container->set(ErrorController::class, $errorController->reveal()); + GeneralUtility::setContainer($container); + + $uri = new Uri('https://www.typo3.org/'); + + $request = new ServerRequest(); + $request = $request->withUri($uri); + $request = $request->withAttribute('site', $site); + + $handler = $this->prophesize(RequestHandler::class); + $handler->handle($request)->willReturn(new JsonResponse(['nextMiddleware' => true])); + + $response = $resolver->process($request, $handler->reveal()); + + self::assertSame(['ErrorController' => true], json_decode($response->getBody()->getContents(), true)); + } +}