mcpField
L
laravel-query-builders

laravel-query-builders

github.com/leeovery開発4340 回インストール31 週間前に更新
リポジトリ

laravel-query-builders について

Laravel開発向けのスキルで、ローカルスコープの代わりにカスタムEloquentクエリビルダーを使う方法を示します。型安全なリレーション検索、メソッドチェーン、再利用可能なクエリロジックを扱います。

主な機能

  1. 01カスタムEloquentビルダーのパターン
  2. 02型安全なネストされたリレーション検索
  3. 03チェーン可能なクエリメソッド
  4. 04再利用可能なビルダートレイト
  5. 05モデルへのビルダー登録

活用シーン

  1. 01注文や顧客の条件の整理
  2. 02型安全なリレーション検索の作成
  3. 03複数のビルダーでのクエリロジック再利用

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/leeovery/claude-laravel --skill laravel-query-builders

インストール後、Claude Code で/laravel-query-buildersを入力して読み込まれたか確認します。

詳細

Laravel クエリビルダー

ローカルスコープではなく、必ずカスタムクエリビルダーを使用してください。

関連ガイド:

  • モデル - カスタムビルダーをモデルに統合する方法
  • コントローラー - コントローラーでクエリオブジェクトを使用する方法

スコープよりカスタムビルダーを使う理由

❌ ローカルスコープは使用しないでください。

✅ カスタムクエリビルダーを使用してください。次のような利点があります:

  1. 型ヒントの改善 - IDE の自動補完を最大限に活用できます
  2. 型安全なネストされたクエリ - whereHas()、orWhereHas() などのクロージャに型ヒントを指定できます
  3. 整理しやすい - すべてのクエリロジックを 1 つのクラスにまとめられます
  4. 合成しやすい - チェーンや合成が簡単です
  5. テストしやすい - クエリロジックを単独でテストできます

基本的なビルダー構造

<?php

declare(strict_types=1);

namespace App\Builders;

use App\Enums\OrderStatus;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;

class OrderBuilder extends Builder
{
    public function wherePending(): self
    {
        return $this->where('status', OrderStatus::Pending);
    }

    public function whereCompleted(): self
    {
        return $this->where('status', OrderStatus::Completed);
    }

    public function whereCustomer(User|int $customer): self
    {
        $customerId = $customer instanceof User ? $customer->id : $customer;
        return $this->where('customer_id', $customerId);
    }

    public function whereTotalGreaterThan(int $amount): self
    {
        return $this->where('total', '>', $amount);
    }

    public function wherePlacedBetween(Carbon $start, Carbon $end): self
    {
        return $this->whereBetween('placed_at', [$start, $end]);
    }

    public function withRelated(): self
    {
        return $this->with(['customer', 'items.product', 'shipments']);
    }

    public function recent(): self
    {
        return $this->latest('placed_at');
    }
}

型安全なネストされたクエリ

リレーションシップのクエリで IDE のサポートを最大限に活用するには、クロージャに型ヒントを指定します:

public function whereHasItems(array|string $productIds): self
{
    return $this->whereHas('items', function (OrderItemBuilder $query) use ($productIds): void {
        $query->whereIn('product_id', (array) $productIds);
    });
}

使用方法:

Order::query()
    ->whereHas('items', function (OrderItemBuilder $query): void {
        $query->whereActive()        // Custom method - autocomplete works!
              ->whereProduct($id);   // Full type safety!
    })
    ->whereHas('customer', function (CustomerBuilder $query): void {
        $query->whereVerified()      // Custom method
              ->wherePremium();      // IDE knows all methods!
    })
    ->get();

外部メソッドの PHPDoc

Spatie のパッケージやマクロのメソッドをドキュメント化します:

/**
 * @method static OrderBuilder whereState(string $column, string|array $state)
 * @method static OrderBuilder whereNotState(string $column, string|array $state)
 */
class OrderBuilder extends Builder
{
    // ...
}

ビルダートレイト

再利用可能なクエリロジックを切り出します:

<?php

declare(strict_types=1);

namespace App\Builders\Concerns;

use Illuminate\Support\Arr;

trait HasProducts
{
    public function whereHasProducts(array|string $productIds): self
    {
        return $this->whereHas('products', function ($query) use ($productIds): void {
            $query->whereIn('id', Arr::wrap($productIds));
        });
    }

    public function whereHasActiveProducts(): self
    {
        return $this->whereHas('products', function ($query): void {
            $query->where('active', true);
        });
    }
}

ビルダーでの使用方法:

class OrderBuilder extends Builder
{
    use HasProducts;

    // ...
}

モデルへのビルダー登録

推奨:PHP 属性(Laravel 11+)
use Illuminate\Database\Eloquent\Attributes\UseEloquentBuilder;

#[UseEloquentBuilder(OrderBuilder::class)]
class Order extends Model
{
    // ...
}
代替方法:静的プロパティ
class Order extends Model
{
    protected static string $eloquentBuilder = OrderBuilder::class;

    // ...
}
非推奨:メソッドのオーバーライド
// ❌ Don't use this approach anymore
public function newEloquentBuilder($query): OrderBuilder
{
    return new OrderBuilder($query);
}

使用例

基本的なチェーン
Order::query()
    ->wherePending()
    ->whereTotalGreaterThan(10000)
    ->wherePlacedBetween(now()->subWeek(), now())
    ->withRelated()
    ->recent()
    ->paginate();
遅延イテレーション
Order::query()
    ->whereCompleted()
    ->lazyById()
    ->each(function (Order $order): void {
        // Process order
    });
複雑なクエリ
$orders = Order::query()
    ->wherePending()
    ->whereCustomer($user)
    ->whereHasItems([$productId1, $productId2])
    ->wherePlacedBetween($startDate, $endDate)
    ->withRelated()
    ->get();

空のビルダー

将来の拡張に備え、最初は空であっても必ずビルダーを作成してください:

<?php

declare(strict_types=1);

namespace App\Builders;

use Illuminate\Database\Eloquent\Builder;

class CustomerBuilder extends Builder
{
    // Empty for now, but ready for future methods
}

よく使うビルダーメソッド

ステータスによる絞り込み
public function whereActive(): self
{
    return $this->where('status', 'active');
}

public function whereInactive(): self
{
    return $this->where('status', 'inactive');
}
日付範囲
public function whereCreatedAfter(Carbon $date): self
{
    return $this->where('created_at', '>', $date);
}

public function whereCreatedToday(): self
{
    return $this->whereDate('created_at', today());
}
ユーザー/所有者による絞り込み
public function whereUser(User|int $user): self
{
    $userId = $user instanceof User ? $user->id : $user;
    return $this->where('user_id', $userId);
}
リレーションシップの読み込み
public function withFullRelations(): self
{
    return $this->with([
        'user',
        'items.product',
        'customer.address',
    ]);
}

ビルダーの構成

app/Builders/
├── OrderBuilder.php
├── CustomerBuilder.php
├── ProductBuilder.php
└── Concerns/
    ├── HasProducts.php
    ├── HasDates.php
    └── HasStatus.php

まとめ

カスタムクエリビルダーは次の利点をもたらします:

  • スコープより優れた IDE サポートを提供します
  • 型安全なネストされたクエリを実現します
  • クエリロジックを整理できます
  • テストが簡単です
  • メソッドチェーンをサポートします

ローカルスコープは使用せず、必ずカスタムビルダーを使用してください。

コメント