对于任何严谨的web应用程序而言美观的URL是绝对必须的。这意味着日渐淘汰的 index.php?article_id=57 这类丑陋的URL要被 /read/intro-to-symfony 取代。

拥有灵活性是更加重要的。你把页面的URL从 /blog 改为 /news 时需要做些什么?你需要追踪并更新多少链接,才能做出这种改变?如果你使用Symfony的路由,改变起来很容易。

Symfony路由器允许你定义创造性的url,再将其映射到程序不同区域。读完本文,你可以做到:

创建复杂的路由,将其映射到控制器

在模板和控制器中生成URL

从Bundle中(或从其他地方)加载路由资源

对路由除错

路由示例 ¶

一个 路由,是指一个URL路径(path)到一个控制器(controller)的映射。例如,你想(通过路由)匹配到诸如 /blog/my-post 和 /blog/all-about-symfony 这样的任何一个URL,并且把路由发送到一个“能够查询和输出该篇博文”的控制器。这个路由很简单:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33// src/AppBundle/Controller/BlogController.php

namespace AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;

class BlogController extends Controller

{

/**

* Matches /blog exactly / 精确匹配了/blog

*

* @Route("/blog", name="blog_list")

*/

public function listAction()

{

// ...

}

/**

* Matches /blog/* / 匹配的是/blog/*

*

* @Route("/blog/{slug}", name="blog_show")

*/

public function showAction($slug)

{

// $slug will equal the dynamic part of the URL

// e.g. at /blog/yay-routing, then $slug='yay-routing'

// $slug 必须等同于URL中的动态部分

// 即,在 /blog/yay-routing 中 $slug='yay-routing'

// ...

}

}

1

2

3

4

5

6

7

8# app/config/routing.ymlblog_list:path: /blogdefaults:{ _controller:AppBundle:Blog:list }

blog_show:path: /blog/{slug}defaults:{ _controller:AppBundle:Blog:show }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

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">

AppBundle:Blog:list

AppBundle:Blog:show

1

2

3

4

5

6

7

8

9

10

11

12

13// app/config/routing.php

use Symfony\Component\Routing\RouteCollection;

use Symfony\Component\Routing\Route;

$collection = new RouteCollection();

$collection->add('blog_list', new Route('/blog', array(

'_controller' => 'AppBundle:Blog:list',

)));

$collection->add('blog_show', new Route('/blog/{slug}', array(

'_controller' => 'AppBundle:Blog:show',

)));

return $collection;

多亏了以下这两个路由:

如果用户来到 /blog,则第一个路由被匹配而 listAction() 会被执行;

如果用户来到 /blog/*, 则第二个路由被匹配而 showAction() 将被执行。因为路由的路径是 /blog/{slug}, 有个 $slug 变量被传到了能够匹配该值的 showAction() 中。例如,如果用户来到 /blog/yay-routing,那么 $slug 即等于 yay-routing。

只要在你的路由路径(route path)中包含有 {placeholder},它便成为一个通配符:它可以匹配 任何 值。你的控制器从现在起 也 可以有一个名为 $placeholder 的参数(此通配符和参数 必须 匹配)。

每个路由都有一个内部名称: blog_list 和 blog_show。这些名称可以是任何内容 (只要唯一即可) 而且不必赋予任何特别的含意。后面,你将使用它来生成Url。

其他格式的路由

每个方法上面的 @Route 被称为一个 annotation(注释)。如果你希望以YAML, XML 或 PHP来配置你的路由,绝对没问题!

在这些格式中,_controller “默认”值,是一个特殊的键,它告诉Symfony,当一个URL匹配这个路由时,要去执行哪个控制器。_controller 字符串被称为 logical name(逻辑名)。它遵循的是“指向特定的PHP类或方法”这样一个模式,本例中是 AppBundle\Controller\BlogController::listAction 和 AppBundle\Controller\BlogController::showAction 方法。

这就是Symfony路由的目标:把一个请求的URL映射到控制器中。接下来,你将学习到所有类型的技巧,可以令极度复杂的URL在映射时变得容易。

添加{通配符}条件 ¶

设想 blog_list 路由将包含博客主题带有分页的一个列表,对于第2和第3页有类似 /blog/2 和 /blog/3 这样的URL。如果你把路由路径改为 /blog/{page},会出现问题:

blog_list: /blog/{page} 将匹配 /blog/*;

blog_show: /blog/{slug} 将 同样 匹配 /blog/*。

当两个路由匹配同一个URL时,第一个 被加载的路由胜出。不幸的是,这也意味着 /blog/yay-routing 将匹配到 blog_list。不太好!

要修复这个,添加一个 requirement(条件),以便 {page} 通配符能够 仅 匹配数字(digits):

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24// src/AppBundle/Controller/BlogController.php

namespace AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;

class BlogController extends Controller

{

/**

* @Route("/blog/{page}", name="blog_list", requirements={"page": "\d+"})

*/

public function listAction($page)

{

// ...

}

/**

* @Route("/blog/{slug}", name="blog_show")

*/

public function showAction($slug)

{

// ...

}

}

1

2

3

4

5

6

7

8

9# app/config/routing.ymlblog_list:path: /blog/{page}defaults: { _controller:AppBundle:Blog:list }requirements:page:'\d+'

blog_show: # ...

1

2

3

4

5

6

7

8

9

10

11

12

13

14

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">

AppBundle:Blog:list

\d+

1

2

3

4

5

6

7

8

9

10

11

12

13

14// app/config/routing.php

use Symfony\Component\Routing\RouteCollection;

use Symfony\Component\Routing\Route;

$collection = new RouteCollection();

$collection->add('blog_list', new Route('/blog/{page}', array(

'_controller' => 'AppBundle:Blog:list',

), array(

'page' => '\d+'

)));

// ...

return $collection;

\d+ 是一个正则表达式,匹配了任意长度的 数字。现在:

URL

路由

参数

/blog/2

blog_list

$page = 2

/blog/yay-routing

blog_show

$slug = yay-routing

要了解其他一些路由的条件 - 像是HTTP method, hostname 以及 dynamic

expressions(动态表达式) - 参考 如何定义路由条件。

给{占位符}一个默认值 ¶

前例中,blog_list 路由的路径是 /blog/{page}。如果用户访问 /blog/1,则会匹配。但如果他们访问的是 /blog,就将 无法 匹配到。一旦你添加了某个 {占位符} 到路由中,它就 必须 得有一个值。

那么当用户访问 /blog 时,你如何才能令 blog_list 再一次匹配呢?添加一个 默认 值即可:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16// src/AppBundle/Controller/BlogController.php

namespace AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;

class BlogController extends Controller

{

/**

* @Route("/blog/{page}", name="blog_list", requirements={"page": "\d+"})

*/

public function listAction($page = 1)

{

// ...

}

}

1

2

3

4

5

6

7

8

9# app/config/routing.ymlblog_list:path: /blog/{page}defaults: { _controller:AppBundle:Blog:list, page:1 }requirements:page:'\d+'

blog_show: # ...

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

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">

AppBundle:Blog:list

1

\d+

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19// app/config/routing.php

use Symfony\Component\Routing\RouteCollection;

use Symfony\Component\Routing\Route;

$collection = new RouteCollection();

$collection->add('blog_list', new Route(

'/blog/{page}',

array(

'_controller' => 'AppBundle:Blog:list',

'page' => 1,

),

array(

'page' => '\d+'

)

));

// ...

return $collection;

现在,当用户访问 /blog 时,blog_list 路由会匹配,并且 $page 路由参数会默认取值为 1。

高级路由示例 ¶

贯穿所有内容,查看下例:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20// src/AppBundle/Controller/ArticleController.php

// ...

class ArticleController extends Controller

{

/**

* @Route(

* "/articles/{_locale}/{year}/{slug}.{_format}",

* defaults={"_format": "html"},

* requirements={

* "_locale": "en|fr",

* "_format": "html|rss",

* "year": "\d+"

* }

* )

*/

public function showAction($_locale, $year, $slug)

{

}

}

1

2

3

4

5

6

7

8# app/config/routing.ymlarticle_show:path: /articles/{_locale}/{year}/{slug}.{_format}defaults:{ _controller:AppBundle:Article:show, _format:html }requirements:_locale: en|fr_format: html|rssyear: \d+

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

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">

path="/articles/{_locale}/{year}/{slug}.{_format}">

AppBundle:Article:show

html

en|fr

html|rss

\d+

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18// app/config/routing.php

use Symfony\Component\Routing\RouteCollection;

use Symfony\Component\Routing\Route;

$collection = new RouteCollection();

$collection->add(

'article_show',

new Route('/articles/{_locale}/{year}/{slug}.{_format}', array(

'_controller' => 'AppBundle:Article:show',

'_format' => 'html',

), array(

'_locale' => 'en|fr',

'_format' => 'html|rss',

'year' => '\d+',

))

);

return $collection;

如你所见,这个路由仅在URL的 {_locale} 部分是 en 或 fr 时,同时 {year} 是一个数字的时候,才会匹配。此路由也表明,你可以在占位符之间使用一个“点”而不是一个斜杠。匹配这个路由的URL可能是下面这种:

/articles/en/2010/my-post

/articles/fr/2010/my-post.rss

/articles/en/2013/my-latest-post.html

这个例子也突显了 _format 路由参数(routing parameter)。当使用这个参数时,匹配到的值将成为 Request 对象中的"request format"(请求format)。

最后,请求格式将被用于某些事情,比如设置响应的 Content-Type 等(如,一个 json 的请求format将转换成 application/json 的 Content-Type)。它也可用于控制器,对每一个 _format 值来输出不同的模板。_format 是一种强有力的方式,来在不同格式(format)之间输出相同的内容。

Symfony 3.0之前的版本中,可以通过(URL中的)名为 _format 的请求参数(query parameter),来覆写request format(例如:

/foo/bar?_format=json)。依赖此种行为不光被认为是个糟糕实践,而且会影响你的程序升级到Symfony 3。

Note

有时,你希望令路由中的特定部分能够进行全局配置。Symfony提供了一种方式,即利用服务容器参数来实现之。更多内容可参考 "如何在路由中使用容器参数"。

Caution

一个路由占位符名称不可以起于数字,也不可以长于32个字符。

特殊路由参数 ¶

你已经看到,每一个路由参数或其默认值最终都是可以做为参数(arguments)用在控制器方法(译注:即action)中的。此外,还有四个特殊参数:每一个都能为你的程序增添一个独有的功能性。

_controller

就像你看到的,此参数用于决定,当路由匹配时,须执行哪个控制器。

_format

用于设置request format (详见这里)。

_fragment

用于设置fragment identifier,即,URL中可选的最末部分,起自一个 # 字符,用来识别页面中的某一部分。

Symfony 3.2:_fragment 参数自Symfony 3.2起被引入。

_locale

用于设置请求中的locale信息 (详见这里)。

控制器命名法 ¶

如果你使用YAML, XML 或 PHP方式的路由配置,则每个路由必须有一个 _controller 参数,用于指定当路由匹配时要执行哪个控制器。这个参数使用了一个简单的字符串规范,被称为 logical controller name(逻辑控制器名),Symfony据此(将路由)映射到某个特定的PHP方法或类中。这一命名法有三个部分,每个部分用一个colon(冒号)分隔开来:

bundle:controller:action

例如,AppBundle:Blog:show 这个 _controller 值代表:

Bundle(Bundle名)

Controller Class(控制器类名)

Method Name(控制器方法名)

AppBundle

BlogController

showAction()

控制器看起来像下面这样:

1

2

3

4

5

6

7

8

9

10

11

12// src/AppBundle/Controller/BlogController.php

namespace AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class BlogController extends Controller

{

public function showAction($slug)

{

// ...

}

}

注意Symfony添加了字符串 Controller 到类名中 (Blog

=> BlogController) 同时添加了 Action 到方法名中 (show => showAction())。

你也可以使用类的FQCN来引用类名和方法: AppBundle\Controller\BlogController::showAction。但如果你遵循了是简便方法,逻辑命名是非常轻巧和灵活的。

Tip

若要引用一个在控制器类中实现了 __invoke() 方法的action,你不可以传入方法名,只需使用FQCN类名足矣 (如 AppBundle\Controller\BlogController)。

Note

除了使用逻辑名或FQCN类名之外,Symfony还支持第三种方式来引用控制器。此方法仅使用一个冒号 (如 service_name:indexAction) 把控制器作为服务来引入 (参考 如何把控制器定义为服务)。

加载路由 ¶

Symfony 从一个 单一的 路由配置文件: app/config/routing.yml中加载你的程序中的全部路由。但从这个文件中,你可以加载任何一个 其他的 路由文件。实际上,Symfony默认从你 AppBundle 中的 Controller/ 目录中加载annotation路由配置,这就是为何Symfony能够看到我们的annotation路由:

1

2

3

4# app/config/routing.ymlapp:resource:"@AppBundle/Controller/"type: annotation

1

2

3

4

5

6

7

8

9

10

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">

1

2

3

4

5

6

7

8

9

10

11// app/config/routing.php

use Symfony\Component\Routing\RouteCollection;

$collection = new RouteCollection();

$collection->addCollection(

// second argument is the type, which is required to enable

// the annotation reader for this resource

$loader->import("@AppBundle/Controller/", "annotation")

);

return $collection;

路由加载的更多内容,包括如何为被加载的路由施以前缀,参考 如何将外部路由资源包容进来。

生成URL ¶

路由系统也可用来生成URL链接。现实中,路由是个双向系统:把URL映射到控制器,或把路由反解为URL。

要生成URL,你需要指定路由名称 (即 blog_show) 以及用在此路由路径中的任意通配符(如 slug = my-blog-post) 的值。有了这些信息,任何URL皆可轻松生成:

1

2

3

4

5

6

7

8

9

10

11

12

13class MainController extends Controller

{

public function showAction($slug)

{

// ...

// /blog/my-blog-post

$url = $this->generateUrl(

'blog_show',

array('slug' => 'my-blog-post')

);

}

}

Note

定义在

generateUrl() 方法是以下代码的快捷方式:

1

2

3

4$url = $this->container->get('router')->generate(

'blog_show',

array('slug' => 'my-blog-post')

);

生成带有Query字符串的URL ¶

generate() 方法接收通配符的值的数组,以生成URI。但如果你传入额外的值,它们将被添加到URI中,作为query string(查询字符串):

1

2

3

4

5$this->get('router')->generate('blog', array(

'page' => 2,

'category' => 'Symfony'

));

// /blog/2?category=Symfony

从模板中生成URL ¶

在Twig中生成URL,参考模板文章: 链到页面。如果你需要在JavaScript中生成URL,参考 如何在JavaScript中生成路由链接。

生成绝对URL ¶

默认时,路由生成相对链接 (如 /blog)。在控制器中把 UrlGeneratorInterface::ABSOLUTE_URL 作为 generateUrl()

方法的第三个参数传入:

1

2

3

4use Symfony\Component\Routing\Generator\UrlGeneratorInterface;

$this->generateUrl('blog_show', array('slug' => 'my-blog-post'), UrlGeneratorInterface::ABSOLUTE_URL);

// http://www.example.com/blog/my-blog-post

Note

用于生成绝对链接的host主机名是通过 Request 对象自动侦测的。若要从web上下文之外来生成绝对URL (例如在命令行中),它不会工作。参考 如何在命令行中生成URL 以了解如何解决此问题。

除错 ¶

这里是一些你在使用路由时常见的报错信息:

Controller "AppBundleControllerBlogController::showAction()" requires that you provide a value for the "$slug" argument.

这个报错仅在你的控制器方法有一个参数时才会发生 (如 $slug):

1

2

3

4public function showAction($slug)

{

// ..

}

但你的路由路径中 并没有 那个 {slug} 通配符 (如,它是 /blog/show)。可添加 {slug} 到路由路径中: /blog/show/{slug} 或者给予参数一个默认值 (即 $slug = null)。

Some mandatory parameters are missing ("slug") to generate a URL for route

"blog_show".

这说明你正在为 blog_show 路由生成链接,但你 并没有 在路由的路径中传入一个 slug 值 (它是必须的,因为路由有 {slug}通配符)。解决办法是是,在生成路由(URL)时传入 slug 值:

1

2

3

4$this->generateUrl('blog_show', array('slug' => 'slug-value'));

// or, in Twig / 或者在Twig中

// {{ path('blog_show', {'slug': 'slug-value'}) }}

路由的翻译 ¶

Symfony不支持基于语种以不同内容来定义路由。在那些场合下,你可以为每个控制器定义多个路由,每一个路由支持其所对应语言;或者使用社区的三方bundle来实现此功能,比如 JMSI18nRoutingBundle 和 BeSimpleI18nRoutingBundle。

总结 ¶

路由是一个将传入的请求之URL映射到用来处理该请求的控制器函数的系统。它允许你指定一个美观的URL,并使程序的功能性与URL“解耦”。路由是一个双向架构,意味着它也可以用来生成URL。

Keep Going! ¶

路由,核对完毕!现在,去解封 控制器 的威力。

php开源路由器,路由 - Symfony开源 - Symfony中国相关推荐

  1. Banana Pi BPI-R64 开源路由器 MTK MT7622 64位芯片方案设计,智能路由开发板

    Banana Pi BPI-R64 开源路由器 MTK MT7622 64位芯片方案设计,智能路由开发板 香蕉Pi R64是一个MTK7622 芯片路由器的开发板,它可以运行在各种开源操作系统上,包括 ...

  2. 五种常见的开源路由器第三方固件测评

    五种最常见的开源路由器第三方固件测评   除了智能手机外,路由器和无线接入点无疑是最常被破解和修改的消费级设备.一方面破解这些设备较为简单,另一方面破解.修改设备参数后能带来一系列好处,比如拥有更多的 ...

  3. 开源云联盟耿航:中国开源软件的发展趋势

    4月23日,以"软件定义存储未来"为题的首届软件定义存储峰会在深圳正式召开,会上,中国开源云联盟秘书长.Ceph中国社区联合创始人.腾讯云TVP耿航作为大会首位演讲嘉宾发表了< ...

  4. Apache RocketMQ 荣获 2021 中国开源云联盟优秀开源项目

    为推动国内开源生态产业发展,中国开源云联盟(China Open Source Cloud League,简称"COSCL")组织开展了 2021 杰出开源贡献者.优秀开源项目.最 ...

  5. “开源、共享、创新” 2020 中国.NET开发者大会小结

    大会的新闻稿在2020年12月31日正式发布:开源·共享·创新|2020年中国.NET开发者大会圆满收官! , 本文是这篇新闻的补充性文章,仅代表个人对大会的各方面分享内容的一个小结. 在2019年上 ...

  6. 你不该错过的2020中国开源年报,填开源开发者问卷,成为国内开源的见证者

    点击上方"开源社"关注我们 | 作者:王伟 | 编辑:黄欣宜 | 设计:冯艺怡 | 责编:王玥敏 卷首语 一年一度的中国开源年报再度启动- 中国开源年报由开源社发起.旨在从多种维度 ...

  7. “开源、共享、创新”, 中国最具前景开发者峰会落幕魔都

    点击蓝字关注我们 作者:张善友 编辑:吴珊珊 校正:潘淳.许豪.刘腾飞.朱兴亮.郑和阳.张潇.韩骏 问卷制作:杨乐 2019年,注定会是 .NET Core 社区发展的关键一年,诸多重大事件在这一年发 ...

  8. 开源虚拟示波器-_一个新的开源数据库,TP-Link路由器上的开源固件以及更多新闻

    开源虚拟示波器- 在本周的开源新闻摘要中,我们介绍了Attic Labs的新开源数据库,TP-Link路由器上的开源固件等. 2016年7月31日至8月6日的开源新闻摘要 Attic Labs宣布新的 ...

  9. 2022 CCF中国开源大会—开放原子开源创新发展论坛即将开幕

    开源已经成为全球数字科技创新发展的大趋势."行业发展,人才先行",开源生态的繁荣发展,离不开人才的培育.推进开源教育.建立产学研一体化开源创新人才培养体系显得至关重要.开放原子开源 ...

最新文章

  1. Python Numpy介绍
  2. python游戏程序-python游戏程序
  3. 编程小白的第一本python入门书-《编程小白的第一本Python入门书》读书笔记
  4. 转:linux内核驱动中_IO, _IOR, _IOW, _IOWR 宏的用法与解析
  5. 知识图谱学习笔记-非结构化数据处理
  6. 【视频】v-bind的使用
  7. 7搭建zabbix_监控03分布式监控Zabbix
  8. IntelliJ IDEA for Mac 项目窗口详解(Project Windows)
  9. 台积电:高雄地震对生产影响比预期略高
  10. DesiredCapabilities内容详解(摘)
  11. 变分模态分解(VMD)
  12. Figma插件开发-生成Gif
  13. (ICPR-2021)使用胶囊的多尺度部分表示变换的步态识别
  14. Win10:文件夹取消隐藏选项为灰色,无法勾选
  15. Nebula Graph介绍和SpringBoot环境连接和查询
  16. 基于SSM框架的毕业设计管理系统 毕业设计-附源码211633
  17. 微软的sdk以及azure_.NET的Azure SDK:关于困难错误搜索的故事
  18. 养殖环控程序 三菱plc可以带物联网模块,7寸触摸屏程序
  19. java调用阿里云短信服务器-发送短信
  20. Amlogic A311D2 八核 Arm 处理器支持高达 16GB RAM

热门文章

  1. Leetcode 535.TinyURL的加密与解密
  2. 人人都能看懂的LSTMGRU
  3. python : 自定义可迭代类,__iter__ ,__next__的作用
  4. python : os.path 相关操作
  5. python关于sorted里面key,reverse以及lamdba,operator这几个鸟人
  6. C++primer 16.1.2节练习
  7. Test: 为WLW添加源代码着色插件WindowsLiveWriter.CNBlogs.CodeHighlighter
  8. KM算法(最优匹配)
  9. Ext 学习之 Store
  10. mongodb系列~mongodb的副本集搭建和原理