如何在Symfony-CMF中将无语言环境的URI重定向到语言环境完整的URI?

时间:2015-05-27 18:36:05

标签: php symfony routes locale 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 到同一路径但添加了区域设置前缀。
  3. 当前方法

    第一部分显然是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()
        );
    }
    

    但这感觉相当hacky,我正在寻找“更清洁”的东西。

    更好的方法?

    最初我想修改LuneticsLocaleBundle,以便每当猜测者确定语言环境时它会触发事件,认为如果它不是RouterLocaleGuesser,那么我们可以推断出请求的URI不包含语言环境。然而事实并非如此,因为RouterLocaleGuesser只会确定首次出现路线时的区域设置 - 所以我没有取得任何进展。

    我现在对任何其他想法都有点困惑。也许我毕竟已经做对了?如果是这样,那么我需要做的就是找到一些方法将允许的语言环境(从配置)注入需求正则表达式...

    1. 外部重定向,即通过HTTP 302状态的响应。

1 个答案:

答案 0 :(得分:1)

我们使用自定义404处理程序和lunetics:

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,这不是那么优雅。