### 資源路由
前面我們已經了解了別名路由的強大之處,但別名路由的缺陷就在于單個路由規則的靈活性不夠,而資源路由則默認生成了一套路由規則,可以用于快速生成RESTful的路由。
#### RESTful
要理解資源路由就要理解什么是RESTful。如果一個架構符合REST(即Representational State Transfer的縮寫,意為表現層狀態轉化)原則,就稱它為RESTful架構。
REST提出了一些設計概念和準則:
1、網絡上的所有事物都被抽象為資源(resource);
2、每個資源對應一個唯一的資源標識(resource identifier);
3、通過通用的連接器接口(generic connector interface)對資源進行操作;
4、對資源的各種操作不會改變資源標識;
5、所有的操作都是無狀態的(stateless)。
需要注意的是,REST是設計風格而不是標準。REST通常基于使用HTTP,URI,和XML以及HTML這些現有的廣泛流行的協議和標準。
傳統的請求模式和REST模式的請求模式區別:
|作用 |傳統模式 |REST模式|
|--|--|--|
|列舉出所有的用戶 |GET /users/list |GET /users|
|列出ID為1的用戶信息 |GET /users/show/id/1 |GET /users/1|
|插入一個新的用戶 |POST /users/add |POST /users|
|更新ID為1的用戶信息 |POST /users/mdy/id/1 |PUT /users/1|
|刪除ID為1的用戶 |POST /users/delete/id/1 |DELETE /users/1|
#### 資源路由定義
現在再來理解什么是資源路由,資源路由的作用就是快速給控制器生成一套RESTful架構的路由規范。
ThinkPHP5.0可以通過命令行快速生成一個RESTful控制器,我們進入命令行,切換到應用根目錄下面,執行下面的指令:
~~~
php think make:controller index/Blog
~~~
會自動生成一個類名是`app\index\controller\Blog`的資源控制器類(采用RESTful架構的控制器),并且會自動生成對應的7個(空白)方法,代碼如下:
~~~
<?php
namespace app\index\controller;
use think\Controller;
use think\Request;
class Blog extends Controller
{
/**
* 顯示資源列表
*
* @return \think\Response
*/
public function index()
{
//
}
/**
* 顯示創建資源表單頁.
*
* @return \think\Response
*/
public function create()
{
//
}
/**
* 保存新建的資源
*
* @param \think\Request $request
* @return \think\Response
*/
public function save(Request $request)
{
//
}
/**
* 顯示指定的資源
*
* @param int $id
* @return \think\Response
*/
public function read($id)
{
//
}
/**
* 顯示編輯資源表單頁.
*
* @param int $id
* @return \think\Response
*/
public function edit($id)
{
//
}
/**
* 保存更新的資源
*
* @param \think\Request $request
* @param int $id
* @return \think\Response
*/
public function update(Request $request, $id)
{
//
}
/**
* 刪除指定資源
*
* @param int $id
* @return \think\Response
*/
public function delete($id)
{
//
}
}
~~~
但是你會看到,這些操作方法本身并不會進行請求類型的判斷,這些是需要配合路由規則來完成的,也就是說我們需要給Blog控制器添加`RESTful`的路由訪問規則,看起來像下面一樣:
|請求類型 |路由規則 |對應操作方法| 描述|
|--|--|--|--|
|GET |blogs |index/Blog/index |顯示博客列表|
|GET |blogs/create |index/Blog/create |新增博客頁面|
|POST |blogs |index/Blog/save |保存博客內容|
|GET |blogs/:id |index/Blog/read |查看博客內容|
|GET| blogs/:id/edit| index/Blog/edit |編輯博客頁面|
|PUT| blogs/:id |index/Blog/update| 更新博客內容|
|DELETE |blogs/:id |index/Blog/delete |刪除博客|
> 這里使用了復數方式的blogs,這是RESTful的一種建議規范。
按照之前學習的方法可能需要一個個注冊,類似下面:
~~~
Route::get('blogs','index/Blog/index');
Route::get('blogs/create','index/Blog/create');
Route::post('blogs','index/Blog/save');
Route::get('blogs/:id','index/Blog/read');
Route::get('blogs/:id/edit','index/Blog/edit');
Route::put('blogs/:id','index/Blog/update');
Route::delete('blogs/:id','index/Blog/delete');
~~~
也許你會想到使用路由分組功能來簡化路由注冊:
~~~
Route::group(['name'=>'blogs','prefix'=>'index/Blog'], function() {
Route::get('/','index');
Route::get('create','create');
Route::post('/','save');
Route::get(':id','read');
Route::get(':id/edit','edit');
Route::put(':id','update');
Route::delete(':id','delete');
});
~~~
看起來是一個足夠聰明的舉動,但必須給每個操作方法注冊路由規則的事實沒有改變。
而如果使用資源路由的話,只需要使用一行代碼就可以完成前面的RESTful路由規則注冊:
~~~
Route::resource('blogs','index/Blog');
~~~
如果采用配置方式定義的話,使用下面的方式:
~~~
return [
// 定義資源路由
'__rest__' => [
'blogs' => 'index/Blog',
],
];
~~~
rescource方法給index模塊的Blog控制器注冊了一個名為blogs(這個名稱其實是隨意的)的資源路由,其實內部會自動注冊前面我們注冊的7個路由規則,沒錯,這一切都是自動完成的。資源路由會給規定的每個操作方法實際注冊一個路由規則,并且可以定義每個方法的請求類型。
也可以在定義資源路由的時候限定執行的方法(標識),例如:
~~~
// 只允許index read edit update 四個操作
Route::resource('blogs','index/Blog',['only'=>['index','read','edit','update']]);
// 排除index和delete操作
Route::resource('blogs','index/Blog',['except'=>['index','delete']]);
~~~
注意這里的index、read、edit和update都是資源操作標識,并不是實際的操作方法。
#### 補充路由
如果需要對資源路由進行補充或者替換,可以在注冊資源路由之后,進行補充注冊:
~~~
// 注冊資源路由
Route::resource('blog','index/Blog');
// 替換blog/:id 路由規則
Route::get('blog/:id','index/Test/read');
// 增加新的理由規則
Route::get('blog/:year/:month','index/Blog/archive');
~~~
如果在注冊資源路由之前進行路由規則替換的話,可以配合only和except路由參數。
#### 資源嵌套
資源路由允許進行嵌套,表示對blogs資源下面的comment資源進行操作:
~~~
// 注冊blogs.comment資源路由
Route::resource('blog.comments','index/Comment');
~~~
注冊的comment控制器仍然是一個RESTful資源控制器,不過其方法的參數略有區別,以read和edit操作方法為例:
~~~
<?php
namespace app\index\controller;
class Comment
{
public function read($id,$blog_id)
{
}
public function edit($id,$blog_id)
{
}
}
~~~
其實比之前的blog資源控制器的對應方法多了一個blog_id參數。
可以訪問如下地址:
~~~
http://tp5.com/blog/128/comments/32
http://tp5.com/blog/128/comments/32/edit
~~~
生成的路由規則分別是:
~~~
blog/:blog_id/comments/:id
blog/:blog_id/comments/:id/edit
~~~
也就是comment資源的上級資源ID,嵌套資源的資源ID默認規范是資源名_id,這里的上級資源的名稱就是blog,我們可以更改資源ID的名稱,例如:
~~~
// 注冊blogs.comment資源路由
Route::resource('blog.comments','index/Comment',['var'=>['blog'=>'blogId']]);
~~~
Comment資源控制器的代碼需要改為:
~~~
<?php
namespace app\index\controller;
class Comment
{
public function read($id,$blogId)
{
}
public function edit($id,$blogId)
{
}
}
~~~
理論上,資源可以多級嵌套,這完全取決于你的應用場景。
小結
現在大家已經領略了資源路由的強大了,下一篇我會給大家講解如何快速生成路由地址。