127 lines
4.3 KiB
PHP
127 lines
4.3 KiB
PHP
<?php
|
|
|
|
namespace KupShop\I18nBundle\Util\Locale;
|
|
|
|
use KupShop\KupShopBundle\Context\ContextManager;
|
|
use KupShop\KupShopBundle\Context\LanguageContext;
|
|
use KupShop\KupShopBundle\Util\HTTPUtil;
|
|
use KupShop\KupShopBundle\Util\System\ControllerUtil;
|
|
use KupShop\KupShopBundle\Views\RouteAwareResponderInterface;
|
|
use KupShop\LocalePrefixBundle\Util\LocalePrefixUtil;
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
use Symfony\Component\HttpFoundation\RequestStack;
|
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
|
use Symfony\Component\Routing\RouterInterface;
|
|
|
|
class LanguageAwareUrlGenerator
|
|
{
|
|
public function __construct(
|
|
private readonly RouterInterface $router,
|
|
private readonly LanguageContext $languageContext,
|
|
private readonly ControllerUtil $controllerUtil,
|
|
private readonly ContextManager $contextManager,
|
|
private readonly RequestStack $requestStack,
|
|
private readonly ?LocalePrefixUtil $localePrefixUtil = null,
|
|
) {
|
|
}
|
|
|
|
public function generateInLanguage(string $language, string $path = '/'): string
|
|
{
|
|
$request = $this->createRequest($path);
|
|
|
|
return $this->withMainRequest($request, function () use ($request, $language) {
|
|
$fallback = true;
|
|
|
|
if ($match = $this->controllerUtil->getControllerByRequest($request)) {
|
|
if ($url['path'] = $this->getCorrectUrlFromController($request, $match, $language)) {
|
|
return HTTPUtil::http_build_url($url);
|
|
}
|
|
|
|
$fallback = false;
|
|
try {
|
|
$url['path'] = $pathInLanguage = $this->router->generateInLanguage($language, $match['_route'], $match['_route_params']);
|
|
$url = HTTPUtil::http_build_url($url);
|
|
if (!$url || empty($pathInLanguage)) {
|
|
$fallback = true;
|
|
}
|
|
} catch (\Exception) {
|
|
$fallback = true;
|
|
}
|
|
}
|
|
|
|
if ($fallback) {
|
|
$url = $this->router->generateInLanguage($language, 'home');
|
|
}
|
|
|
|
$this->languageContext->activate($language);
|
|
|
|
return $url;
|
|
});
|
|
}
|
|
|
|
private function getCorrectUrlFromController(Request $request, array $match, string $language): ?string
|
|
{
|
|
$controller = $this->controllerUtil->instantiateController($match['_controller']);
|
|
$controllerReturn = clone $this->controllerUtil->callController($request, $controller);
|
|
|
|
if (!($controllerReturn instanceof RouteAwareResponderInterface)) {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
$url = $this->contextManager->activateContexts(
|
|
[LanguageContext::class => $language],
|
|
fn (): ?string => $controllerReturn->getCorrectUrl(),
|
|
);
|
|
} catch (NotFoundHttpException) {
|
|
$url = null;
|
|
}
|
|
|
|
return $url === null ? $this->router->generateInLanguage($language, 'home') : $url;
|
|
}
|
|
|
|
private function createRequest(string $uri): Request
|
|
{
|
|
$request = Request::create($uri);
|
|
$request->attributes->set('path', ltrim(parse_url($uri)['path'] ?? '/', '/'));
|
|
|
|
if (findModule(\Modules::LOCALE_PREFIX)) {
|
|
$this->localePrefixUtil->setRequestAttribute($request);
|
|
}
|
|
|
|
if ($this->requestStack->getMainRequest()->hasSession()) {
|
|
$request->setSession(
|
|
$this->requestStack->getMainRequest()->getSession()
|
|
);
|
|
}
|
|
|
|
return $request;
|
|
}
|
|
|
|
private function withMainRequest(Request $request, callable $fn): mixed
|
|
{
|
|
$prevRequests = [];
|
|
while ($this->requestStack->getCurrentRequest()) {
|
|
// no-op: intentionally discarding all requests so request in args will be main request
|
|
$prevRequests[] = $this->requestStack->pop();
|
|
}
|
|
// reverse, so last pop request is first
|
|
$prevRequests = array_reverse($prevRequests);
|
|
|
|
// push arg request to requests so it becomes main request
|
|
$this->requestStack->push($request);
|
|
|
|
$result = $fn();
|
|
|
|
// remove arg request
|
|
$this->requestStack->pop();
|
|
|
|
// restore prev requests
|
|
foreach ($prevRequests as $prevRequest) {
|
|
$this->requestStack->push($prevRequest);
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
}
|