8.5. 路由协议详解

默认路由协议

默认的路由协议Yaf_Route_Static, 就是分析请求中的request_uri, 在去除掉base_uri以后, 获取到真正的负载路由信息的request_uri片段, 具体的策略是, 根据"/"对request_uri分段, 依次得到Module,Controller,Action, 在得到Module以后, 还需要根据Yaf_Application::$modules来判断Module是否是合法的Module, 如果不是, 则认为Module并没有体现在request_uri中, 而把原Module当做Controller, 原Controller当做Action:

例 8.4. 默认路由协议

     
     <?php
     /**
      * 对于请求request_uri为"/ap/foo/bar/dummy/1"
      * base_uri为"/ap"
      * 则最后参加路由的request_uri为"/foo/bar/dummy/1"
      * 然后, 通过对URL分段, 得到如下分节
      * foo, bar, dummy, 1
      * 然后判断foo是不是一个合法的Module, 如果不是, 则认为结果如下:
      */
      array(
        'module'     => '默认模块',
        'controller' => 'foo',
        'action'     => 'bar',
        'params'     => array(
             'dummy' => 1,
        )
     )

     /**
      * 而如果在配置文件中定义了ap.modules="Index,Foo",
      * 则此处就会认为foo是一个合法模块, 则结果如下
      */
      array(
        'module'     => 'foo',
        'controller' => 'bar',
        'action'     => 'dummy',
        'params'     => array(
             1 => NULL,
        )
     )
     
    


[重要] 重要
当只有一段路由信息的时候, 比如对于上面的例子, 请求的URI为/ap/foo, 则默认路由和下面要提到的Yaf_Route_Supervar会首先判断ap.action_prefer, 如果为真, 则把foo当做Action, 否则当做Controller

Yaf_Route_Simple

Yaf_Route_Simple是基于请求中的query string来做路由的, 在初始化一个Yaf_Route_Simple路由协议的时候, 我们需要给出3个参数, 这3个参数分别代表在query string中Module, Controller, Action的变量名:

例 8.5. Yaf_Route_Simple

     
     <?php
     /**
      * 指定3个变量名
      */
      $route = new Yaf_Route_Simple("m", "c", "a");
      $router->addRoute("name", $route);
     /**
      * 对于如下请求: "http://domain.com/index.php?c=index&a=test
      * 能得到如下路由结果
      */
      array(
        'module'     => '默认模块',
        'controller' => 'index',
        'action'     => 'test',
        )
     
    


[注意] 注意
只有在query string中不包含任何3个参数之一的情况下, Yaf_Route_Simple才会返回失败, 将路由权交给下一个路由协议.

Yaf_Route_Supervar

Yaf_Route_Supervar和Yaf_Route_Simple相似, 都是在query string中获取路由信息, 不同的是, 它获取的是一个类似包含整个路由信息的request_uri

例 8.6. Yaf_Route_Supervar

     
     <?php
     /**
     * 指定supervar变量名
     */
     $route = new Yaf_Route_Supervar("r");
     $router->addRoute("name", $route);
     /**
     * 对于如下请求: "http://domain.com/index.php?r=/a/b/c
     * 能得到如下路由结果
     */
     array(
     'module'     => 'a',
     'controller' => 'b',
     'action'     => 'c',
     )
     
    


[注意] 注意
在query string中不包含supervar变量的时候, Yaf_Route_Supervar会返回失败, 将路由权交给下一个路由协议.

Yaf_Route_Map

Yaf_Route_Map议是一种简单的路由协议, 它将REQUEST_URI中以'/'分割的节, 组合在一起, 形成一个分层的控制器或者动作的路由结果. Yaf_Route_Map的构造函数接受俩个参数, 第一个参数表示路由结果是作为动作的路由结果,还是控制器的路由结果. 默认的是动作路由结果. 第二个参数是一个字符串, 表示一个分隔符, 如果设置了这个分隔符, 那么在REQUEST_URI中, 分隔符之前的作为路由信息载体, 而之后的作为请求参数.

例 8.7. 映射路由协议

     
     <?php
     /**
      * 对于请求request_uri为"/ap/foo/bar"
      * base_uri为"/ap"
      * 则最后参加路由的request_uri为"/foo/bar"
      * 然后, 通过对URL分段, 得到如下分节
      * foo, bar
      * 组合在一起以后, 得到路由结果foo_bar
      * 然后根据在构造Yaf_Route_Map的时候, 是否指明了控制器优先,
      * 如果没有, 则把结果当做是动作的路由结果
      * 否则, 则认为是控制器的路由结果
      * 默认的, 控制器优先为FALSE
      */
     
    


Yaf_Route_Rewrite

Yaf_Route_Rewrite是一个强大的路由协议, 它能满足我们绝大部分的路由需求:

例 8.8. Yaf_Route_Rewrite

     
     <?php
     //创建一个路由协议实例
     $route = new Yaf_Route_Rewrite(
       'product/:ident',
       array(
         'controller' => 'products',
         'action' => 'view'
       )
     );
     //使用路由器装载路由协议
     $router->addRoute('product', $route);
     
    


在这个例子中, 我们试图匹配Url指定到一个单一的产品, 就像http://domain.com/product/choclolat-bar. 为了实现这点, 我们在路由协议中传递了2个变量到路由协议Yaf_Route_Rewrite的构造函数其中. 第一个变量('product/:indent')就是匹配的路径, 第二个变量(array变量)是路由到的动作控制器; 路径使用一个特别的标识来告诉路由协议如何匹配到路径中的每一个段,这个标识有有两种,可以帮助我们创建我们的路由协议,如下所示:

a) :
b) *

冒号(:)指定了一个段,这个段包含一个变量用于传递到我们动作控制器中的变量,我们要设置好事先的变量名,比如在上面我们的变量名就是'ident',因此,倘若我们访问http://domian.com/product/chocoloate-bar将会创建一个变量名为ident并且其值是'chocoloate-bar'的变量,我们然后就可以在我们的动作控制器ProductsController/viewAction下获取到它的值:$this->getRequest()->getParam('ident');

星号(*)被用做一个通配符, 意思就是在Url中它后面的所有段都将作为一个通配数据被存储. 例如,如果我们有路径'path/product/:ident/*'(就是路由协议中设置的第一个变量), 并且我们访问的Url为http://domain.com/product/chocolate-bar/test/value1/another/value2,那么所有的在'chocolate-bar'后面的段都将被做成变量名/值对,因此这样会给我们下面的结果:

    
    ident = chocolate-bar
    test = value1
    another = value2
    
   

这种行为也就是我们平常默认使用的路由协议的行为,记住变量名/值要成对出现,否则像/test/value1/这样的将不会这种另一个变量,我们有静态的路由协议部分,这些部分简单地被匹配来满足我们的路由协议,在我们的例子中,静态部分就是product; 就像你现在看到的那样,我们的Yaf_Route_Rewrite路由协议提供给我们极大的灵活性来控制我们的路由

Yaf_Route_Regex

到目前为止,我们之前的路由协议都很好的完成了基本的路由操作,我们常用的也是他们,然而它们会有一些限制,这就是我们为什么要引进正则路由(Yaf_Route_Regex)的原因. 正则路由给予我们preg正则的全部力量,但同时也使得我们的路由协议变得更加复杂了一些.即使是他们有点复杂,我还是希望你能好好掌握它,因为它比其他路由协议要灵活一点点. 一开始,我们先对之前的产品案例改用使用正则路由:

例 8.9. Yaf_Route_Regex

     
   <?php
   $route = new Yaf_Route_Regex(
     'product/([a-zA-Z-_0-9]+)',
     array(
      'controller' => 'products',
      'action' => 'view'
     )
   );
   $router->addRoute('product', $route);
     
    


你可以看到,我们现在移动我们的正则到我们的path(构造函数的第一个参数)中来了,就像之前的那样,这个正则路由协议现在应该是匹配是一个数字、字母、-和_组成的ident变量的字符提供给我们,但是,你一定会问,ident变量在哪呢?好,如果你使用了这个正则路由协议,我们可以通过变量1(one)来获取其值,即可以在控制器里用:$this->getRequest()->getParam(1)来获取,其实这里如果看过正则的都知道这就是反向引用中的\1.然而,你一定会想为什么要定义的这么的垃圾,我们不能够记住或者弄清每一个数字代表的是什么变量(其实我刚开始看的时候也是一样的感受).为了改变这点,正则路由协议的构造函数提供了第3个参数来完成数字到变量名的映射:

例 8.10. Yaf_Route_Regex

     
   <?php
   $route = new Yaf_Route_Regex(
     'product/([a-zA-Z-_0-9]+)',
     array(
       'controller' => 'products',
       'action' => 'view'
     ),
     array(
       //完成数字到字符变量的映射
       1 => 'ident'
     )
   );
   $router->addRoute('product', $route);
     
    


这样,我们就简单的将变量1映射到了ident变量名,这样就设置了ident变量,同时你也可以在控制器里面获取到它的值.