開発ブログ

株式会社Nextatのスタッフがお送りする技術コラムメインのブログ。

電話でのお問合わせ 075-744-6842 ([月]-[金] 10:00〜17:00)

  1. top >
  2. 開発ブログ >
  3. PHP >
  4. Laravel >
  5. 【Laravel】JsonResourceクラスのwhen, mergeWhenメソッドを紹介

【Laravel】JsonResourceクラスのwhen, mergeWhenメソッドを紹介

こんにちは、モリです。 今回は、JsonResourceクラスを拡張したクラスで使用できるメソッドwhen, mergeWhenについて紹介します。
Laravel 10.20でmergeWhenメソッドが拡張されたのをきっかけに、既存のwhen, mergeWhenメソッドについて調べてまとめた記事となります。
そのため、5.6等の古いバージョンのLaravelでも使用できます。

環境

  • PHP: 8.1
  • Laravel Framework: 10.20.0

whenメソッド

日々の業務でJSONレスポンスを返すAPIを実装することが多く、そうした場合Illuminate\Http\Resources\Json\JsonResourceを継承したクラスを作成して取得したリソースをJSON構造に変換しています。
そうした中で、下記のように条件によってレスポンスに含める属性を変える場面によく遭遇します。

class BannerResource extends JsonResource
{
    /**
     * @var Banner
     */
    public $resource;

    public function toArray($request): array
    {
        $baseData = [
            'id' => $this->resource->id,
            'name' => $this->resource->name,
        ];

        if ($this->resource->type === BannerType::IMAGE) {
            $baseData = array_merge($baseData, ['imageUrl' => $this->resource->image_url]);
        }

        return $baseData;
    }
}

リソースのタイプ($this->resource->type)が画像(image)の場合は、imageUrlを含めた配列を返すようにしています。 こうした状況で、whenメソッドを使うと以下のように書くことができます。

    public function toArray($request): array
    {
        return [
            'id' => $this->resource->id,
            'name' => $this->resource->name,
            'imageUrl' => $this->when($this->resource->type === BannerType::IMAGE, $this->resource->image_url),
        ];
    }

whenメソッドを使わない場合と比べてすっきりした形で書くことができました。
また、このメソッドの特徴として、条件式がfalseの場合は、その属性を含めないということが挙げられます。例えば、whenメソッドを使わない書き方の別例として、以下のような書き方もできるのですが、条件式がfalseの場合でも値がnullでimageUrlが含まれてしまいます。 API設計として値がnullであることを許可しないのであれば、この後に属性を取り除く処理を加える必要があります。

    public function toArray($request): array
    {
        return [
            'id' => $this->resource->id,
            'name' => $this->resource->name,
            'imageUrl' => $this->resource->type == BannerType::IMAGE ? $this->resource->image_url : null,
        ];
    }

加えてwhenメソッドは、第二引数にクロージャを渡すこともできます。 クロージャを渡すことで、条件式がtrueの場合に返す値に対して複雑な処理を加えることも可能です。

    public function toArray($request): array
    {
        return [
            'id' => $this->resource->id,
            'name' => $this->resource->name,
            'imageUrl' => $this->when($this->resource->type === BannerType::IMAGE, function () {
                return $this->resource->image_url;
            }),
        ];
    }

mergeWhenメソッド

次に紹介するのは、mergeWhenメソッドです。
こちらもwhenメソッドと同様に条件式がtrueの場合にのみ、第二引数の値を返す使い方ができることに変わりはありませんが、複数の属性をレスポンスに含めたい際に用いることができます。

    public function toArray($request): array
    {
        return [
            'id' => $this->resource->id,
            'name' => $this->resource->name,
            $this->mergeWhen($this->resource->type === BannerType::IMAGE, [
                'imageUrl' => $this->resource->image_url,
                'imageAlt' => $this->resource->image_alt,
            ]),
        ];
    }

また、mergeUnlessメソッドも用意されていて、条件式がfalseの場合にのみ、第二引数の値を返す使い方ができます。

Laravel 10.20で拡張されたmergeWhenメソッドについて

前述したとおり、Laravel 10.20でmergeWhenメソッドが拡張されました。 下記のように第3引数に返したい値を渡せる等になり、条件式がfalseの場合に返す値を指定できるようになりました。

    public function toArray($request): array
    {
        return [
            'id' => $this->resource->id,
            'name' => $this->resource->name,
            $this->mergeWhen(
                $this->resource->type === BannerType::IMAGE,
                [
                    'imageUrl' => $this->resource->image_url,
                    'imageAlt' => $this->resource->image_alt,
                ],
                [
                    'movieUrl' => $this->resource->movie_url,
                ]
            )
        ];
    }

参考

https://laravel-news.com/laravel-10-20-0
https://readouble.com/laravel/10.x/ja/eloquent-resources.html#conditional-attributes

最後に

以上が、JsonResource継承クラスにおけるwhen, mergeWhenメソッドについての紹介となります。 JSONレスポンスを返すAPIを実装する場合には使う機会が多いと思いますので、ぜひ活用してみてください。
この他にも普段何気なく書いているコードをまだまだ整理できそうです。
ありがとうございました。

TOPに戻る