如何定义可选的占位符

3.4 版本
维护中的版本

为了让事情更加精彩,我们添加一个新的路由,为这个假想的博客程序显示出所有的可用主题列表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// src/AppBundle/Controller/BlogController.php
 
// ...
class BlogController extends Controller
{
    // ...
 
    /**
     * @Route("/blog")
     */
    public function indexAction()
    {
        // ...
    }
}
1
2
3
4
# app/config/routing.yml
blog:
    path:      /blog
    defaults:  { _controller: AppBundle:Blog:index }
1
2
3
4
5
6
7
8
9
10
11
<!-- app/config/routing.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/routing
        http://symfony.com/schema/routing/routing-1.0.xsd">
 
    <route id="blog" path="/blog">
        <default key="_controller">AppBundle:Blog:index</default>
    </route>
</routes>
1
2
3
4
5
6
7
8
9
10
// app/config/routing.php
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;
 
$collection = new RouteCollection();
$collection->add('blog', new Route('/blog', array(
    '_controller' => 'AppBundle:Blog:index',
)));
 
return $collection;

到目前为止,该路由只是尽可能的简单,它没有包含通配符(参数),也只能匹配确定的URL即/blog。但如果你需要该路由支持分页,以/blog/2来显示blog列表的第2页呢?更新该路由,添加一个新的{page}占位符:

1
2
3
4
5
6
7
8
9
10
11
// src/AppBundle/Controller/BlogController.php
 
// ...
 
/**
 * @Route("/blog/{page}")
 */
public function indexAction($page)
{
    // ...
}
1
2
3
4
# app/config/routing.yml
blog:
    path:      /blog/{page}
    defaults:  { _controller: AppBundle:Blog:index }
1
2
3
4
5
6
7
8
9
10
11
<!-- app/config/routing.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/routing
        http://symfony.com/schema/routing/routing-1.0.xsd">
 
    <route id="blog" path="/blog/{page}">
        <default key="_controller">AppBundle:Blog:index</default>
    </route>
</routes>
1
2
3
4
5
6
7
8
9
10
// app/config/routing.php
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;
 
$collection = new RouteCollection();
$collection->add('blog', new Route('/blog/{page}', array(
    '_controller' => 'AppBundle:Blog:index',
)));
 
return $collection;

跟之前的{slug}占位符一样,匹配{page}的值也能在你的控制器中使用。这个值主要是决定“哪一组博客主题”将被显示在当前分页上。

但是等一下!由于占位符默认是必须的,这个路由将不再匹配简单的/blog。而变成了若要看第1页的博客,必须要使用/blog/1这样的URL!因为没有什么办法能让富web应用程序去操作或修改路由进而令{page}参数可选。通过在(路由配置中的)defaults集合中包含该参数的默认值,可以实现:

1
2
3
4
5
6
7
8
9
10
11
// src/AppBundle/Controller/BlogController.php
 
// ...
 
/**
 * @Route("/blog/{page}", defaults={"page" = 1})
 */
public function indexAction($page)
{
    // ...
}
1
2
3
4
# app/config/routing.yml
blog:
    path:      /blog/{page}
    defaults:  { _controller: AppBundle:Blog:index, page: 1 }
1
2
3
4
5
6
7
8
9
10
11
12
<!-- app/config/routing.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/routing
        http://symfony.com/schema/routing/routing-1.0.xsd">
 
    <route id="blog" path="/blog/{page}">
        <default key="_controller">AppBundle:Blog:index</default>
        <default key="page">1</default>
    </route>
</routes>
1
2
3
4
5
6
7
8
9
10
11
// app/config/routing.php
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;
 
$collection = new RouteCollection();
$collection->add('blog', new Route('/blog/{page}', array(
    '_controller' => 'AppBundle:Blog:index',
    'page'        => 1,
)));
 
return $collection;

通过添加pagedefaults键,{page}占位符在URL中不再是必选项。URL /blog将匹配这个路由,此时page参数的值将被设为1/blog/2同样匹配路由,此时给了page参数为2。完美了!

URL Route/路由 Parameters/参数
/blog blog {page} = 1
/blog/1 blog {page} = 1
/blog/2 blog {page} = 2

当然,你可以有多个可选的占位符(如/blog/{slug}/{page}),但是某个可选的占位符后面的所有占位符都必须可选。举例,/{page}/blog 是一个有效的路径,但是page必须是必填的(比如,简单的/blog是不能匹配/{page}/blog路由的)。

带有选填参数的路由,其末尾将不去匹配带有斜杠的请求(如/blog/无法匹配,/blog能够匹配)。

本文,包括例程代码在内,采用的是 Creative Commons BY-SA 3.0 创作共用授权。

登录symfonychina 发表评论或留下问题(我们会尽量回复)