API 资源类 | Eloquent模型 | Laravel 5.8 中文文档


本站和网页 https://xueyuanjun.com/post/19536 的作者无关,不对其内容负责。快照谨为网络故障时之索引,不代表被搜索网站的即时页面。

API 资源类 | Eloquent模型 | Laravel 5.8 中文文档
Laravel 学院
文档
Laravel 8.x 中文文档
Laravel 7.x 中文文档
Laravel 6.x 中文文档
Laravel 5.8 中文文档
Laravel 5.7 中文文档
Laravel 5.6 中文文档
Laravel 5.5 中文文档
Laravel 5.4 中文文档
Laravel 5.3 中文文档
Laravel 5.2 中文文档
Laravel 5.1 中文文档
Lumen 中文文档
全栈教程
PHP 全栈工程师指南
PHP 入门到实战
Laravel 入门到精通
Vue.js 入门到实战
玩转 PhpStorm 教程
Laravel 博客入门项目
Laravel 微信小程序项目
Laravel 前后端分离项目
Swoole 入门到实战
Eloquent 性能优化实战
Redis 高性能实战系列
Laravel 新版本特性
PHP 新特性与最佳实践
Golang
Go 入门教程
Go Web 编程
Gin 使用教程
微服务开发
内功修炼
数据结构与算法
网络协议
微服务从入门到实践
高性能 MySQL 实战
高性能 Redis 实战
Laravel 消息队列实战
Laravel 从学徒到工匠
PHP 设计模式系列
名企面试指南
资源库
Laravel 资源大全
Laravel 开源项目
Laravel 扩展包
Laravel 资源下载
更多
博客 & 新闻
问答 & 讨论
Leetcode 题解
学院君读书笔记系列
关于 Laravel 学院
Laravel 互助学习群
Golang 互助学习群
更多
Laravel 中文文档
Laravel 全栈教程
Laravel 学习路径
Go 入门教程
程序员内功修炼
博客
问答
搜索
注册
登录
Info
Content
章节导航
Laravel 5.8 中文文档
目录索引
序言
3篇文章
新版特性
升级指南
贡献指南
快速入门
5篇文章
安装配置
目录结构
重量级开发环境:Homestead
轻量级开发环境:Valet
部署应用到生产环境
核心架构
5篇文章
一次 Laravel 请求的生命周期
服务容器
服务提供者
门面(Facades)
契约(Contracts)
基础组件
12篇文章
路由
中间件
CSRF 保护
控制器
HTTP 请求
HTTP 响应
视图
URL 生成
Session
表单验证
异常处理
日志
前端开发
4篇文章
Blade 模板引擎
本地化
快速入门:JavaScript & CSS 脚手架
使用进阶:通过 Laravel Mix 编译前端资源
安全系列
8篇文章
登录认证
API 认证解决方案:Laravel Passport
API 认证
授权
邮箱验证
加密
哈希
重置密码
进阶系列
12篇文章
Artisan 控制台
广播
缓存
集合
事件
文件存储
辅助函数
邮件
通知
扩展包开发
队列
任务调度
数据库操作
6篇文章
快速入门
查询构建器
分页
迁移
数据填充
Redis
Eloquent模型
6篇文章
快速入门
关联关系
集合
访问器和修改器
API 资源类
序列化
测试系列
6篇文章
快速入门
HTTP 测试
浏览器测试
控制台测试
数据库测试
模拟
官方扩展包
7篇文章
订阅支付解决方案:Laravel Cashier(Stripe)
订阅支付解决方案:Laravel Cashier(Braintree)
远程操作解决方案:Laravel Envoy
队列系统解决方案:Laravel Horizon
全文搜索解决方案:Laravel Scout
第三方登录解决方案:Laravel Socialite
本地开发调试解决方案:Laravel Telescope
图书
Laravel 5.8 中文文档
Eloquent模型
API 资源类
API 资源类
由 学院君 创建于3年前, 最后更新于 3年前
版本号 #1
10889 views
2 likes
0 collects
简介
构建 API 时,在 Eloquent 模型和最终返回给应用用户的 JSON 响应之间可能需要一个转化层。Laravel 的资源类允许你以简单优雅的方式将模型和模型集合转化为 JSON 格式数据。
生成资源类
要生成一个资源类,可以使用 Artisan 命令 make:resource,默认情况下,资源类存放在应用的 app/Http/Resources 目录下,资源类都继承自 Illuminate\Http\Resources\Json\JsonResource 基类:
php artisan make:resource User
资源集合
除了生成转化独立模型的资源类之外,还可以生成转化模型集合的资源类。这样响应就可以包含链接和其他与整个给定资源集合相关的元信息。
要创建一个资源集合处理类,需要在创建资源类的时候使用 --collection 标记,或者在资源名称中包含单词 Collection 以便告知 Laravel 需要创建一个资源集合类,资源集合类继承自 Illuminate\Http\Resources\Json\ResourceCollection 基类:
php artisan make:resource Users --collection
php artisan make:resource UserCollection
核心概念
注:这是一个关乎资源和资源集合的高屋建瓴的概述,强烈推荐你阅读本文档的其他部分来深入强化理解资源类提供的功能和定制化。
在深入了解资源类提供的所有功能之前,我们先来高屋建瓴的看一下如何在 Laravel 中使用资源类。一个资源类表示一个单独的需要被转化为 JSON 数据结构的模型,例如,下面是一个简单的 User 类:
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class User extends JsonResource
/**
* Transform the resource into an array.
* @param \Illuminate\Http\Request
* @return array
*/
public function toArray($request)
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
每一个资源类都包含一个 toArray 方法用来返回在发送响应时需要被转化 JSON 的属性数组,注意这里我们可以通过 $this 变量直接访问模型属性,这是因为资源类是一个代理,可以访问底层对应模型提供的属性和方法。资源类定义好之后,可以从路由或控制器返回:
use App\User;
use App\Http\Resources\User as UserResource;
Route::get('/user', function () {
return new UserResource(User::find(1));
});
资源集合
如果你需要返回资源集合或者分页响应,可以在路由或控制器中创建资源实例时使用 collection 方法:
use App\User;
use App\Http\Resources\User as UserResource;
Route::get('/user', function () {
return UserResource::collection(User::all());
});
当然,这种方式不能添加除模型数据之外的其他需要和集合一起返回的元数据,如果你想要自定义资源集合响应,可以创建专用的资源类来表示集合:
php artisan make:resource UserCollection
资源集合类生成之后,可以很轻松地定义需要包含到响应中的元数据:
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class UserCollection extends ResourceCollection
/**
* Transform the resource collection into an array.
* @param \Illuminate\Http\Request
* @return array
*/
public function toArray($request)
return [
'data' => $this->collection,
'links' => [
'self' => 'link-value',
],
];
定义好资源集合类之后,就可以从路由或控制器中返回它:
use App\User;
use App\Http\Resources\UserCollection;
Route::get('/users', function () {
return new UserCollection(User::all());
});
保留集合键
当从路由返回资源集合时,Laravel 会重置集合的键以便它们按照数字索引排序。不过,你可以添加 preserveKeys 属性到资源类来标识对应集合键是否保留:
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class User extends JsonResource
/**
* Indicates if the resource's collection keys should be preserved.
* @var bool
*/
public $preserveKeys = true;
如果 preserveKeys 属性设置为 true,集合键将被保留:
use App\User;
use App\Http\Resources\User as UserResource;
Route::get('/user', function () {
return UserResource::collection(User::all()->keyBy->id);
});
自定义底层资源类
通常,资源集合的 $this->collection 属性会被自动填充,填充结果是将集合的每个项目映射到对应的单一资源类,这个单一资源类被假设为不带 Collection 后缀的集合类名。
例如,UserCollection 会尝试映射给定用户实例到 User 资源,如果要自定义这一行为,可以覆盖资源集合的 $collects 属性:
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class UserCollection extends ResourceCollection
/**
* The resource that this resource collects.
* @var string
*/
public $collects = 'App\Http\Resources\Member';
编写资源类
注:如果你还没有阅读核心概念,强烈建议你在继续下去之前阅读那部分文档。
其实资源类很简单,它们所做的只是将给定模型转化为数组,因此,每个资源类都包含 toArray 方法,用于将模型属性转化为一个可以返回给用户的、API 友好的数组:
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class User extends JsonResource
/**
* Transform the resource into an array.
* @param \Illuminate\Http\Request
* @return array
*/
public function toArray($request)
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
定义好资源类之后,就可以从路由或控制器中将其直接返回:
use App\User;
use App\Http\Resources\User as UserResource;
Route::get('/user', function () {
return new UserResource(User::find(1));
});
关联关系
如果你想要在响应中包含关联资源,可以将它们添加到 toArray 方法返回的数组。在本例中,我们使用 Post 资源类的 collection 方法添加用户博客文章到资源响应:
/**
* 将资源转化为数组
* @param \Illuminate\Http\Request
* @return array
*/
public function toArray($request)
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'posts' => PostResource::collection($this->posts),
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
注:如果你想要在关联关系被加载之后包含它们,请查看附加条件的关联关系部分文档。
资源集合
资源类用于将单个模型转化为数组,而资源集合类用于将模型集合转化为数组。并不是每种类型的模型都需要定义一个资源集合类,因为所有资源类都提供了一个 collection 方法立马生成一个特定的资源集合:
use App\User;
use App\Http\Resources\User as UserResource;
Route::get('/user', function () {
return UserResource::collection(User::all());
});
不过,如果你需要自定义与集合一起返回的元数据,就需要定义一个资源集合类了:
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class UserCollection extends ResourceCollection
/**
* Transform the resource collection into an array.
* @param \Illuminate\Http\Request
* @return array
*/
public function toArray($request)
return [
'data' => $this->collection,
'links' => [
'self' => 'link-value',
],
];
和单个资源类一样,资源集合类也可以从路由或控制器中直接返回:
use App\User;
use App\Http\Resources\UserCollection;
Route::get('/users', function () {
return new UserCollection(User::all());
});
数据包装
默认情况下,在资源响应被转化为 JSON 的时候最外层的资源都会包裹到一个 data 键里,例如,一个典型的资源集合响应数据如下所示:
"data": [
"id": 1,
"name": "Eladio Schroeder Sr.",
"email": "therese28@example.com",
},
"id": 2,
"name": "Liliana Mayert",
"email": "evandervort@example.com",
如果你想要禁止包装最外层资源,可以调用资源基类提供的 withoutWrapping 方法,通常,你需要在 AppServiceProvider 或者其他每个请求都会加载的服务提供者中调用这个方法:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Http\Resources\Json\Resource;
class AppServiceProvider extends ServiceProvider
/**
* Perform post-registration booting of services.
* @return void
*/
public function boot()
Resource::withoutWrapping();
/**
* Register bindings in the container.
* @return void
*/
public function register()
//
注:withoutWrapping 只影响最外层资源,并不会移除你手动添加到自己的资源集合类中的 data 键。
包装嵌套资源
你完全可以自己决定如何包装资源的关联关系。如果你想要所有资源集合包裹到 data 键里,而不管它们之间的嵌套,那么就需要为每个资源定义一个资源集合类并通过 data 键返回这个集合。
当然,你可能会担心这样做会不会导致最外层的资源被包装到两个 data 键,如果你这样想的话就是完全多虑了,Laravel 永远不会让资源出现双层包装,所以你大可不必担心转化资源集合的嵌套问题:
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class CommentsCollection extends ResourceCollection
/**
* Transform the resource collection into an array.
* @param \Illuminate\Http\Request
* @return array
*/
public function toArray($request)
return ['data' => $this->collection];
数据包装和分页
在资源响应中返回分页集合时,Laravel 会把资源数据包装到 data 键里,即使调用了 withoutWrapping 方法也不例外。这是因为分页响应总是会包含带有分页器状态信息的 meta 和 links 键:
"data": [
"id": 1,
"name": "Eladio Schroeder Sr.",
"email": "therese28@example.com",
},
"id": 2,
"name": "Liliana Mayert",
"email": "evandervort@example.com",
],
"links":{
"first": "http://example.com/pagination?page=1",
"last": "http://example.com/pagination?page=1",
"prev": null,
"next": null
},
"meta":{
"current_page": 1,
"from": 1,
"last_page": 1,
"path": "http://example.com/pagination",
"per_page": 15,
"to": 10,
"total": 10
分页
你可能经常需要传递分页器实例到资源类的 collection 方法或者自定义的资源集合类:
use App\User;
use App\Http\Resources\UserCollection;
Route::get('/users', function () {
return new UserCollection(User::paginate());
});
分页响应总是会包含带有分页器状态信息的 meta 和 links 键:
"data": [
"id": 1,
"name": "Eladio Schroeder Sr.",
"email": "therese28@example.com",
},
"id": 2,
"name": "Liliana Mayert",
"email": "evandervort@example.com",
],
"links":{
"first": "http://example.com/pagination?page=1",
"last": "http://example.com/pagination?page=1",
"prev": null,
"next": null
},
"meta":{
"current_page": 1,
"from": 1,
"last_page": 1,
"path": "http://example.com/pagination",
"per_page": 15,
"to": 10,
"total": 10
带条件的属性
有时候你可能希望只有在满足给定条件的情况下才在资源响应中包含某个属性。例如,你可能希望只有在当前用户是管理员的情况下才包含某个值。为此,Laravel 提供了多个辅助函数来帮助你实现这种功能,when 方法就可以用于在满足某种条件的前提下添加属性到资源响应:
/**
* 将资源转化为数组
* @param \Illuminate\Http\Request
* @return array
*/
public function toArray($request)
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'secret' => $this->when($this->isAdmin(), 'secret-value'),
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
在这个例子中,secret 键只有在 $this->isAdmin() 方法返回 true 的前提下才会出现在最终资源响应中。如果这个方法返回 false,secret 键将会在资源响应发送给客户端之前从返回数据中完全移除。when 方法让你在任何时候都可以优雅地定义资源类,而不必在构建数组时重新编写条件语句。
when 方法还可以接受闭包作为第二个参数,从而允许你在给定条件为 true 的时候计算返回值:
'secret' => $this->when($this->isAdmin(), function () {
return 'secret-value';
}),
注:记住,在资源类上的方法调用实际上代理的是底层模型实例方法,所以,在这个示例中,isAdmin 方法调用的实际上底层 User 模型上的方法。
合并带条件的属性
有时候你可能有多个属性基于同一条件才会包含到资源响应中,在这种情况下,你可以使用 mergeWhen 方法在给定条件为 true 的前提下来包含这些属性到响应中:
/**
* Transform the resource into an array.
* @param \Illuminate\Http\Request
* @return array
*/
public function toArray($request)
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
$this->mergeWhen(Auth::user()->isAdmin(), [
'first-secret' => 'value',
'second-secret' => 'value',
]),
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
再次说明,如果给定条件为 false,这些属性将会在资源响应发送给客户端之前从响应数据中完全移除。
注:mergeWhen 方法不能在混合字符串和数字键的数组中使用,此外,也不能在没有顺序排序的纯数字键数组中使用。
带条件的关联关系
除了通过条件加载属性之外,还可以基于给定关联关系是否在模型上加载的条件在资源响应中包含关联关系。这样的话在控制器中就可以决定哪些关联关系需要被加载,然后资源类就可以在关联关系确实已经被加载的情况下很轻松地包含它们。
最后,这种机制也让我们在资源类中避免 N+1 查询问题变得简单。whenLoaded 方法可用于带条件的加载关联关系。为了避免不必要的关联关系加载,该方法接收关联关系名称而不是关联关系本身:
/**
* Transform the resource into an array.
* @param \Illuminate\Http\Request
* @return array
*/
public function toArray($request)
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'posts' => PostResource::collection($this->whenLoaded('posts')),
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
在这个例子中,如果关联关系还没有被加载,posts 键将会在资源响应发送到客户端之前从响应数据中移除。
带条件的中间表信息
除了在资源响应中带条件的包含关联关系信息之外,你还可以使用 whenPivotLoaded 方法从多对多关联关系中间表中引入满足条件的数据。whenPivotLoaded 方法接收中间表名称作为第一个参数,第二个参数是一个闭包,该闭包定义了如果模型对应中间表信息有效的情况下返回的数据:
/**
* Transform the resource into an array.
* @param \Illuminate\Http\Request
* @return array
*/
public function toArray($request)
return [
'id' => $this->id,
'name' => $this->name,
'expires_at' => $this->whenPivotLoaded('role_users', function () {
return $this->pivot->expires_at;
}),
];
如果中间表使用访问器而不是 pivot,可以使用 whenPivotLoadedAs 方法:
/**
* Transform the resource into an array.
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
return [
'id' => $this->id,
'name' => $this->name,
'expires_at' => $this->whenPivotLoadedAs('subscription', 'role_user', function () {
return $this->subscription->expires_at;
}),
];
添加元数据
有些 JSON API 标准要求添加额外的元数据到资源响应或资源集合响应。这些元数据通常包含链接到资源或关联资源的 links,或者关于资源本身的元数据。如果你需要返回关于资源的额外元数据,可以在 toArray 方法中包含它们。例如,你可以在转化资源集合时引入 links 信息:
/**
* Transform the resource into an array.
* @param \Illuminate\Http\Request
* @return array
*/
public function toArray($request)
return [
'data' => $this->collection,
'links' => [
'self' => 'link-value',
],
];
从资源类返回额外元数据的场景下,在返回分页响应时永远不必担心意外覆盖 Laravel 自动添加的 links 或 meta 键,任何自定义的额外 links 键都会被合并到分页器提供的链接中。
顶层元数据
有时候你可能希望只有在资源是最外层被返回数据的情况下包含特定元数据。通常情况下,这将会包含关于整个响应的元数据,要定义这个元数据,需要添加一个 with 方法到你的资源类。该方法只有在资源是最外层被渲染数据的情况下才会返回一个被包含到资源响应中的元数据数组:
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class UserCollection extends ResourceCollection
/**
* Transform the resource collection into an array.
* @param \Illuminate\Http\Request
* @return array
*/
public function toArray($request)
return parent::toArray($request);
/**
* Get additional data that should be returned with the resource array.
* @param \Illuminate\Http\Request $request
* @return array
*/
public function with($request)
return [
'meta' => [
'key' => 'value',
],
];
构造资源类时添加元数据
你还可以在路由或控制器中构造资源类实例时添加顶层数据,在所有资源类中都有效的 additional 方法,可用于添加数组数据到资源响应:
return (new UserCollection(User::all()->load('roles')))
->additional(['meta' => [
'key' => 'value',
]]);
资源响应
正如你所了解到的,资源类可以直接从路由和控制器中返回:
use App\User;
use App\Http\Resources\User as UserResource;
Route::get('/user', function () {
return new UserResource(User::find(1));
});
不过,有时候你可能需要在响应发送到客户端之前自定义输出 HTTP 响应。有两种方法来实现这个功能,第一种是链接 response 方法到资源类,该方法会返回一个 Illuminate\Http\Response 实例,从而允许你完全控制响应头:
use App\User;
use App\Http\Resources\User as UserResource;
Route::get('/user', function () {
return (new UserResource(User::find(1)))
->response()
->header('X-Value', 'True');
});
另一种方法是在资源类中定义一个 withResponse 方法,该方法会在资源在响应中作为最外层数据返回时被调用:
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class User extends JsonResource
/**
* Transform the resource into an array.
* @param \Illuminate\Http\Request
* @return array
*/
public function toArray($request)
return [
'id' => $this->id,
];
/**
* Customize the outgoing response for the resource.
* @param \Illuminate\Http\Request
* @param \Illuminate\Http\Response
* @return void
*/
public function withResponse($request, $response)
$response->header('X-Value', 'True');
Laravel
5.8
文档
Eloquent
资源
模型
API
集合
JSON
关联关系
数据包装
分页
元数据
响应
点赞
取消点赞
收藏
取消收藏
赞赏
分享到以下平台:
<< 上一篇:
访问器和修改器
>> 下一篇:
序列化
5 条评论
#1
王一飞
评论于 3年前
正在删除评论...
资源类和资源集合的区别在哪里啊,有什么主要的区别吗
#2
学院君
评论于 3年前
回复 #1
正在删除评论...
集合里面包含多个资源
#3
张若初
评论于 3年前
正在删除评论...
不清楚,API资源类在什么项目里边能用的上
#4
学院君
评论于 3年前
回复 #3
正在删除评论...
看下这篇最新教程:https://xueyuanjun.com/post/19645.html
#5
张若初
评论于 3年前
回复 #3
正在删除评论...
谢谢
登录后即可添加评论
升级为学院君订阅用户(新年优惠🎁)
内容导航
简介
生成资源类
核心概念
资源集合
编写资源类
数据包装
分页
带条件的属性
带条件的关联关系
添加元数据
资源响应
相关推荐
API 资源类:架起模型与 JSON API 之间的桥梁
Laravel 5.5 中文文档
Eloquent模型
API 资源类
Laravel 5.6 中文文档
Eloquent模型
API 资源类
Laravel 5.7 中文文档
Eloquent模型
API 资源类
Laravel 6 中文文档
Eloquent模型
API 资源类
Laravel 8 中文文档
Eloquent ORM
回到顶部
2022 基于 Laravel 6 构建
关于学院
订阅服务
友情链接
站点地图
本站 CDN 加速服务由又拍云赞助