在 Laravel 中动态隐藏 API 字段的方法


Posted in PHP onOctober 25, 2019

我最近在 Laravel Brasil 社区看到一个问题,结果比看起来更有趣。想象一下你有一个 UsersResource 用下面的实现:

<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\Resource;
class UsersResource extends Resource
{
 /**
  * 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
  ];
 }
}

出于某种原因,您可能希望在另一个端点上重新使用该资源类,但隐藏email 字段。这篇文章就是告诉你如何实现这一点的。

如果你不知道 API Resources 是什么,请查看我之前关于这个的文章。

  • First Impression on API Resources
  • API Resources with Nested Relationship

1- 初始化项目

有趣的东西从第3节开始.

composer create-project --prefer-dist laravel/laravel api-fields
cd api-fields
touch database/database.sqlite

编辑.env文件,删除数据库设置并使用 SQLite

DB_CONNECTION=sqlite

继续设置项目

php artisan migrate
php artisan make:resource UsersResource
php artisan make:resource --collection UsersResourceCollection 
php artisan make:controller UsersController
php artisan tinker
factory(App\User::class)->times(20)->create();
quit

2- 路由

确保在 api.php 文件中创建一个路由。

Route::apiResource('/users', 'UsersController');

3- 控制器

控制器代表了期望的目标。在这个例子中,让我们假设在用户列表中,我们只想要所有用户的名字,而在用户显示中,我们只想隐藏电子邮件地址。

<?php
namespace App\Http\Controllers;
use App\Http\Resources\UsersResource;
use App\User;
class UsersController extends Controller
{
 /**
  * Display a listing of the resource.
  *
  * @param User $user
  * @return \Illuminate\Http\Response
  */
 public function index(User $user)
 {
  return UsersResource::collection($user->paginate())->hide(['id', 'email']);
 }
 /**
  * Display a user.
  *
  * @param User $user
  * @return \Illuminate\Http\Response
  */
 public function show(User $user)
 {
  return UsersResource::make($user)->hide(['id']);
 }
}

为了达到这个目的,我们需要 UsersResourceCollection UsersResource 同时知道如何处理 hide 调用。

4- UsersResource 类

让我们从  show 方法开始.  UsersResource::make 将会返回  UsersResource 的对象. 因此,我们应该揭开  hide 的神秘面纱,它可以存储我们期望从响应中移除的键.

<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\Resource;
class UsersResource extends Resource
{
 /**
  * @var array
  */
 protected $withoutFields = [];
 
  /**
  * Transform the resource into an array.
  *
  * @param \Illuminate\Http\Request
  * @return array
  */
 public function toArray($request)
 {
  return $this->filterFields([
   'id' => $this->id,
   'name' => $this->name,
   'email' => $this->email
  ]);
 }
 /**
  * Set the keys that are supposed to be filtered out.
  *
  * @param array $fields
  * @return $this
  */
 public function hide(array $fields)
 {
  $this->withoutFields = $fields;
  return $this;
 }
 /**
  * Remove the filtered keys.
  *
  * @param $array
  * @return array
  */
 protected function filterFields($array)
 {
  return collect($array)->forget($this->withoutFields)->toArray();
 }
}

大功告成! 现在我们可以访问 http://api.dev/api/users/1 ,你会发现响应中已经没有id 字段了。

{
 "data": {
 "name": "Mr. Frederik Morar",
 "email": "darryl.wilkinson@example.org"
 }
}

5- UsersResourceCollection 类

执行项目集合中的 index 方法, 我们需要作出如下修改:

(1) 确保  UsersResource::collection 返回 UsersResourceCollection 实例

(2) 在  UsersResourceCollection 上公开 hide 方法

(3) 将隐藏的字段传递给  UsersResource

关于 (1), 我们只需要重写  UsersResource 中的 collection 方法

<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\Resource;
class UsersResource extends Resource
{
 public static function collection($resource)
 {
  return tap(new UsersResourceCollection($resource), function ($collection) {
   $collection->collects = __CLASS__;
  });
 }
 
 /**
  * @var array
  */
 protected $withoutFields = [];
 /**
  * Transform the resource into an array.
  * 将资源转换为一个数组
  * 
  * @param \Illuminate\Http\Request
  * @return array
  */
 public function toArray($request)
 {
  return $this->filterFields([
   'id' => $this->id,
   'name' => $this->name,
   'email' => $this->email
  ]);
 }
 /**
  * Set the keys that are supposed to be filtered out.
  * 设置需要隐藏过滤掉的键
  * 
  * @param array $fields
  * @return $this
  */
 public function hide(array $fields)
 {
  $this->withoutFields = $fields;
  return $this;
 }
 /**
  * Remove the filtered keys.
  * 删除隐藏的键
  * 
  * @param $array
  * @return array
  */
 protected function filterFields($array)
 {
  return collect($array)->forget($this->withoutFields)->toArray();
 }
}

关于 (2) 和 (3) 我们需要修改 UsersResourceCollection 文件. 让我们公开 hide 方法并使用隐藏字段处理集合。.

<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class UsersResourceCollection extends ResourceCollection
{
 /**
  * @var array
  */
 protected $withoutFields = [];
 /**
  * Transform the resource collection into an array.
  *
  * @param \Illuminate\Http\Request
  * @return array
  */
 public function toArray($request)
 {
  return $this->processCollection($request);
 }
 public function hide(array $fields)
 {
  $this->withoutFields = $fields;
  return $this;
 }
 /**
  * Send fields to hide to UsersResource while processing the collection.
  * 将隐藏字段通过 UsersResource 处理集合
  * 
  * @param $request
  * @return array
  */
 protected function processCollection($request)
 {
  return $this->collection->map(function (UsersResource $resource) use ($request) {
   return $resource->hide($this->withoutFields)->toArray($request);
  })->all();
 }
}

就是这么简单! 现在我们访问 http://api.dev/api/users  看到返回结果中没有了 id 和 email 字段了如在 UsersController 中的指定方法 .

{
 "data": [{
 "name": "Mr. Frederik Morar"
 }, {
 "name": "Angel Daniel"
 }, {
 "name": "Brianne Mueller"
 }],
 "links": {
 "first": "http://lab.php71/api-fields-2/public/api/users?page=1",
 "last": "http://lab.php71/api-fields-2/public/api/users?page=7",
 "prev": null,
 "next": "http://lab.php71/api-fields-2/public/api/users?page=2"
 },
 "meta": {
 "current_page": 1,
 "from": 1,
 "last_page": 7,
 "path": "http://api-fields.lab.php71/api/users",
 "per_page": 3,
 "to": 3,
 "total": 20
 }
}

6- 总结

本文目标是让Resource类通过隐藏一些在其他接口允许暴露的字段从而变得更加灵活。例如当我们请求/users接口时响应的数据是不包含avatar字段的,但是当请求/users/99时响应的数据里包含avatar字段。

我不推荐过度重复去请求API资源,因为它很可能会把简单的事情变得更加复杂,所以说在请求的时候隐藏某些特定的字段是更简单、更合理的解决方案。

以上所述是小编给大家介绍的在 Laravel 中动态隐藏 API 字段的方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

PHP 相关文章推荐
一个简单的自动发送邮件系统(二)
Oct 09 PHP
PHP编程最快明白(第一讲 软件环境和准备工作)
Oct 25 PHP
PHP基础教程(php入门基础教程)一些code代码
Jan 06 PHP
CodeIgniter实现更改view文件夹路径的方法
Jul 04 PHP
php新浪微博登录接口用法实例
Dec 23 PHP
PHP设置进度条的方法
Jul 08 PHP
php编程每天必学之验证码
Mar 03 PHP
PHP读取大文件的几种方法介绍
Oct 27 PHP
PHP 二级子目录(后台目录)设置二级域名
Mar 02 PHP
php curl上传、下载、https登陆实现代码
Jul 23 PHP
深入学习微信网址链接解封的防封原理visit_type
Aug 15 PHP
关于Laravel-admin的基础用法总结和自定义model详解
Oct 08 PHP
Laravel 实现添加多语言提示信息
Oct 25 #PHP
Laravel5.5 动态切换多语言的操作方式
Oct 25 #PHP
解决php扩展安装不生效问题
Oct 25 #PHP
Laravel实现通过blade模板引擎渲染视图
Oct 25 #PHP
laravel 解决Validator使用中出现的问题
Oct 25 #PHP
laravel接管Dingo-api和默认的错误处理方式
Oct 25 #PHP
Laravel 解决419错误 -ajax请求错误的问题(CSRF验证)
Oct 25 #PHP
You might like
在openSUSE42.1下编译安装PHP7 的方法
2015/12/24 PHP
php文件上传 你真的掌握了吗
2016/11/28 PHP
2017年最好用的9个php开发工具推荐(超好用)
2017/10/23 PHP
详解thinkphp中的volist标签
2018/01/15 PHP
浅谈PHP中的那些魔术常量
2020/12/02 PHP
jQuery 第二课 操作包装集元素代码
2010/03/14 Javascript
Notify - 基于jquery的消息通知插件
2011/10/18 Javascript
Javascript查询DBpedia小应用实例学习
2013/03/07 Javascript
用nodejs实现PHP的print_r函数代码
2014/03/14 NodeJs
asp知识整理笔记3(问答模式)
2015/09/27 Javascript
jQuery Pagination分页插件使用方法详解
2017/02/28 Javascript
JavaScript实现二维坐标点排序效果
2017/07/18 Javascript
除Console.log()外更多的Javascript调试命令
2018/01/24 Javascript
Vue 全局loading组件实例详解
2018/05/29 Javascript
JS实现页面数据懒加载
2020/02/13 Javascript
Vue.js中Line第三方登录api的实现代码
2020/06/29 Javascript
[04:42]2015国际邀请赛CDEC战队晋级之路
2015/08/13 DOTA
[56:20]LGD vs VP Supermajor 败者组决赛 BO3 第三场 6.10
2018/07/04 DOTA
Python类的用法实例浅析
2015/05/27 Python
详解Python3中yield生成器的用法
2015/08/20 Python
Sanic框架请求与响应实例分析
2018/07/16 Python
详解Django+Uwsgi+Nginx 实现生产环境部署
2018/11/06 Python
Python 数值区间处理_对interval 库的快速入门详解
2018/11/16 Python
Python BeautifulSoup [解决方法] TypeError: list indices must be integers or slices, not str
2019/08/07 Python
详解win10下pytorch-gpu安装以及CUDA详细安装过程
2021/01/28 Python
EJB面试题
2015/07/28 面试题
竞聘演讲稿范文
2014/01/12 职场文书
公司司机岗位职责范本
2014/03/03 职场文书
青蓝工程实施方案
2014/03/27 职场文书
村干部承诺书
2014/03/28 职场文书
2014年党员自我评议(5篇)
2014/09/12 职场文书
“四风”查摆问题自我剖析材料
2014/09/27 职场文书
2015年工程部工作总结
2015/04/30 职场文书
七年级语文教学反思
2016/03/03 职场文书
面试必问:圣杯布局和双飞翼布局的区别
2021/05/13 HTML / CSS
Oracle安装TNS_ADMIN环境变量设置参考
2021/11/01 Oracle