如何在Symfony2中使路由不区分大小写?

时间:2013-07-09 02:16:38

标签: symfony routing

Symfony2中是否有任何配置允许使用案例不敏感路由?

例如,下面的路线应该被视为相同:

www.exmaple.com/all 
www.exmaple.com/ALL

有一个pull request about this,但没有参考如何实现它。

3 个答案:

答案 0 :(得分:2)

我在纯symfony(没有apache mod_rewrite)中找到了一种很好的方法,而不必为每条路由创建不区分大小写的转发规则。

这利用了Twig ExceptionController。因为这在路由未能匹配之后发生(或者由于某些其他原因而抛出了404异常),所以它不会破坏使用大写的任何现有路由URL(尽管这仍然是一个坏主意)。

namespace Application\Symfony\TwigBundle\Controller;

use Symfony\Component\HttpKernel\Exception\FlattenException;
use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Bundle\TwigBundle\Controller\ExceptionController as BaseExceptionController;

/**
 * ExceptionController.
 */
class ExceptionController extends BaseExceptionController
{


    /**
     * Redirects 404s on urls with uppercase letters to the lowercase verion,
     * then uses it's parent class to
     * Convert an Exception to a Response.
     *
     * @param Request              $request   The request
     * @param FlattenException     $exception A FlattenException instance
     * @param DebugLoggerInterface $logger    A DebugLoggerInterface instance
     *
     * @return Response
     *
     * @throws \InvalidArgumentException When the exception template does not exist
     */
    public function showAction(Request $request, FlattenException $exception, DebugLoggerInterface $logger = null)
    {
        if ( (string) $exception->getStatusCode() === '404' && preg_match('/[A-Z]/', $request->getPathInfo())) {
            $lowercaseUrl = strtolower($request->getPathInfo());
            if ($request->isMethod('POST')) {
                return new RedirectResponse(
                    $lowercaseUrl,
                    '307'//307 status code preserves post information.
                );
            }
            $queryString = $request->getQueryString();
            return new RedirectResponse(
                $lowercaseUrl.( strlen($queryString)>0 ? '?'.$queryString : '' ),
                '301'//301 status code plays nice with search engines
                );
        }
        return parent::showAction($request, $exception, $logger);
    }
}

唯一的另一个技巧是你需要将这个控制器配置为一个服务,你可以将正确的参数注入到父类的构造函数中:

in services.yml

services:
    application.custom.exception_controller:
        class: Application\Symfony\TwigBundle\Controller\ExceptionController
        arguments: [ "@twig", "%kernel.debug%" ]

在config.yml中:

twig:
    exception_controller: application.custom.exception_controller:showAction

当然,您可以将此控制器和服务定义放在任何地方

答案 1 :(得分:1)

据我所知,Symfony 2无法做到这一点。但是,您应该可以使用Apache的mod_rewrite来完成它。有关详细信息,请参阅this blog post

请务必阅读评论,因为初始帖子有一些错误。

答案 2 :(得分:1)

从Symfony2.4开始,您现在可以为路线定义条件并使用表达式语言进行复杂检查。请参阅Router: Completely Customized Route Matching with Conditions文档。

另一个解决方案是覆盖路由编译器类来更改/扩展路由匹配器的php编译:

contact:
    path:     /{media}
    defaults: { _controller: AcmeDemoBundle:Main:contact, media: organic }
    requirements:
        media: email|organic|ad
    options:
        compiler_class: MyVendor\Component\Routing\CaseInsensitiveRouteCompiler

请参阅Symfony\Component\Routing\RouteCompiler课程。

或者,正如fabpot在pull请求注释中所说,您可以覆盖Request :: getPathInfo [1]方法以始终返回小写字符串(使用setFactory [2]覆盖默认请求类)。

* 1 github.com/symfony/symfony/blob/master/src/Symfony/Component/HttpFoundation/Request.php#L866

* 2 github.com/symfony/symfony/blob/master/src/Symfony/Component/HttpFoundation/Request.php#L402