在 Laravel 中动态 隐藏 / 显示 API 字段
最近项目有多个不同类型前端,所以在给api返回数据的时候需要隐藏某些字段
之前看了一篇文章在 Laravel 中动态隐藏 API 字段觉得还是有点不方便,所以就自己弄了一个。
目前实现了三个方法
- 设置隐藏的字段
hide
方法 - 设置显示的字段
show
方法 - 设置类型
type
方法(在toArray里面判断类型返回相应的数据)
Resource
实现
首先看Resource
如何实现
自定义一个BaseResource
继承Resource
。。额!直接上代码吧
class BaseResource extends Resource
{
protected $withoutFields = [];
private $hide = true;
protected $type = 'default';
public function type(string $request)
{
$this->type = $request;
return $this;
}
public function hide(array $fields)
{
$this->withoutFields = $fields;
return $this;
}
public function show(array $fields)
{
$this->withoutFields = $fields;
$this->hide = false;
return $this;
}
protected function filterFields($array)
{
if (!$this->hide) {
return collect($array)->only($this->withoutFields)->toArray();
}
return collect($array)->except($this->withoutFields)->toArray();
}
}
在相应的Resource
从原来的Resource
继承BaseResource
。继续上代码
class Channel extends BaseResource
{
public function toArray($request)
{
return $this->filterFields([
'id' => $this->id,
'name' => $this->name,
'cover' => $this->cover,
'user'=>[
'nickname'=>'small-dog',
'avatar'=>'xxx'
]
]);
}
}
如何使用??很简单啦
$channel = Channel::find(1);
ChannelResource::make($channel)->hide(['name','user.nickname']);//支持 . 来隐藏多维数组
ResourceCollection
实现
这个也差不多,就一点细微的差别
定义一个BaseResourceCollection
继承ResourceCollection
。。额!直接上代码吧
class BaseResourceCollection extends ResourceCollection
{
protected $withoutFields = [];
private $hide = true;
protected $type = 'default';
public function type(string $request)
{
$this->type = $request;
return $this;
}
public function hide(array $fields)
{
$this->withoutFields = $fields;
return $this;
}
public function show(array $fields)
{
$this->withoutFields = $fields;
$this->hide = false;
return $this;
}
public function toArray($request)
{
return [
'data' => $this->collection->map(function ($item) {
if (!$this->hide) {
return collect($item)->only($this->withoutFields)->all();
}
return collect($item)->except($this->withoutFields)->all();
}),
'meta' => $this->when(!empty($this->pageMeta()), $this->pageMeta())
];
}
//定义这个方法主要用于分页,当用josn返回的时候是没有 links 和 meta 的
public function pageMeta()
{
try {
return [
'current_page' => $this->resource->currentPage(),
'last_page' => $this->resource->lastPage(),
'per_page' => $this->resource->perPage(),
'total' => $this->resource->total(),
];
} catch (\BadMethodCallException $exception) {
return [];
}
}
}
自己的Collection
继承BaseResourceCollection
class ChannelCollection extends BaseResourceCollection
{
}
toArray
都可以省了,哈哈哈!!!
使用方法
$channel = Channel::query()->where('user_id', $user->id)->orderByDesc('id');
$page = $channel->paginate(10);//当用get的时候是没有meta这个字段的
$data['list'] = ChannelCollection::make($page)->hide(['name','user.nickname']);
最后说一个设置类型的作用,一个资源文件要处理不同类型的数据,比如一个是给APP的,一个是给商家后台的
public function toArray($request)
{
if ($this->type == 'edit') {
return $this->filterFields([
'id' => hashid_encode($this->id),
]);
}
return $this->filterFields([
'id' =>$this->id,
]);
}
然后在使用的时候
$channel = Channel::find(1);
ChannelResource::make($channel)->type('edit')->hide(['name','user.nickname']);//支持 . 来隐藏多维数组
总结
本文目标是让Resource类通过隐藏一些在其他接口允许暴露的字段从而变得更加灵活,可能会有问题,目前我还没遇到,今天才弄出来的~~~
如果有类型需求的小伙伴用了这个发现问题可以讨论哦~~~
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: