如何在 Symfony-CMF 中将无区域设置的 URI 重定向到全区域设置的 URI?
How should one redirect locale-less URIs to locale-full ones in 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 to store such routes in the content repository, and DynamicRouter 来利用它们:简单易行。
如果 GET
请求到达时 没有 语言环境前缀,我们希望:
- 确定最适合用户的语言环境;然后
- 重定向1 用户到同一路径但添加了语言环境前缀。
当前方法
第一部分显然是 LuneticsLocaleBundle 的候选者,其猜测顺序 router
比我们期望的后备方法更高:同样,简单易行。
但是,如何最好地实施第二部分就不太明显了。目前我们已经将 Symfony 的 default/static 路由器配置为在路由链中的优先级低于 DynamicRouter,并在其中配置了一个控制器,如下所示:
/**
* @Route("/{path}", requirements={"path" = "^(?!(en|fr)(/.*)?$)"})
* @Method({"GET"})
*/
public function localeNotInUriAction()
{
$request = this->getRequest();
$this->redirect(
'/'
. $request->getLocale() // set by Lunetics
. $request->getRequestUri()
);
}
但这感觉有点老套,我正在寻找一些东西 "cleaner"。
更好的方法?
最初我想修改 LuneticsLocaleBundle 以便在猜测者确定语言环境时它会触发一个事件,认为如果它不是 RouterLocaleGuesser
那么我们可以推断请求的 URI 不包含语言环境.然而,这显然不是这种情况,因为 RouterLocaleGuesser
只会在一开始就有路由的情况下确定语言环境——所以我不会取得任何进展。
我现在对任何其他想法都有些困惑。也许我已经在做正确的事了?如果是这样,那么我需要做的就是找到一些方法将允许的语言环境(从配置中)注入到需求正则表达式中……
- 外部重定向,即通过具有 HTTP 302 状态的响应。
我们使用自定义 404 处理程序和疯子:
exception_listener:
class: AppBundle\EventListener\ExceptionListener
arguments:
container: "@service_container"
tags:
- { name:"kernel.event_listener", event:kernel.exception, handler:onKernelException }
和 php class
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,这不是那么优雅。
背景
我们有一个(相当典型的?)多语言 Symfony CMF 网站安排,其中资源路径以所需语言环境为前缀——例如:
http://www.example.com/en/path/to/english-resource.html
;和http://www.example.com/fr/voie/à/ressource-française.html
.
我们正在使用 RoutingAutoBundle to store such routes in the content repository, and DynamicRouter 来利用它们:简单易行。
如果 GET
请求到达时 没有 语言环境前缀,我们希望:
- 确定最适合用户的语言环境;然后
- 重定向1 用户到同一路径但添加了语言环境前缀。
当前方法
第一部分显然是 LuneticsLocaleBundle 的候选者,其猜测顺序 router
比我们期望的后备方法更高:同样,简单易行。
但是,如何最好地实施第二部分就不太明显了。目前我们已经将 Symfony 的 default/static 路由器配置为在路由链中的优先级低于 DynamicRouter,并在其中配置了一个控制器,如下所示:
/**
* @Route("/{path}", requirements={"path" = "^(?!(en|fr)(/.*)?$)"})
* @Method({"GET"})
*/
public function localeNotInUriAction()
{
$request = this->getRequest();
$this->redirect(
'/'
. $request->getLocale() // set by Lunetics
. $request->getRequestUri()
);
}
但这感觉有点老套,我正在寻找一些东西 "cleaner"。
更好的方法?
最初我想修改 LuneticsLocaleBundle 以便在猜测者确定语言环境时它会触发一个事件,认为如果它不是 RouterLocaleGuesser
那么我们可以推断请求的 URI 不包含语言环境.然而,这显然不是这种情况,因为 RouterLocaleGuesser
只会在一开始就有路由的情况下确定语言环境——所以我不会取得任何进展。
我现在对任何其他想法都有些困惑。也许我已经在做正确的事了?如果是这样,那么我需要做的就是找到一些方法将允许的语言环境(从配置中)注入到需求正则表达式中……
- 外部重定向,即通过具有 HTTP 302 状态的响应。
我们使用自定义 404 处理程序和疯子:
exception_listener:
class: AppBundle\EventListener\ExceptionListener
arguments:
container: "@service_container"
tags:
- { name:"kernel.event_listener", event:kernel.exception, handler:onKernelException }
和 php class
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,这不是那么优雅。