在 Laravel 中動態 隱藏 / 顯示 API 欄位

SmallRuralDog發表於2018-03-02

最近專案有多個不同型別前端,所以在給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 協議》,轉載必須註明作者和本文連結

相關文章