Как перенаправить URI без локали на полные локали в Symfony-CMF?

У нас есть (довольно типичное?) Соглашение для многоязычного веб-сайта Symfony CMF, где пути к ресурсам начинаются с префикса желаемой локали, например:

  • http://www.example.com/en/path/to/english-resource.html; а также
  • http://www.example.com/fr/voie/à/ressource-française.html,

Мы используем RoutingAutoBundle хранить такие маршруты в хранилище контента, и DynamicRouter использовать их: просто и легко.

Если GET запрос приходит без префикс локали, мы хотели бы:

  1. определить наиболее подходящий язык для пользователя; а потом
  2. переадресовывать1 пользователь по тому же пути, но с добавленным префиксом локали.

Первая часть является очевидным кандидатом на LuneticsLocaleBundle, с router выше в своем порядке угадывания, чем наши желаемые методы отступления: опять же, просто и легко.

Однако то, как лучше реализовать вторую часть, немного менее очевидно. В настоящее время мы настроили статический / статический маршрутизатор Symfony на более низкий приоритет в цепочке маршрутизации, чем DynamicRouter, и настроили контроллер следующим образом:

/**
* @Route("/{path}", requirements={"path" = "^(?!(en|fr)(/.*)?$)"})
* @Method({"GET"})
*/
public function localeNotInUriAction()
{
$request = this->getRequest();

$this->redirect(
'/'
. $request->getLocale()     // set by Lunetics
. $request->getRequestUri()
);
}

Но это кажется довольно хакерским, и я нахожусь в поиске чего-то более «чистого».

Первоначально я думал изменить LuneticsLocaleBundle так, чтобы он вызывал событие всякий раз, когда гадатель определяет локаль, думая, что если бы это не было RouterLocaleGuesser тогда мы можем сделать вывод, что запрошенный URI не содержит локали. Однако это явно не так, так как RouterLocaleGuesser определит локаль только в том случае, если сначала был маршрут, поэтому я бы не продвинулся.

Я сейчас немного застрял на любых других идеях. Возможно, я уже все делаю правильно? Если так, то все, что мне нужно сделать, — это найти способ вставить разрешенные локали (из конфига) в регулярное выражение требования…


  1. Внешнее перенаправление, то есть через ответ со статусом HTTP 302.

1

Решение

мы используем пользовательский обработчик 404 и лунетик:

exception_listener:
class: AppBundle\EventListener\ExceptionListener
arguments:
container: "@service_container"tags:
- { name:"kernel.event_listener", event:kernel.exception, handler:onKernelException }

и класс php

class ExceptionListener
{
/**
* @var ContainerInterface
*/
protected $container;

public function __construct(ContainerInterface $container)
{
$this->container = $container;
}

public function onKernelException(GetResponseForExceptionEvent $event)
{
if ($this->container->getParameter('kernel.debug')) {
// do not interfere with error handling while debugging
return;
}
$exception = $event->getException();
if ($exception instanceof NotFoundHttpException) {
$this->handle404($event);
return;
}

// ...
}

public function handle404(GetResponseForExceptionEvent $event)
{
$request = $event->getRequest();

if (preg_match('#^\/(de|fr|en)\/#', $request->getPathInfo())) {
// a real 404, these are nicely handled by Twig
return;
}

// i *think* that the locale is not set on the request, as lunetics comes after routing, and the routing will raise the 404
$bestLang = $this->container->get('lunetics_locale.guesser_manager')->runLocaleGuessing($request);
if (! $bestLang) {
$bestLang = 'de';
}

$qs = $request->getQueryString();
if (null !== $qs) {
$qs = '?'.$qs;
}
$url = $request->getSchemeAndHttpHost() . $request->getBaseUrl() . '/' . $bestLang . $request->getPathInfo() . $qs;

$this->redirect($event, $url);
}

было бы лучше также проверить, существует ли целевой путь на самом деле — как мы перенаправим / foobar в / de / foobar и отобразим 404 для этого, что не так уж и элегантно.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]