Chuyển đến nội dung chính

レッスン 4: 雄弁な ORM と関係

雄弁なモデル、一括割り当て、論理的な削除。関係 (hasOne、hasMany、belongsTo、belongsToMany、morphMany)。積極的な読み込み、クエリ スコープ、アクセサ/ミューテーター。キャスト。

💻 プログラミング — レッスン 4 レッスン 4: 雄弁な ORM と関係

Laravel: 基本から上級まで

パート 1: Laravel の基礎

xdev.asia

1. 雄弁なモデル

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Casts\Attribute;

class Product extends Model
{
    use SoftDeletes;

    protected $fillable = ['name', 'slug', 'description', 'price', 'stock', 'category_id'];

    protected function casts(): array
    {
        return [
            'price' => 'decimal:2',
            'is_active' => 'boolean',
            'metadata' => 'array',
            'published_at' => 'datetime',
        ];
    }

    // Accessor (Laravel 11)
    protected function formattedPrice(): Attribute
    {
        return Attribute::make(
            get: fn () => number_format($this->price) . 'đ',
        );
    }
}

2. 人間関係

class Product extends Model
{
    // One-to-Many
    public function category()
    {
        return $this->belongsTo(Category::class);
    }

    public function reviews()
    {
        return $this->hasMany(Review::class);
    }

    // Many-to-Many
    public function tags()
    {
        return $this->belongsToMany(Tag::class)->withTimestamps();
    }

    // Has One Through
    public function brandCountry()
    {
        return $this->hasOneThrough(Country::class, Brand::class);
    }

    // Polymorphic
    public function images()
    {
        return $this->morphMany(Image::class, 'imageable');
    }
}

// Sử dụng
$product->category->name;
$product->tags()->attach([1, 2, 3]);
$product->tags()->sync([1, 2]);

3. 熱心な読み込み

// N+1 prevention
$products = Product::with(['category', 'tags', 'reviews.user'])->get();

// Conditional eager loading
$products = Product::with(['reviews' => function ($query) {
    $query->where('rating', '>=', 4)->latest()->limit(5);
}])->get();

// Lazy eager loading
$products = Product::all();
$products->load('category');

// Prevent N+1 (development)
// AppServiceProvider
Model::preventLazyLoading(!app()->isProduction());

4. クエリのスコープ

class Product extends Model
{
    // Local scope
    public function scopeActive($query)
    {
        return $query->where('is_active', true);
    }

    public function scopePriceRange($query, float $min, float $max)
    {
        return $query->whereBetween('price', [$min, $max]);
    }
}

// Sử dụng
$products = Product::active()->priceRange(100, 500)->paginate(20);

次の記事: 移行、シーディング、クエリビルダー。