Yaf零基礎學習總結8-Yaf中的路由和路由協議

路由器主要負責解析一個請求而且決定什麼module、controller、action被請求;它同時也定義了一種方法來實現用戶自定義路由,這也使得它成爲最重要的一個MVC組組件。爲了方便自定義路由, Yaf摒棄了0.1版本中的自定義路由器方式, 而採用了更爲靈活的路由器和路由協議分離的模式。也就是一個固定不變的路由器, 配合各類可自定義的路由協議, 來實現靈活多變的路由策略. 

做爲一個應用中的路由組件是很重要的,理所固然的路由組件是抽象的,這樣容許做爲開發者的咱們很容易的設計出咱們自定義的路由協議.然而,默認的路由組件其實已經服務得咱們很好了.記住,若是咱們須要一個非標準的路由協議時候,咱們就能夠自定義一個本身的路由協議,而不用採用默認的路由協議。Yaf的路由組件由兩部分組成,就是路由和路由協議 

路由協議事實上主要負責匹配咱們預先定義好的路由協議,意思就是咱們只有一個路由器,但咱們能夠有許多路由協議. 路由器主要負責管理和運行路由鏈,它根據路由協議棧倒序依次調用各個路由協議, 一直到某一個路由協議返回成功之後, 就匹配成功. 

路由的過程發生派遣過程的最開始,而且路由解析僅僅發生一次.路由過程在何控制器動做(Controller, Action)被派遣以前被執行,一旦路由成功,路由器將會把解析出獲得的信息傳遞給請求對象(Yaf_Request_Abstract object), 這些信息包括moduel、controller、action、用戶params等. 而後派遣器(Yaf_Dispatcher)就會按照這些信息派遣正確的控制器動做. 路由器也有插件鉤子,就是routerStartup和routerShutdown,他們在路由解析先後分別被調用. 

php

默認的路由協議

默認狀況下,Yaf的路由器是Yaf_Router, 而默認使用的路由協議是Yaf_Route_Static,是基於HTTP路由的, 它指望一個請求是HTTP請求而且請求對象是使用Yaf_Request_Http 

使用路由 

使用路由既可讓之很複雜,同時也能讓它很簡單,這是歸於你的應用。然而使用一個路由是很簡單的,你能夠添加你的路由協議給路由器,Yaf爲咱們提供了6種路由協議,分別以下: 

Yaf_Route_Simple 
Yaf_Route_Supervar 
Yaf_Route_Static 
Yaf_Route_Map 
Yaf_Route_Rewrite 
Yaf_Route_Regex 

下面咱們會分別舉例說明如何使用這些路由協議來達到咱們的目的。 

首先咱們得了解路由器和路由協議是如何工做的,就是咱們得先獲得一個路由器實例,Yaf中經過派遣器的getRouter方法來獲得默認的路由器,代碼以下: html

[php]  view plain copy
 
  1. <?php  
  2.      //經過派遣器獲得默認的路由器  
  3.      $router = Yaf_Dispatcher::getInstance()->getRouter();  
  4. ?>  



獲得路由器以後咱們能夠用路由器來添加路由協議了。咱們能夠經過配置文件來添加路由協議,示例以下 bash

[common]
     ;自定義路由
     ;順序很重要
     routes.regex.type="regex"
     routes.regex.match="#^/list/([^/]*)/([^/]*)#"
     routes.regex.route.controller=Index
     routes.regex.route.action=action
     routes.regex.map.1=name
     routes.regex.map.2=value
     ;添加一個名爲simple的路由協議
     routes.simple.type="simple"
     routes.simple.controller=c
     routes.simple.module=m
     routes.simple.action=a
     ;添加一個名爲supervar的路由協議
     routes.supervar.type="supervar"
     routes.supervar.varname=r

     [product : common]
     ;product節是Yaf默認關心的節, 添加一個名爲rewrite的路由協議
     routes.rewrite.type="rewrite"
     routes.rewrite.match="/product/:name/:value"



而後在Bootstrap中經過調用Yaf_Router::addConfig添加定義在配置中的路由協議 dom

[php]  view plain copy
 
  1. <?php  
  2.   
  3. class Bootstrap extends Yaf_Bootstrap_Abstract{  
  4.   
  5.         public function _initRoute(Yaf_Dispatcher $dispatcher) {  
  6.                 $router = Yaf_Dispatcher::getInstance()->getRouter();  
  7.                 /** 
  8.                  * 添加配置中的路由 
  9.                  */  
  10.                 $router->addConfig(Yaf_Registry::get("config")->routes);  
  11.         }  
  12. }  




默認路由協議Yaf_Route_Static

默認的路由協議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: 

使用示例: ide

[php]  view plain copy
 
  1. <?php  
  2.      /** 
  3.       * 對於請求request_uri爲"/ap/foo/bar/dummy/1" 
  4.       * base_uri爲"/ap" 
  5.       * 則最後參加路由的request_uri爲"/foo/bar/dummy/1" 
  6.       * 而後, 經過對URL分段, 獲得以下分節 
  7.       * foo, bar, dummy, 1 
  8.       * 而後判斷foo是否是一個合法的Module, 若是不是, 則認爲結果以下: 
  9.       */  
  10.       array(  
  11.         'module'     => '默認模塊',  
  12.         'controller' => 'foo',  
  13.         'action'     => 'bar',  
  14.         'params'     => array(  
  15.              'dummy' => 1,  
  16.         )  
  17.      )  
  18.   
  19.      /** 
  20.       * 而若是在配置文件中定義了ap.modules="Index,Foo", 
  21.       * 則此處就會認爲foo是一個合法模塊, 則結果以下 
  22.       */  
  23.       array(  
  24.         'module'     => 'foo',  
  25.         'controller' => 'bar',  
  26.         'action'     => 'dummy',  
  27.         'params'     => array(  
  28.              1 => NULL,  
  29.         )  
  30.      )  




當只有一段路由信息的時候, 好比對於上面的例子, 請求的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的變量名: 

使用實例: this

[php]  view plain copy
 
  1. <?php  
  2.      /** 
  3.       * 指定3個變量名 
  4.       */  
  5.       $route = new Yaf_Route_Simple("m", "c", "a");  
  6.       $router->addRoute("name", $route);  
  7.      /** 
  8.       * 對於以下請求: "http://domain.com/index.php?c=index&a=test 
  9.       * 能獲得以下路由結果 
  10.       */  
  11.       array(  
  12.         'module'     => '默認模塊',  
  13.         'controller' => 'index',  
  14.         'action'     => 'test',  
  15.         )  



只有在query string中不包含任何3個參數之一的狀況下, Yaf_Route_Simple纔會返回失敗, 將路由權交給下一個路由協議. 


spa

Yaf_Route_Supervar

Yaf_Route_Supervar和Yaf_Route_Simple類似, 都是在query string中獲取路由信息, 不一樣的是, 它獲取的是一個相似包含整個路由信息的request_uri 

使用實例: 插件

[php]  view plain copy
 
  1. <?php  
  2.      /** 
  3.      * 指定supervar變量名 
  4.      */  
  5.      $route = new Yaf_Route_Supervar("r");  
  6.      $router->addRoute("name", $route);  
  7.      /** 
  8.      * 對於以下請求: "http://domain.com/index.php?r=/a/b/c 
  9.      * 能獲得以下路由結果 
  10.      */  
  11.      array(  
  12.      'module'     => 'a',  
  13.      'controller' => 'b',  
  14.      'action'     => 'c',  
  15.      )  



在query string中不包含supervar變量的時候, Yaf_Route_Supervar會返回失敗, 將路由權交給下一個路由協議. 

設計

Yaf_Route_Map

Yaf_Route_Map議是一種簡單的路由協議, 它將REQUEST_URI中以'/'分割的節, 組合在一塊兒, 造成一個分層的控制器或者動做的路由結果. Yaf_Route_Map的構造函數接受倆個參數, 第一個參數表示路由結果是做爲動做的路由結果,仍是控制器的路由結果. 默認的是動做路由結果. 第二個參數是一個字符串, 表示一個分隔符, 若是設置了這個分隔符, 那麼在REQUEST_URI中, 分隔符以前的做爲路由信息載體, 而以後的做爲請求參數. 

使用實例: 

[php]  view plain copy
 
  1. <?php  
  2.      /** 
  3.       * 對於請求request_uri爲"/ap/foo/bar" 
  4.       * base_uri爲"/ap" 
  5.       * 則最後參加路由的request_uri爲"/foo/bar" 
  6.       * 而後, 經過對URL分段, 獲得以下分節 
  7.       * foo, bar 
  8.       * 組合在一塊兒之後, 獲得路由結果foo_bar 
  9.       * 而後根據在構造Yaf_Route_Map的時候, 是否指明瞭控制器優先, 
  10.       * 若是沒有, 則把結果當作是動做的路由結果 
  11.       * 不然, 則認爲是控制器的路由結果 
  12.       * 默認的, 控制器優先爲FALSE 
  13.       */  



Yaf_Route_Rewrite

Yaf_Route_Rewrite是一個強大的路由協議, 它能知足咱們絕大部分的路由需求: 

使用實例: 

[php]  view plain copy
 
  1. <?php  
  2.      //建立一個路由協議實例  
  3.      $route = new Yaf_Route_Rewrite(  
  4.        'product/:ident',  
  5.        array(  
  6.          'controller' => 'products',  
  7.          'action' => 'view'  
  8.        )  
  9.      );  
  10.      //使用路由器裝載路由協議  
  11.      $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正則的所有力量,但同時也使得咱們的路由協議變得更加複雜了一些.即便是他們有點複雜,我仍是但願你能好好掌握它,由於它比其餘路由協議要靈活一點點. 一開始,咱們先對以前的產品案例改用使用正則路由 

使用實例: 

[php]  view plain copy
 
  1. <?php  
  2.    $route = new Yaf_Route_Regex(  
  3.      'product/([a-zA-Z-_0-9]+)',  
  4.      array(  
  5.       'controller' => 'products',  
  6.       'action' => 'view'  
  7.      )  
  8.    );  
  9.    $router->addRoute('product', $route);  



你能夠看到,咱們如今移動咱們的正則到咱們的path(構造函數的第一個參數)中來了,就像以前的那樣,這個正則路由協議如今應該是匹配是一個數字、字母、-和_組成的ident變量的字符提供給咱們,可是,你必定會問,ident變量在哪呢?好,若是你使用了這個正則路由協議,咱們能夠經過變量1(one)來獲取其值,便可以在控制器裏用:$this->getRequest()->getParam(1)來獲取,其實這裏若是看過正則的都知道這就是反向引用中的\1.然而,你必定會想爲何要定義的這麼的垃圾,咱們不可以記住或者弄清每個數字表明的是什麼變量(其實我剛開始看的時候也是同樣的感覺).爲了改變這點,正則路由協議的構造函數提供了第3個參數來完成數字到變量名的映射: 

[php]  view plain copy
 
  1. <?php  
  2.    $route = new Yaf_Route_Regex(  
  3.      'product/([a-zA-Z-_0-9]+)',  
  4.      array(  
  5.        'controller' => 'products',  
  6.        'action' => 'view'  
  7.      ),  
  8.      array(  
  9.        //完成數字到字符變量的映射  
  10.        1 => 'ident'  
  11.      )  
  12.    );  
  13.    $router->addRoute('product', $route);  



這樣,咱們就簡單的將變量1映射到了ident變量名,這樣就設置了ident變量,同時你也能夠在控制器裏面獲取到它的值. 

自定義路由協議

固然, 這個世界上沒有絕對的事情. 因此萬一如今全部的路由協議都不能知足你的需求, 那麼你能夠本身實現你本身的路由協議, 你要作的是, 申明你的路由協議實現了Yaf_Route_Interface接口便可。這裏就不對自定義路由協議再作過多的說明了。 

路由註冊的順序很重要, 最後註冊的路由協議, 最早嘗試路由, 這就有個陷阱. 請注意.

相關文章
相關標籤/搜索