【问题标题】:Add trailing slashes to symfony routing with optional pagination parameter of friendly URL使用友好 URL 的可选分页参数向 symfony 路由添加尾部斜杠
【发布时间】:2016-03-11 15:50:30
【问题描述】:

我有以下路由配置:

# Resources/config/routing.yml
AcmeBundle_article:
    resource: "@AcmeBundle/Resources/config/routing/article.yml"
    prefix:   /article

# Resources/config/routing/article.yml
acme_article:
    path:     /{page}
    defaults: { _controller: AcmeBundle:Article:index, page: 1 }

每当我调用$this->redirect($this->generateUrl('acme_article')){{ path('acme_article') }} 时,URL 都会不带斜杠/,例如example.com/article。我希望它像

example.com/article/ example.com/article/1
example.com/article/2

当我改变路由时没有{page}参数如下

# Resources/config/routing/article.yml
acme_article:
    path:     /
    defaults: { _controller: AcmeBundle:Article:index }

然后,按照我的预期添加尾部斜杠:

example.com/article/
example.com/article/?page=1
example.com/article/?page=2

但是,我想在路由中保留{page},并且只想在没有页面参数时添加斜杠。是否可以在 Symfony 2 路由中做?

【问题讨论】:

    标签: php symfony routing


    【解决方案1】:

    你可以这样做:

    # Resources/config/routing/article.yml
    acme_article:
        pattern: /{page}
        defaults: { _controller: AcmeBundle:Article:index, page: 1 }
        requirements:
            page: ".*"
    

    在你的控制器中:

    // ArticleController.php
    public function indexAction($page)
    {
        if (!$page) {
            $page = 1;
        }
    }
    

    现在您可以使用:

    /article   # page = 1
    /article/  # page = 1
    /article/2 # page = 2
    

    编辑

    要保留参数的类型提示,只需在方法中添加一个检查。示例:

    // Article:index
    if ($page && intval($page) < 1) {
        return $this->redirect('/article/');
    }
    

    你保留尾部斜杠,因为page 没有设置。

    编辑 2

    以下解决方案似乎更清洁。

    # Resources/config/routing/article.yml
    acme_article:
        pattern: /{page}
        defaults: { _controller: AcmeBundle:Article:index, page: 1 }
        requirements:
            page: \d*
    

    此替代方法允许尾部斜杠,并且page参数必须是数字(如果已设置)。

    它可以解决您关于允许在 URL 中使用斜杠的问题,但如果您不在生成的 url 末尾手动添加斜杠,它不会自动重定向(我知道它不是很干净,但没有找到其他替代方法:/)。

    【讨论】:

    • page: ".*" 表示任何字符都允许page
    • 是的,如果您仅将参数限制为数字,则似乎您不能有尾部斜杠。使用这种(快速而肮脏的)替代方法,您必须检查控制器内的页面参数类型,如果它不是 int 则使用重定向(查看我的编辑以获取工作示例)。
    • 您可能误解了这个问题。当我们在控制器中调用$this-&gt;redirect($this-&gt;generateUrl('acme_article')) 或在twig 中使用路由键acme_article 调用{{ path('acme_article') }} 时,Symfony 路由会自动省略斜线。我们从来没有使用过这样的$this-&gt;redirect('/article/');
    • ´$this->redirect($this->generateUrl('your_home_route') . 'article/');´ 返回带有斜杠的完整 URL。如果你真的需要斜线,这是我知道的唯一选择,因为在 Symfony 上定义/生成 url 似乎是不可能的。
    • article/等控制器中直接使用URL并不是一个好主意,因为所有路由都定义在一个地方,即routing.yml
    【解决方案2】:

    我一直在寻找一种可以使用路由配置解决此问题的方法,但我认为这是不可能的。不过我做了一些调整。

    (1) 我在路由中添加了一个变量trailingSlash,默认值为/。我使用KnpPaginator 进行分页。第一页分页时需要默认值/,否则URL中不附加尾部斜杠。

    acme_article:
        path:     /{trailingSlash}{page}
        defaults: { _controller: AcmeBundle:Article:index, trailingSlash: /, page: 1 }
        requirements:
            trailingSlash : '/?'
    

    (2) 我在Article:index控制器中添加了一些参数处理。当没有找到尾部斜杠时,抛出错误。

    public function indexAction($trailingSlash = null, $page = 1)
    {
        $request = $this->container->get('request');
    
        // if there is $page, $trailingSlash will be empty
        if (($trailingSlash == '/' && $page >= 1) || !is_numeric($page)) {
            throw new NotFoundHttpException(sprintf('No route found for "%s"', $request->getPathInfo()));
        }
    
        // ...
    
        return $this->render('AcmeBundle:Article:index.html.twig', array(
            'articles'          => $articles,
            'pagination'        => $pagination,
            'totalArticles'     => $pagination->getTotalItemCount(),
            'trailingSlash'     => $trailingSlash
        ));
    }
    

    (3)我必须在控制器和树枝中的每个 URL 生成中添加一个尾部斜杠。

    // Controller
    $this->redirect($this->generateUrl('acme_article').'/');
    // Twig
    {{ path('acme_article') }}/
    

    (4) 从 SEO 的角度来看,我强制在 rel="canonical" 中为 page=1 添加斜杠

    {% block canonical %}
        <!-- trailingSlash is / when page = 1 -->
        <!-- trailingSlash is empty when page > 1 -->
        <link rel="canonical" href="{{ url(app.request.get('_route'), app.request.get('_route_params')) }}{{ trailingSlash }}" />
    {% endblock %}
    

    它解决了问题,但我觉得这是一种解决方法。欢迎提供更好的解决方案。

    【讨论】:

      猜你喜欢
      • 2020-03-21
      • 1970-01-01
      • 2012-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-13
      • 1970-01-01
      • 2012-04-05
      相关资源
      最近更新 更多