🌊

【Laravel】Eloquentの値返却とResourceCollectionに渡す際の工夫

2023/08/20に公開

eloquentからの返却値の形式がCollectionの時とModelの時で何が違うのか。
形式の違うインスタンスをそれぞれresourceCollectionで整形する為の工夫について解説します。

ModelインスタンスとCollectionインスタンス

  • Modelインスタンス
    テーブルの一行を表現するオブジェクト。
    eloquentで1レコードを取得する前提のメソッドの返却値はModelインスタンスになります。
    find, first, create…

  • Collectionインスタンス
    複数のModelインスタンスを含むオブジェクト。
    eloquentで複数のレコードを取得するメソッドの返却値はCollectionインスタンスになります。
    all, get…

サンプルコード

all

articlesテーブルを全権取得してddで確認すると、Collectionインスタンスが返却されます。
また、artcielsテーブルは1レコードのみだったのでそれをCollectionで取得してきています。
allや後述するwhereなどの複数レコードを取得する可能性があるメソッドが、一件だけを取得してきた場合もCollectionインスタンスとして扱われるところがポイントです。

$result = Article::all();

dd($result);

whereとfind

どちらも検索のクエリを掛けるメソッドですが、下記の違いがあります。

  • findで検索できるのはidのみ、whereは複数カラムで検索可能
  • whereはgetで取得を行う
  • findの取得は1件のみで、whereは複数権取得が可能

where

下記はwhereのサンプルです。
autoincrementのidが3なので、コードで直接3を指定してクエリを掛けています。

結果としては、Collectionインスタンスが返却されています。

$result = Article::where('id', 3)->get();

dd($return);

find

$return = Article::find(3);

dd($return);

findは1レコード前提のクエリなので、Modelインスタンスが返却されています。

ResourceCollectionへの渡し方

eloquentから取得したオブジェクトをresourceCollectionで整形してからレスポンスするケースです。

all

allではCollectionを取得できるので、resourceファイルでは$this-> でプロパティにアクセスできます

$result = Article::all();

return IndexArticleResource::collection($result);
class IndexArticleResource extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @return array<string, mixed>
     */
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'title' => $this->title,
            'content' => $this->content,
        ];
    }
}
// response

{
    "articles": [
        {
            "id": 3,
            "title": "title01",
            "content": "content01"
        }
    ]
}

where

whereもCollecitonで返却されるので$this-> でアクセスできます。

$result = Article::where('id', 3)->get();

WhereArticleResource::collection($result);
class WhereArticleResource extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @return array<string, mixed>
     */
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'title' => $this->title,
            'content' => $this->content,
        ];
    }
}
// response

{
    "article": [
        {
            "id": 3,
            "title": "title01",
            "content": "content01"
        }
    ]
}

find

findはModelインスタンスを返すので、ResourceCollectionに渡すにはcollectメソッドでCollection型に変換してあげる必要があります。
この場合はModelインスタンスがCollectionインスタンスに変換されるのではなく、Illuminate\Support\CollectionクラスにModelインスタンスがラップされる形でCollectionと同様の扱いをすることができるようになります。

$result= Article::find(3);

$collectResult = collect([ $result ]);

dd($collectionResult);

collectしたオブジェクトをResourceCollectionに渡してレスポンスを定義します。

$result= Article::find(3);

$collectResult = collect([ $result ]);

FindArticleResource::collection($result);
class FindArticleResource extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @return array<string, mixed>
     */
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'title' => $this->title,
            'content' => $this->content,
        ];
    }
}
// response

{
    "article": [
        {
            "id": 3,
            "title": "title01",
            "content": "content01"
        }
    ]
}

ModelインスタンスはResourceCollectionに渡せませんが、collectによって渡せるようになりました。

Discussion