5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Laravelでシンプルかつ最強なAPIを作る設計パターン - QueryControlModel

Last updated at Posted at 2022-07-02

今回は私が実務でも利用しているLaravelを用いたAPI量産パターンの中で中核を担う QueryControlModel を利用したデザインパターンを紹介します。
もうこれ無しではやりにくくて困ってしまうくらいには便利な拡張になってます。

サンプルリポジトリ:madakaheri/sample-laravel-qc

Laravel + QueryControlModelを用いたシンプルで強力なAPI

実際に実務で利用しており、GraphQLよりも柔軟で強力なAPIを実現しています。
シンプルなCRUDを実装した後は、PolicyやRequestバリデーションを設定するだけでOK。

カスタム QueryControlModel トレイト

App\Models\TraitsにQueryControlModelを作成し、各モデルに継承させRequestのクエリストリングスから自由に検索、リレーションデータの追加、ページネーションをコントロールできるよう拡張しています。

namespace App\Models\Traits;

trait QueryControlModel
{
    /**
     * Append datas
     */
    public function scopeQueryControl($query)
    {
        return $query
        ->when(request()->query('select'), function ($query, $csv) {
            return $query->select(explode(',', $csv));
        })
        ->when(request()->query('with'), function ($query, $csv) {
            return $query->with(explode(',', $csv));
        })
        ->when(request()->query('withCount'), function ($query, $csv) {
            return $query->withCount(explode(',', $csv));
        });
    }

    /**
     * Please Override in Model
     */
    public function scopeQueryFilter($query)
    {
        return $query;
        // ex)
        // ->when(request()->query('user'), function ($query, $csv) {
        //     return $query->whereIn('user_id', explode(',', $csv));
        // })
    }

    /**
     * count(), paginate() and get() supported.
     */
    public function scopeQueryGet($query)
    {
        $count = request()->query('count', false);
        $paginate = request()->query('paginate', false);

        if ($count) {
            return $query->count();
        }
        if ($paginate) {
            return $query->paginate((int) $paginate);
        }
        return $query->get();
    }
}

QueryControlModelはRequestクエリにのみ反応するローカルスコープとして実装していますので、tinkerやバッチ処理の邪魔はしないようになっています。
scopeQueryControl($query)は各モデルでオーバーライドして使用します。

コントローラーメソッドでの利用

indexやshowメソッドから呼び出して使用します。

UserControllerの例

namespace App\Http\Controllers;

use App\Http\Requests\StoreUserRequest;
use App\Http\Requests\UpdateUserRequest;
use App\Models\User;

class UserController extends Controller
{
    public function index()
    {
        return User
        ::queryControl()// <-- withやwithCountのデータ追加
        ->queryFilter()//  <-- 各モデルのクエリフィルター
        ->queryGet();//    <-- count() / paginate(Int) / get() に対応
    }

    public function show($id)// <-- インジェクションせず $id として取り出します
    {
        return User
        ::queryControl()// <-- withやwithCountのデータ追加
        ->queryFilter()//  <-- 各モデルのクエリフィルター
        ->findOrFail($id);
    }
}
5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?