laravel-query-builders について
Laravel開発向けのスキルで、ローカルスコープの代わりにカスタムEloquentクエリビルダーを使う方法を示します。型安全なリレーション検索、メソッドチェーン、再利用可能なクエリロジックを扱います。
主な機能
- 01カスタムEloquentビルダーのパターン
- 02型安全なネストされたリレーション検索
- 03チェーン可能なクエリメソッド
- 04再利用可能なビルダートレイト
- 05モデルへのビルダー登録
活用シーン
- 01注文や顧客の条件の整理
- 02型安全なリレーション検索の作成
- 03複数のビルダーでのクエリロジック再利用
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ leeovery/ claude-laravel --skill laravel-query-buildersインストール後、Claude Code で/laravel-query-buildersを入力して読み込まれたか確認します。
詳細
Laravel クエリビルダー
ローカルスコープではなく、必ずカスタムクエリビルダーを使用してください。
関連ガイド:
スコープよりカスタムビルダーを使う理由
❌ ローカルスコープは使用しないでください。
✅ カスタムクエリビルダーを使用してください。次のような利点があります:
- 型ヒントの改善 - IDE の自動補完を最大限に活用できます
- 型安全なネストされたクエリ -
whereHas()、orWhereHas()などのクロージャに型ヒントを指定できます - 整理しやすい - すべてのクエリロジックを 1 つのクラスにまとめられます
- 合成しやすい - チェーンや合成が簡単です
- テストしやすい - クエリロジックを単独でテストできます
基本的なビルダー構造
<?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 サポートを提供します
- 型安全なネストされたクエリを実現します
- クエリロジックを整理できます
- テストが簡単です
- メソッドチェーンをサポートします
ローカルスコープは使用せず、必ずカスタムビルダーを使用してください。
コメント
Markdown 対応