### 资源路由
前面我们已经了解了别名路由的强大之处,但别名路由的缺陷就在于单个路由规则的灵活性不够,而资源路由则默认生成了一套路由规则,可以用于快速生成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)
{
}
}
~~~
理论上,资源可以多级嵌套,这完全取决于你的应用场景。
小结
现在大家已经领略了资源路由的强大了,下一篇我会给大家讲解如何快速生成路由地址。