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

Bài 4: Eloquent ORM & Relationships

Eloquent models, mass assignment, soft deletes. Relationships (hasOne, hasMany, belongsTo, belongsToMany, morphMany). Eager loading, query scopes, accessors/mutators. Casts.

💻 Lập trình — Bài 4 Bài 4: Eloquent ORM & Relationships

Laravel: Từ Cơ bản đến Nâng cao

Phần 1: Laravel Fundamentals

xdev.asia

1. Eloquent Model

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. Relationships

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. Eager Loading

// 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. Query Scopes

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);

Bài tiếp theo: Migrations, Seeding & Query Builder.