Symfony 路由:class 前缀注释中的可选语言环境目录
Symfony route: Optional locale directory in class prefix annotation
我需要能够定义路由,其中 /{_locale}
部分是可选的。这意味着我需要这些 URL 来使用相同的控制器:
my-domain.com/
(语言环境将由请求侦听器设置)
my-domain.com/[any-locale]/
同样适用于:
my-domain.com/my-page
(语言环境将由请求侦听器设置)
my-domain.com/[any-locale]/my-page
问题是我无法定义两个 class @Route
注释,因为这不是 Symfony 的 valid/accepted;而且我无法在我的控制器中复制每条路线 classes 因为会有很多,那真的很糟糕!
我试过只有一个 class 注释,但我无法让它工作。这是我的尝试:
第一个:
/**
* @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());
}
}
结论:
- 有效
- 有效
- 失败(因为只有
my-domain.com//my-page
有效)
- 有效
第二个:
我认为问题出在前导斜杠上,所以我尝试了这个:
/**
* @Route("{slash_and_locale}", requirements={"slash_and_locale": "\/?(\w{2,3})?"}, defaults={"slash_and_locale": ""})
*/
class DefaultController extends Controller { // ...
结论:
- 有效
- 有效
- 失败(同样的原因)
- 有效
我看过这个 (old) question 但还没有提交正确的答案:(
有人有建议吗?
真的很有帮助,谢谢!
我在我的项目中这样做 (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();
}
这可能是解决问题的基本方法,但有效。您的所有 "default" 路由都有效,如果您使用任何语言环境前缀访问站点,您的侦听器会更改语言,并且此控制器会重定向到当前语言的正确路由。
希望对您有所帮助。
这是我最终决定要做的事情:
- 不管我想要什么,我为每个控制器操作定义了两条路线(见下面的例子);
- 我扩展了 Symfony 的
RoutingExtension
以在使用 path
或 url
方法时自动选择正确的路线。
这是我的双路由配置的样子(注意双路由,第二个有 +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);
}
}
希望对您有所帮助!
我找到了一种通过扩展来自定义 routingComponent 的方法。这样每一个 url 没有匹配的路由,将被重试前缀 url 与默认 locale
<?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);
}
}
}
在参数中设置新的url匹配器:
parameters:
# UrlMatcher
router.options.matcher.cache_class: ~
router.options.matcher_class: App\Component\UrlMatcher
我需要能够定义路由,其中 /{_locale}
部分是可选的。这意味着我需要这些 URL 来使用相同的控制器:
my-domain.com/
(语言环境将由请求侦听器设置)my-domain.com/[any-locale]/
同样适用于:
my-domain.com/my-page
(语言环境将由请求侦听器设置)my-domain.com/[any-locale]/my-page
问题是我无法定义两个 class @Route
注释,因为这不是 Symfony 的 valid/accepted;而且我无法在我的控制器中复制每条路线 classes 因为会有很多,那真的很糟糕!
我试过只有一个 class 注释,但我无法让它工作。这是我的尝试:
第一个:
/**
* @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());
}
}
结论:
- 有效
- 有效
- 失败(因为只有
my-domain.com//my-page
有效) - 有效
第二个:
我认为问题出在前导斜杠上,所以我尝试了这个:
/**
* @Route("{slash_and_locale}", requirements={"slash_and_locale": "\/?(\w{2,3})?"}, defaults={"slash_and_locale": ""})
*/
class DefaultController extends Controller { // ...
结论:
- 有效
- 有效
- 失败(同样的原因)
- 有效
我看过这个 (old) question 但还没有提交正确的答案:(
有人有建议吗? 真的很有帮助,谢谢!
我在我的项目中这样做 (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();
}
这可能是解决问题的基本方法,但有效。您的所有 "default" 路由都有效,如果您使用任何语言环境前缀访问站点,您的侦听器会更改语言,并且此控制器会重定向到当前语言的正确路由。
希望对您有所帮助。
这是我最终决定要做的事情:
- 不管我想要什么,我为每个控制器操作定义了两条路线(见下面的例子);
- 我扩展了 Symfony 的
RoutingExtension
以在使用path
或url
方法时自动选择正确的路线。
这是我的双路由配置的样子(注意双路由,第二个有 +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);
}
}
希望对您有所帮助!
我找到了一种通过扩展来自定义 routingComponent 的方法。这样每一个 url 没有匹配的路由,将被重试前缀 url 与默认 locale
<?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);
}
}
}
在参数中设置新的url匹配器:
parameters:
# UrlMatcher
router.options.matcher.cache_class: ~
router.options.matcher_class: App\Component\UrlMatcher