在 Laravel 中动态 隐藏 / 显示 API 字段

最近项目有多个不同类型前端,所以在给api返回数据的时候需要隐藏某些字段
之前看了一篇文章在 Laravel 中动态隐藏 API 字段觉得还是有点不方便,所以就自己弄了一个。
目前实现了三个方法

  1. 设置隐藏的字段 hide方法
  2. 设置显示的字段 show方法
  3. 设置类型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 协议》,转载必须注明作者和本文链接
本帖由系统于 3年前 自动加精
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 4

可以,学习了!!

3年前 评论

在 laravel 6 中, created_at,updated_at 日期格式 给格式化了.楼主遇到这个问题了吗

2年前 评论
wenber

如果使用 ChannelResource::collection($channels)这样就会报错了.

2年前 评论

withoutFields的意思是不要的字段吧?

11个月前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!