Symfony route:类前缀注释中的可选语言环境目录

时间:2015-09-29 09:39:29

标签: php symfony routes

我需要能够定义/{_locale}部分是可选的路线。这意味着我需要这些URL使用相同的控制器:

  1. my-domain.com/(区域设置将由请求侦听器设置)
  2. my-domain.com/[any-locale]/
  3. 同样如下:

    1. my-domain.com/my-page(区域设置将由请求侦听器设置)
    2. my-domain.com/[any-locale]/my-page
    3. 问题是我无法定义两个类@Route注释,因为Symfony无效/接受它;而且我不能复制我的控制器类中的每一条路线,因为会有很多而且会非常糟糕!

      我试过只有一个类注释,但我无法让它工作。以下是我的尝试:

      第一:

      /**
       * @Route("/{_locale}", requirements={"_locale": "(\w{2,3})?"})
       */
      class DefaultController extends Controller {
      
          /**
           * @Route("/")
           * @param Request $request
           * @return Response
           */
          public function indexAction(Request $request) {
              return new Response('index '.$request->getLocale());
          }
      
          /**
           * @Route("/my-page")
           * @param Request $request
           * @return Response
           */
          public function testAction(Request $request) {
              return new Response('test '.$request->getLocale());
          }
      
      }
      

      结论:

      1. 作品
      2. 作品
      3. 失败(因为只有my-domain.com//my-page才有效)
      4. 作品
      5. 第二

        我认为问题是主要的斜线,所以我尝试了这个:

        /**
         * @Route("{slash_and_locale}", requirements={"slash_and_locale": "\/?(\w{2,3})?"}, defaults={"slash_and_locale": ""})
         */
        class DefaultController extends Controller { // ...
        

        结论:

        1. 作品
        2. 作品
        3. 失败(同样的原因)
        4. 作品
        5. 我见过这个(old) question但是还没有提交正确答案:(

          有意见的人吗? 真的很有帮助,谢谢!

3 个答案:

答案 0 :(得分:1)

这是我最终决定做的事情:

  1. 尽管我想要的是,我为每个控制器动作定义了两条路线(见下面的例子);
  2. 我使用RoutingExtensionpath方法扩展Symfony的url以自动选择正确的路线。
  3. 这是我的双路径配置的样子(注意双路线,第二路线有+locale后缀):

    <?php
    
    // src\AppBundle\Controller\DefaultController.php
    
    namespace AppBundle\Controller;
    
    use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
    use Symfony\Bundle\FrameworkBundle\Controller\Controller;
    use Symfony\Component\HttpFoundation\Response;
    
    class DefaultController extends Controller {
    
        /**
         * @Route("/", name="front_index")
         * @Route("/{_locale}/", name="front_index+locale", requirements={"_locale": "\w{2,3}"})
         * @return Response
         */
        public function indexAction() {
            return $this->render('test/domain-translation.html.twig');
        }
    
    }
    

    这是我的RoutingExtension重载:

    <?php
    
    // src\AppBundle\Twig\LocaleRoutingExtension.php
    
    namespace AppBundle\Twig;
    
    use AppBundle\Document\Domain;
    use Symfony\Bridge\Twig\Extension\RoutingExtension;
    use Symfony\Component\DependencyInjection\ContainerInterface;
    use Symfony\Component\HttpFoundation\Request;
    
    class LocaleRoutingExtension extends RoutingExtension {
    
        /** @var ContainerInterface */
        protected $container;
    
        /** @var Domain */
        protected $domain;
    
        /** @var Request */
        protected $request;
    
        public function setContainer(ContainerInterface $container) {
            $this->container = $container;
            $this->domain = $this->container->get('app.domain_service')->getDomain();
            $this->request = $this->container->get('request_stack')->getMasterRequest();
        }
    
        protected function processNameAndParameters($name, $parameters) {
    
            $nameWithLocale = $name . '+locale';
            $routes = $this->container->get('router')->getRouteCollection();
            $route = $routes->get($nameWithLocale);
    
            if (array_key_exists('no-locale-filter', $parameters) && $parameters['no-locale-filter']) {
                unset($parameters['no-locale-filter']);
                return array('name' => $name, 'parameters' => $parameters);
            }
    
            if (isset($this->domain) && $this->domain->hasMultipleLocales() && isset($route)) {
                $name = $nameWithLocale;
    
                $locale = null;
                if (!array_key_exists('_locale', $parameters)) {
                    if (isset($this->request)) {
                        $locale = $this->request->getLocale();
                    } else {
                        $locale = $this->domain->getDefaultLocale();
                    }
                }
    
                $parameters['_locale'] = $locale;
            }
    
            return array('name' => $name, 'parameters' => $parameters);
        }
    
        public function getPath($name, $parameters = array(), $relative = false) {
            $processed = $this->processNameAndParameters($name, $parameters);
            return parent::getPath($processed['name'], $processed['parameters'], $relative);
        }
    
        public function getUrl($name, $parameters = array(), $schemeRelative = false) {
            $processed = $this->processNameAndParameters($name, $parameters);
            return parent::getUrl($processed['name'], $processed['parameters'], $schemeRelative);
        }
    
    }
    

    我希望这有帮助!

答案 1 :(得分:0)

我在我的项目(yml)中执行此操作

language_selection:
    path: /{locale}/{path}
    defaults: { _controller: PurchaserBundle:Home:langSelection, path: "" }
    requirements:
        path:  .+
        locale: es|ca|en

在控制器中:

public function langSelectionAction($locale, $path)
{
    if (in_array($locale, array('es', 'en', 'ca'))) {
        return $this->redirect('/' . $path);
    }

    $this->create404NotFound();
}

这可能是解决问题的基本方法,但有效。所有“默认”路由都有效,如果您使用任何语言环境前缀访问该站点,您的侦听器将更改语言,并且此控制器将以当前语言重定向到正确的路由。

我希望它有所帮助。

答案 2 :(得分:0)

我找到了一种仅通过扩展自定义routingComponent的方法。这样,每个与路由不匹配的网址都将被重试,并使用默认语言环境作为前缀网址

<?php

namespace App\Component;

use Symfony\Component\Routing\Exception\ResourceNotFoundException;
use Symfony\Component\Routing\Matcher\UrlMatcher as BaseUrlMatcher;

class UrlMatcher extends BaseUrlMatcher
{
    public function match($pathinfo)
    {
        try {
            return parent::match($pathinfo);
        } catch (ResourceNotFoundException $exception) {
            $url = sprintf('/%s%s', 'en', $pathinfo);

            return parent::match($url);
        }
    }
}

在参数中设置新的urlMatcher:

parameters:
        # UrlMatcher
        router.options.matcher.cache_class: ~
        router.options.matcher_class: App\Component\UrlMatcher