Laravel在5.5以后,更新了API资源
资源的生成和介绍相关,请自行查看文档: Laravel 5.8文档
动机
我一直用的都是其他框架,Laravel是最近一个项目才去实际接触,确实是很赞的一款框架。
在项目中,我碰到了这样一个问题:
User模型和Article模型 1对多关联,而Article模型和Caregory模型1对1关联。
我现在需要通过User模型获取到Article表和Category表中的数据。
第一次尝试:预加载 + 远程关联。
在阅读文档时,预加载模型,可以很好的去获取关联模型的字段。如下:
public function index(int $id)
{
return User::with('articles')->find($id);
}
获取的结果集像这样:
{
"id": 9,
"name": "张三",
"create_time": "2019-03-18 17:40:59",
"articles": [
{
"id": 1,
"title": "Laravel",
"user_id": 9,
"content": "测试1",
"category_id": 1,
"created_at": "2019-04-13 17:59:12"
},
{
"id": 2,
"title": "Thinkphp",
"user_id": 9,
"content": "测试2",
"category_id": 2,
"created_at": "2019-04-13 17:59:13"
}
]
}
但我想要的数据,还需要很多第三个category表的字段,他和user表并无关联,所以无法用with加载。
于是我想到远程关联:
在User的model中定义方法
/**
* 远程一对多关联Category模型
*
*/
public function categories()
{
return $this->hasManyThrough(
'App\Models\Category',
'App\Models\Article',
'user_id',
'id',
'id',
'category_id'
);
}
控制器中with加上categories
public function index(int $id)
{
return User::with(['articles','categories'])->find($id);
}
获取到的结果
{
"id": 9,
"name": "张三",
"create_time": "2019-03-18 17:40:59",
"articles": [
{
"id": 1,
"title": "Laravel",
"user_id": 9,
"content": "测试1",
"category_id": 1,
"created_at": "2019-04-13 17:59:12"
},
{
"id": 2,
"title": "Thinkphp",
"user_id": 9,
"content": "测试2",
"category_id": 2,
"created_at": "2019-04-13 17:59:13"
}
],
"categories": [
{
"id": 1,
"name": "Laravel",
"created_at": "2019-04-13 17:59:48",
"laravel_through_key": 9
},
{
"id": 2,
"name": "TP",
"created_at": "2019-04-13 17:59:57",
"laravel_through_key": 9
}
]
}
虽然我拿到了所有想要拿到的数据,但数据结构,并不理想,并且修改起来想一想好像很麻烦,于是,我尝试第二种方法:API资源。
二、 API资源
这东西,我理解为就是一个中间的加工厂,在你获取结果之后,进行字段和数据结构的处理。
首先,创建UserResource和ArticleResource,在toArray方法中,把你想要返回的字段做处理,里面可以随意的去修改字段,包括随便添加个aaa,bbb,返回什么就写什么。
如果,想在不同的方法里,都使用这个Resource的字段处理,我没想到太好的办法,我是通过判断路由来处理的,
注意:如果你想获取的主要数据是单条数据,使用的是find和first方法,那么直接实例化一个资源类就好: new xxxResource(Model::find(1))。但如果你想要获取的是多条数据,或是分页数据,那么就要使用资源集合,如xxxResource::collection(Model::paginate(10))。
/**
* UserController中
*/
public function index(int $id)
{
$users = User::with('articles')->find($id);
return new UserResource($users);
}
/**
* UserResource 中
*/
public function toArray($request)
{
$data = [
'id' => $this->id,
'name' => $this->name,
'articles' => ArticleResource::collection($this->whenLoaded('articles'))
];
// is_route方法是自己写的判断当前请求的路由名称是否与写入的相等。
if(is_route('user.show')) {
$data = [
// 想要返回字段
];
}
return $data;
}
/**
* ArticleResource 中
*/
public function toArray($request)
{
return [
'id' => $this->id,
'title' => $this->title,
'category_id' => $this->category_id,
'category_name' => $this->getCategoryField('name'),
'category_aaa' => $this->getCategoryField('aaa')
];
}
protected function getCategoryField($field)
{
if(empty($this->categoryModel)){
$this->categoryModel = new Category();
}
return $this->categoryModel->find($this->category_id)->$field;
}
这样,我就获取到了自己想要的数据结构:
{
"data": {
"id": 9,
"name": "张三",
"articles": [
{
"id": 1,
"title": "Laravel",
"category_id": 1,
"category_name": "Laravel",
"category_aaa": "111"
},
{
"id": 2,
"title": "Thinkphp",
"category_id": 2,
"category_name": "TP",
"category_aaa": "222"
}
]
}
}