Symfony2 学习笔记之系统路由

mfony2 学习笔记之系统路由

漂亮的URL绝对是一个严肃的web应用程序必须做到的,这种方式使index.php?article_id=57这类的丑陋URL被隐藏,由更受欢迎的像 /read/intro-to-symfony 来替代。

拥有灵活性更为重要,如果你要改变一个页面的URL,比如从/blog 到 /new 怎么办?
有多少链接需要你找出来并更新呢? 如果你使用Symfony的router,这种改变将变得很简单。

Symfony2 router让你定义更具创造力的URL,你可以map你的应用程序的不同区域。
创建复杂的路由并map到controllers并可以在模板和controllers内部生成URLs
从bundles(或者其他任何地方)加载路由资源
调试你的路由

路由活动
一个路径是一个从URL 模式到一个controller的绑定。
比如假设你想匹配任何像 /blog/my-post 或者 /blog/all-about-symfony的路径并把它们发送到一个controller在那里可以查找并渲染blog实体。
该路径很简单:
YAML格式:

# app/config/routing.yml
blog_show:
pattern: /blog/{slug}
defaults: {_controller: AcmeBlogBundle:Blog:show }

XML格式:

<!-- 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_show" pattern="/blog/{slug}">
<default key="_controller">AcmeBlogBundle:Blog:show</default>
</route>
</routes>

PHP代码格式:

// app/config/routing.php
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;

$collection = new RouteCollection();
$collection->add(‘blog_show‘, new Route(‘/blog/{slug}‘, array(
         ‘_controller‘ => ‘AcmeBlogBundle:Blog:show‘,
)));

blog_show路径定义了一个URL模式,它像/blog/* 这里的通配符被命名为slug。对于URL/blog/my-blog-post,slug变量会得到值 my-blog-post。

_controller参数是一个特定的键,它告诉Symfogy当一个URL匹配这个路径时哪个controller将要被执行。
_controller字符串被称为逻辑名。它的值会按照特定的模式来指定具体的PHP类和方法。

// src/Acme/BlogBundle/Controller/BlogController.php

namespace Acme\BlogBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class BlogController extends Controller
{
    public function showAction($slug)
    {
        $blog = // use the $slug variable to query the database

        return $this->render(‘AcmeBlogBundle:Blog:show.html.twig‘, array(
            ‘blog‘ => $blog,
        ));
    }
}

现在当你再访问/blog/my-post 时,showAction controller将被执行并且$slug变量的值为my-post

Symfogy2 的路由器目标:映射一个请求的URL到controller。

路由:内部的秘密
当一个请求发送到应用程序时,它包含一个客户端想要获取资源的地址。这个地址叫做URL或者URI。可能是/contact,/blog/read-me或者其它样式。
GET /blog/my-blog-post
Symfony2 路由系统的目标是解析这些URL并决定哪个controller应该被执行来回复该请求。
整个路由过程可以分为:
1.请求被Symfony2的前端控制器(app.php)处理。
2.Symfony2核心(kernel)要求路由器检查请求。
3.路由器匹配接收到的URL到一个特定的路径并返回有关信息,包括应该被执行的controller。
4.Symfony2核心执行该controller,该controller最终会返回一个Response对象。
路由器层就是一个把接收到的URL转换为要执行的特定controller的工具。

创建路由
Symfony会从一个单独的路由配置文件中加载你应用程序的所有路由。该文件通常为 app/config/routing.yml。 它可以被配置成包括XML或者PHP文件等文件。
YAML格式:

# app/config/config.yml
framework:
    # ...
    router:        { resource: "%kernel.root_dir%/config/routing.yml" }

XML格式:

<!-- app/config/config.xml -->
<framework:config ...>
    <!-- ... -->
    <framework:router resource="%kernel.root_dir%/config/routing.xml" />
</framework:config>

PHP代码格式:

// app/config/config.php
$container->loadFromExtension(‘framework‘, array(
    // ...
    ‘router‘        => array(‘resource‘ => ‘%kernel.root_dir%/config/routing.php‘),
));

基础路由配置
定义一个路由很简单,通常一个应用程序拥有很多路由。一个基础路由是由两部分组成:pattern部分和defaults数组部分。
比如:
YAML格式:

_welcome:
    pattern:   /
    defaults:  { _controller: AcmeDemoBundle:Main:homepage }

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="_welcome" pattern="/">
        <default key="_controller">AcmeDemoBundle:Main:homepage</default>
    </route>

</routes>

PHP代码格式:

use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;

$collection = new RouteCollection();
$collection->add(‘_welcome‘, new Route(‘/‘, array(
    ‘_controller‘ => ‘AcmeDemoBundle:Main:homepage‘,
)));

return $collection;

该路由匹配首页(/)并映射到AcmeDemoBundle:Main:homepage controller。_controller字符串被Symfony2翻译成一个相应的PHP函数并被执行。

带占位符路由
当然,路由系统支持更多有趣的路由。许多路由会包含一个或者多个被命名的通配符占位符。
YAML格式:

blog_show:
    pattern:   /blog/{slug}
    defaults:  { _controller: AcmeBlogBundle:Blog:show }

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_show" pattern="/blog/{slug}">
        <default key="_controller">AcmeBlogBundle:Blog:show</default>
    </route>
</routes>

PHP代码格式:

use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;

$collection = new RouteCollection();
$collection->add(‘blog_show‘, new Route(‘/blog/{slug}‘, array(
    ‘_controller‘ => ‘AcmeBlogBundle:Blog:show‘,
)));

return $collection;

该模式将匹配任何类似/blog/*形式的URL。匹配占位符{slug}的值将会在controller中被使用。换句话说,如果URL是/blog/hello-world,
则$slug变量值是hello-world, 该值将能在controller中被使用。该模式不会匹配像/blog, 因为默认情况下所有的占位符都是必须的。 当然可以通过在defaults数组中给这些占位符赋来改变它。

必需和可选占位符
我们来添加一个新的路由,显示所有可用的blog列表。
YAML格式:

blog:
    pattern:   /blog
    defaults:  { _controller: AcmeBlogBundle:Blog:index }

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" pattern="/blog">
        <default key="_controller">AcmeBlogBundle:Blog:index</default>
    </route>
</routes>

PHP代码格式:

use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;

$collection = new RouteCollection();
$collection->add(‘blog‘, new Route(‘/blog‘, array(
    ‘_controller‘ => ‘AcmeBlogBundle:Blog:index‘,
)));

return $collection;

到目前为止,我们的路由都是非常简单的路由模式。它们包含的非占位符将会被精确匹配。

如果你想该路由能够支持分页,比如让/blog/2 显示第二页的blog,那就需要为之前的路由添加一个新的{page}占位符。
YAML格式:

blog:
    pattern:   /blog/{page}
    defaults:  { _controller: AcmeBlogBundle:Blog:index }

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" pattern="/blog/{page}">
        <default key="_controller">AcmeBlogBundle:Blog:index</default>
    </route>
</routes>

PHP代码格式:

use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;

$collection = new RouteCollection();
$collection->add(‘blog‘, new Route(‘/blog/{page}‘, array(
    ‘_controller‘ => ‘AcmeBlogBundle:Blog:index‘,
)));

return $collection;

跟之前的{slug}占位符一样{page}占位符将会在你的controller内部可用,它的值可以用于表示要显示的blog值的页码。但是要清楚,因为占位符默认情况下都是必需的,该路由也将不再匹配之前的/blog URL,这时候你如果还像看第一页的话,就必须通过/blog/1 URL来访问了。要解决该问题,可以在该路由的defaults数组中指定{page}的默认值。

YAML格式:

blog:
    pattern:   /blog/{page}
    defaults:  { _controller: AcmeBlogBundle:Blog:index, page: 1 }

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" pattern="/blog/{page}">
        <default key="_controller">AcmeBlogBundle:Blog:index</default>
        <default key="page">1</default>
    </route>
</routes>

PHP代码格式:

use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;

$collection = new RouteCollection();
$collection->add(‘blog‘, new Route(‘/blog/{page}‘, array(
    ‘_controller‘ => ‘AcmeBlogBundle:Blog:index‘,
    ‘page‘ => 1,
)));

return $collection;

通过添加page到defaults键, {page}占位符就不再是必需的。这时候 /blog将会被匹配并且page参数被设置为1,URL /blog/2 也会被匹配。

添加要求约束
看看下面这些路由:
YAML格式:

blog:
    pattern:   /blog/{page}
    defaults:  { _controller: AcmeBlogBundle:Blog:index, page: 1 }

blog_show:
    pattern:   /blog/{slug}
    defaults:  { _controller: AcmeBlogBundle:Blog:show }

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" pattern="/blog/{page}">
        <default key="_controller">AcmeBlogBundle:Blog:index</default>
        <default key="page">1</default>
    </route>

    <route id="blog_show" pattern="/blog/{slug}">
        <default key="_controller">AcmeBlogBundle:Blog:show</default>
    </route>
</routes>

PHP代码格式:

use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;

$collection = new RouteCollection();
$collection->add(‘blog‘, new Route(‘/blog/{page}‘, array(
    ‘_controller‘ => ‘AcmeBlogBundle:Blog:index‘,
    ‘page‘ => 1,
)));

$collection->add(‘blog_show‘, new Route(‘/blog/{show}‘, array(
    ‘_controller‘ => ‘AcmeBlogBundle:Blog:show‘,
)));

return $collection;

你发现问题了吗?注意这两个路由都能匹配像/blog/* 类型的URL。Symfony只会选择第一个与之匹配的路由。

换句话说,blog_show将永远不会被像/blog/* 类型的URL匹配。而像 /blog/my-blog-post这样的URL也会被blog路由匹配,并且page变量会获得my-blog-post这样的值。
这肯定不可以,那么怎么办呢?答案是给路由添加约束要求requirements。
在blog路由中占位符{page}理想状态下只匹配整数值。幸运的是正则表达可以很容易的满足这一要求。
YAML格式:

blog:
    pattern:   /blog/{page}
    defaults:  { _controller: AcmeBlogBundle:Blog:index, page: 1 }
    requirements:
        page:  \d+

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" pattern="/blog/{page}">
        <default key="_controller">AcmeBlogBundle:Blog:index</default>
        <default key="page">1</default>
        <requirement key="page">\d+</requirement>
    </route>
</routes>

PHP代码格式:

use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;

$collection = new RouteCollection();
$collection->add(‘blog‘, new Route(‘/blog/{page}‘, array(
    ‘_controller‘ => ‘AcmeBlogBundle:Blog:index‘,
    ‘page‘ => 1,
), array(
    ‘page‘ => ‘\d+‘,
)));

return $collection;

这里 \d+ 约束是一个正则表达式,它指定了{page}只接受整数。这样像/blog/my-blog-post就不再被匹配了。这时候,它才会被blog_show路由匹配。因为参数的约束都是正则表达式,所以其复杂程度和灵活性都有你来决定了。

假设home页使用两种语言则可以这样配置路由:
YAML格式:

homepage:
    pattern:   /{culture}
    defaults:  { _controller: AcmeDemoBundle:Main:homepage, culture: en }
    requirements:
        culture:  en|fr

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="homepage" pattern="/{culture}">
        <default key="_controller">AcmeDemoBundle:Main:homepage</default>
        <default key="culture">en</default>
        <requirement key="culture">en|fr</requirement>
    </route>
</routes>

PHP代码格式:

use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;

$collection = new RouteCollection();
$collection->add(‘homepage‘, new Route(‘/{culture}‘, array(
    ‘_controller‘ => ‘AcmeDemoBundle:Main:homepage‘,
    ‘culture‘ => ‘en‘,
), array(
    ‘culture‘ => ‘en|fr‘,
)));

return $collection;

添加HTTP 方法约束
除了URL,你还可以匹配请求的方法(GET,HEAD,POST,PUT,DELETE等)。假设你有一个联系表单有两个controller,一个用于显示表单(使用GET请求)一个用于处理提交的表单(POST请求)。它的配置如下:
YAML格式:

contact:
    pattern:  /contact
    defaults: { _controller: AcmeDemoBundle:Main:contact }
    requirements:
        _method:  GET

contact_process:
    pattern:  /contact
    defaults: { _controller: AcmeDemoBundle:Main:contactProcess }
    requirements:
        _method:  POST

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="contact" pattern="/contact">
        <default key="_controller">AcmeDemoBundle:Main:contact</default>
        <requirement key="_method">GET</requirement>
    </route>

    <route id="contact_process" pattern="/contact">
        <default key="_controller">AcmeDemoBundle:Main:contactProcess</default>
        <requirement key="_method">POST</requirement>
    </route>
</routes>

PHP代码格式:

use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;

$collection = new RouteCollection();
$collection->add(‘contact‘, new Route(‘/contact‘, array(
    ‘_controller‘ => ‘AcmeDemoBundle:Main:contact‘,
), array(
    ‘_method‘ => ‘GET‘,
)));

$collection->add(‘contact_process‘, new Route(‘/contact‘, array(
    ‘_controller‘ => ‘AcmeDemoBundle:Main:contactProcess‘,
), array(
    ‘_method‘ => ‘POST‘,
)));

return $collection;

尽管这两个路由拥有同一个URL模式定义(/contact),但是第一个路由只会匹配GET请求,而第二个只会匹配POST请求。这就意味着你可以通过同一个URL来显示表单并提交表单,而用不同的controller对他们进行处理。如果没有指定_method约束,那么该路由会匹配所有请求方法。跟其它约束一样,_method约束也接受正则表达式,如果只想匹配GET或者POST那么你可以用GET|POST

 

高级路由例子
Symfony2中具备一切让你创建任何形式路由的条件。
YAML格式:

article_show:
  pattern:  /articles/{culture}/{year}/{title}.{_format}
  defaults: { _controller: AcmeDemoBundle:Article:show, _format: html }
  requirements:
      culture:  en|fr
      _format:  html|rss
      year:     \d+

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="article_show" pattern="/articles/{culture}/{year}/{title}.{_format}">
        <default key="_controller">AcmeDemoBundle:Article:show</default>
        <default key="_format">html</default>
        <requirement key="culture">en|fr</requirement>
        <requirement key="_format">html|rss</requirement>
        <requirement key="year">\d+</requirement>
    </route>
</routes>

PHP代码格式:

use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;

$collection = new RouteCollection();
$collection->add(‘homepage‘, new Route(‘/articles/{culture}/{year}/{title}.{_format}‘, array(
    ‘_controller‘ => ‘AcmeDemoBundle:Article:show‘,
    ‘_format‘ => ‘html‘,
), array(
    ‘culture‘ => ‘en|fr‘,
    ‘_format‘ => ‘html|rss‘,
    ‘year‘ => ‘\d+‘,
)));

return $collection;

上面的路由,在匹配时只会匹配{culture}部分值为en或者fr并且{year}的值为数字的URL。该路由还告诉我们,可以用在占位符之间使用区间代替斜线。

它能够匹配如下URL:
/articles/en/2010/my-post
/articles/fr/2010/my-post.rss

这其中有个特殊的路由参数 _format,在使用该参数时,其值变为请求格式。这种请求格式相当于Respose对象的Content-Type,比如json请求格式会翻译成一个Content-Type为application/json.该参数可以用于在controller中为每个_format渲染一个不同的模板。它是一个很强的方式来渲染同一个内容到不同的格式。

特殊的路由参数:
正如你所看到的,每一个路由参数或者默认值最终都是作为一个controller方法输入参数被使用。另外,有三个参数比较特别,它们每一个都在你的应用程序中增加一个唯一功能。
_controller: 这个参数决定了当路由匹配时,哪个controller被执行。
_format: 用于设置请求格式。
_locale: 用于在session上设置本地化。

Controller的命名模式:
每一个路由必须有一个_controller参数,它决定了当路由匹配时哪个controller应该被执行。该参数使用单一的字符串模式,被称为logical controller name。
通过它Symfony可以映射到一个特定的PHP方法和类。该模式有三部分,每一部分用冒号分割开:
bundle:controller:action

比如_controller 的值为 AcmeBlogBundle:Blog:show 意思是AcmeBlogBundle bundle中BlogController类里面的showAction方法。

// src/Acme/BlogBundle/Controller/BlogController.php

namespace Acme\BlogBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class BlogController extends Controller
{
    public function showAction($slug)
    {
        // ...
    }
}

Symfony会自动把它们的添加相应的后缀,Blog=>BlogController, show => showAction。

你也可以使用它的完全限定名和方法来给_controller赋值,Acme\BlogBundle\Controller\BlogController::showAction 但一般为了简洁灵活而是用逻辑名称。另外除了上面两种形式外,Symfony还支持第三种方式只有一个冒号分割符,如service_name:indexAction来为_controller赋一个作为服务使用的controller。

路由参数和控制器参数
路由参数非常重要,因为每一个路由参数都会转变成一个控制器参数被在方法中使用。

public function showAction($slug)
{
  // ...
}

事实上,全部的defaults集合和表单的参数值合并到一个单独的数组中。这个数组中的每个键都会成为controller方法的参数。换句话说,你的controller方法的每一个参数,Symfony都会从路由参数中查找并把找到的值赋给给参数。上面例子中的变量 $culture, $year,$title,$_format,$_controller 都会作为showAction()方法的参数。因为占位符和defaults集合被合并到一起,即使$_controller变量也是一样。你也可以使用一个特殊的变量$_route 来指定路由的名称。

包括外部路由资源
所有的路由资源的都是通过一个单一的配置文件导入的。通常是app/config/routing.yml。当然你可能想从别处导入路由资源,比如你定义的bundle中的路由资源,你可以这样导入:
YAML格式:

# app/config/routing.yml
acme_hello:
    resource: "@AcmeHelloBundle/Resources/config/routing.yml"

XML格式:

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

    <import resource="@AcmeHelloBundle/Resources/config/routing.xml" />
</routes>

PHP代码格式:

// app/config/routing.php
use Symfony\Component\Routing\RouteCollection;

$collection = new RouteCollection();
$collection->addCollection($loader->import("@AcmeHelloBundle/Resources/config/routing.php"));

return $collection;

在使用YAML导入资源时,键(比如acme_hello)是没有意义的,只是用来保证该资源唯一不被其它行覆盖。使用resources key加载给定的路由资源。在这个示例中资源是一个全路径文件,@AcmeHelloBundle是简写语法,它会被指向bundle路径。被导入的文件内容如下:

YAML格式:

 # src/Acme/HelloBundle/Resources/config/routing.yml
acme_hello:
     pattern:  /hello/{name}
     defaults: { _controller: AcmeHelloBundle:Hello:index }

XML格式:

<!-- src/Acme/HelloBundle/Resources/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="acme_hello" pattern="/hello/{name}">
        <default key="_controller">AcmeHelloBundle:Hello:index</default>
    </route>
</routes>

PHP代码格式:

// src/Acme/HelloBundle/Resources/config/routing.php
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;

$collection = new RouteCollection();
$collection->add(‘acme_hello‘, new Route(‘/hello/{name}‘, array(
    ‘_controller‘ => ‘AcmeHelloBundle:Hello:index‘,
)));

return $collection;

这个文件中的路由会被解析并跟主要的路由文件内容一起被加载。

给导入的路由资源添加前缀
你可以为导入的路由资源选择一个前缀,比如说假设你想acme_hello路由有一个这样的 匹配模式:/admin/hello/{name} 而不是直接的 /hello/{name}
那么你在导入它的时候可以为其指定prefix。
YAML格式:

# app/config/routing.yml
acme_hello:
    resource: "@AcmeHelloBundle/Resources/config/routing.yml"
    prefix:   /admin

XML格式:

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

    <import resource="@AcmeHelloBundle/Resources/config/routing.xml" prefix="/admin" />
</routes>

PHP代码格式:

// app/config/routing.php
use Symfony\Component\Routing\RouteCollection;

$collection = new RouteCollection();
$collection->addCollection($loader->import("@AcmeHelloBundle/Resources/config/routing.php"), ‘/admin‘);

return $collection;

当该外部路由资源加载的时候字符串 /admin 将被插入到匹配模式的前面。

可视化并调试路由
当你添加和个性化路由时,能够看到它并能获取一些细节信息将是非常有用的。一个好的查看你应用程序的路由的方法是通过router:debug 命令行工具。
在你项目目录下执行如下命令:

$ php app/console router:debug

将会输出你应用程序的所有路由。你也可以在该命令后面添加某个路由的名字来获取单个路由信息

$ php app/console router:debug article_show

生成URL

一个路由系统应该也能用来生成URL。事实上,路由系统是一个双向的系统,映射URL到controller+parameters 和 回对应到 一个URL。可以使用match()和generate()方法来操作。比如:

$params = $router->match(‘/blog/my-blog-post‘);
// array(‘slug‘ => ‘my-blog-post‘, ‘_controller‘ => ‘AcmeBlogBundle:Blog:show‘)

$uri = $router->generate(‘blog_show‘, array(‘slug‘ => ‘my-blog-post‘));
// /blog/my-blog-post

要生成一个URL,你需要指定路由的名称(比如 blog_show)和任意的通配符(比如:slug=my-blog-post)作为参数。通过这些信息,可以生成任意的URL。

class MainController extends Controller
{
    public function showAction($slug)
    {
      // ...

      $url = $this->get(‘router‘)->generate(‘blog_show‘, array(‘slug‘ => ‘my-blog-post‘));
    }
}

那么如何从模板内部来生成URL呢?如果你的应用程序前端使用了AJAX请求,你也许想能够基于你的路由配置在javascript中生成URL,通过使用

FOSJsRoutingBundle(https://github.com/FriendsOfSymfony/FOSJsRoutingBundle) 你可以做到:

var url = Routing.generate(‘blog_show‘, { "slug": ‘my-blog-post‘});

生成绝对路径的URL
默认的情况下,路由器生成相对路径的URL(比如 /blog).要生成一个绝对路径的URL,只需要传入一个true到generate方法作为第三个参数值即可。

$router->generate(‘blog_show‘, array(‘slug‘ => ‘my-blog-post‘), true);
// http://www.example.com/blog/my-blog-post

当生成一个绝对路径URL时主机是当前请求对象的主机,这个是基于PHP提供的服务器信息自动决定的。当你需要为运行子命令行的脚本生成一个绝对URL时,你需要在Request对象上手动设置期望的主机头。

$request->headers->set(‘HOST‘, ‘www.example.com‘);

生成带有查询字符串的URL
generate()带有一个数组通配符值来生成URI。 但是如果你传入额外的值,它将被添加到URI作为查询字符串:

$router->generate(‘blog‘, array(‘page‘ => 2, ‘category‘ => ‘Symfony‘));
// /blog/2?category=Symfony

从模板中生成URL
最常用到生成URL的地方是从模板中链接两个页面时,这来需要使用一个模板帮助函数:
Twig格式:

<a href="{{ path(‘blog_show‘, { ‘slug‘: ‘my-blog-post‘ }) }}">
  Read this blog post.
</a>

PHP格式:

<a href="<?php echo $view[‘router‘]->generate(‘blog_show‘, array(‘slug‘ => ‘my-blog-post‘)) ?>">
    Read this blog post.
</a>

也可以生成绝对路径:

Twig格式:

<a href="{{ url(‘blog_show‘, { ‘slug‘: ‘my-blog-post‘ }) }}">
  Read this blog post.
</a>

PHP格式:

<a href="<?php echo $view[‘router‘]->generate(‘blog_show‘, array(‘slug‘ => ‘my-blog-post‘), true) ?>">
    Read this blog post.
</a>

强制路由使用HTTPS或者HTTP

有时候为了安全起见,你需要你的站点必须使用HTTPS协议访问。这时候路由组件可以通过_scheme 约束来强迫URI方案。比如:

YAML格式:

secure:
    pattern:  /secure
    defaults: { _controller: AcmeDemoBundle:Main:secure }
    requirements:
        _scheme:  https

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="secure" pattern="/secure">
        <default key="_controller">AcmeDemoBundle:Main:secure</default>
        <requirement key="_scheme">https</requirement>
    </route>
</routes>

PHP代码格式:

use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;

$collection = new RouteCollection();
$collection->add(‘secure‘, new Route(‘/secure‘, array(
    ‘_controller‘ => ‘AcmeDemoBundle:Main:secure‘,
), array(
    ‘_scheme‘ => ‘https‘,
)));

return $collection;

上面的路由定义就是强迫secure路由使用HTTPS协议访问。

反之,当生成secure 的URL的时候,路由系统会根据当前的访问协议方案生成相应的访问协议。比如当前是HTTP,则会自动生成HTTPS访问;如果是HTTPS访问,那么就也会相应的生成HTTPS访问。

# 如果方案是 HTTPS
{{ path(‘secure‘) }}
# 生成 /secure

# 如果方案是 HTTP
{{ path(‘secure‘) }}
# 生成 https://example.com/secure

当然你也可以通过设置_scheme为HTTP,来强制使用HTTP访问协议。除了上面说的强迫使用HTTPS协议访问的设置方法外,还有一种用于站点区域设置

使用requires_channel 比如你想让你站点中/admin 下面的所有路由都必须使用HTTPS协议访问,或者你的安全路由定义在第三方bundle时使用。

总结:

路由系统是一个为将接收的请求URL映射到被调用来处理该请求的controller函数的系统。它既能够让你生成漂亮的URL同时又能保持你的应用程序功能跟这些URL解耦。路由系统是双向机制的,也就是说它们也可以用来生成URL。

英文URL:http://symfony.com/doc/current/book/routing.html

Symfony2 学习笔记之系统路由

时间: 2024-10-14 14:14:25

Symfony2 学习笔记之系统路由的相关文章

Symfony2学习笔记之HTTP Cache

富web应用程序的本质意味着它们的动态.无论你的应用程序多么有效率,每个请求比起静态文件来说总会存在很多的耗费.对于大多数web程序来说,这没什么. Symfony2非常的轻快,无论你做些严重超载的请求,每个请求将会得到很快的回复,而不会对你的服务器造成压力.但是随着你站点的成长,负载将成为一个严重的问题.对每个请求处理应该只被正常执行一次.这就是缓存真正要达成的目标. 站在巨人肩膀上的缓存:提高一个应用程序执行效率的最有效方法是缓存一个页面的所有输出然后让后续的请求绕开整个应用程序.当然,这对

Symfony2学习笔记之表单

对于一个Web开发者来说,处理HTML表单是一个最为普通又具挑战的任务.Symfony2集成了一个Form组件,让处理表单变的容易起来.在这一节里,我们将从基础开始创建一个复杂的表单,学习表单类库中最重要的内容. Symfony2 的Form组件是一个独立的类库,你可以在Symfony2项目之外使用它. 创建一个简单的表单:假设你要创建一个应用程序的todo列表,需要显示一些任务.因为你的用户需要编辑和创建任务,所以你需要创建一个表单.在你开始之前,首先来看通用的Task类,用来表示和存储一个单

Symfony2学习笔记之数据库操作

数据库和Doctrine让我们来面对这个对于任何应用程序来说最为普遍最具挑战性的任务,从数据库中读取和持久化数据信息.幸运的是,Symfony和Doctrine进行了集成,Doctrine类库全部目标就是给你一个强大的工具,让你的工作更加容易. Doctrine是完全解耦与Symfony的,所以并不一定要使用它. 一个简单例子:一个产品,我们首先来配置数据库,创建一个Product对象,持久化它到数据库并把它读回来. 首先我们需要创建一个bundle: $php app/console gene

Symfony2 学习笔记之内部构件

Symfony2内部是怎样工作的以及我们如何来扩展它呢?从外部整体上看,symfony2代码是由许多独立的层构成,每一层都是建立在前一层基础之上.其中,自动加载时不受框架直接管理的,它完全是在UniversalClassLoader类和src/autoload.php文件的帮助下独立完成的. HttpFoundation 组件最深层次的是HttpFoundation组件,它提供了处理HTTP所需的主要对象.是一个对一些PHP函数和变量的面向对象抽象.包括:Request 类,抽象了PHP中主要的

Symfony2 学习笔记之插件格式

一个bundle类似于其它框架中的插件,但是比插件表现更好.它跟其它框架最主要的不同是在Symfony2中所有东西都是bundle,包括核心框架功能和你写的所有应用程序代码.Symfony2中,bundle可是一等公民.这给了你使用其它第三方开发的内容包或者分发你自己的bundle更多灵活性.你可以方便的选择哪些内容可以应用到你的程序中那些不用,来根据你的想法优化它们. 一个bundle就是一个目录,它具有很好的结构性,它能存放从类到controller和web资源等任何东西. 一个bundle

Symfony2学习笔记之事件分配器

----EventDispatcher组件使用 简介:       面向对象编程已经在确保代码的可扩展性方面走过了很长一段路.它是通过创建一些责任明确的类,让它们之间变得更加灵活,开发者可以通过继承这些类创建子类,来改变它们的行为.但是如果想将某个开发者的改变跟其它已经编写了自己子类的开发者共享,这种面向对象的继承就不再那么有用了. 举一个现实的实例,你想为你的项目提供一个插件系统.一个能够被添加到方法的插件,或者在方法执行的前后完成某些工作,而不会干扰到其它插件.这个通过单一的继承完成不是一个

Symfony2 学习笔记之控制器

一个controller是你创建的一个PHP函数,它接收HTTP请求(request)并创建和返回一个HTTP回复(Response).回复对象(Response)可以是一个HTML页面,一个XML文档,一个序列化的JSON数组,一个图片,一个重定向,一个404错误或者任何你想要的内容.controller中可以包含任何渲染你页面内容的所需要的逻辑. 下面是一个controller最简单的例子,仅仅打印一个Hello world! use Symfony\Component\HttpFounda

Symfony2学习笔记之数据校验

校验在web应用程序中是一个常见的任务.数据输入到表单需要被校验.数据在被写入数据库之前或者传入一个webservice时也需要被校验. Symfony2 配备了一个Validator 组件,它让校验工作变得简单易懂.该组件是基于JSR303 Bean校验规范.一个Java规范用在PHP中. 基本验证理解校验的最好方法是看它的表现.首先,假设你已经创建了一个用于你应用程序某个地方的PHP对象. //src/Acme/BlogBundle/Entity/Author.php namespace A

Symfony2 学习笔记之服务容器

现在的PHP应用程序都是面向对象开发,所以主要是由对象构成.有的对象可以方便的分发邮件信息而有的可能帮你把信息写入到数据库中.在你的应用程序中,你可能创建一个对象用于管理你的产品库存,或者另外一个对象处理来自第三方API的数据.重要的是现在应用程序要做的这些事情都是被组织到许许多多的对象中来处理它的每一项任务的. 我们将套路一下Symfony2中一个特殊的PHP对象,它帮助我们实例化,组织和获取你应用程序汇总的许多对象.这个对象叫做服务容器,它可以帮助你使用标准统一的方式来创建你程序中的对象.它