Model là cửa ngõ tới một bảng
namespace App\Models;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
#[Fillable(['category_id', 'name', 'slug', 'price', 'description', 'is_active'])]
class Product extends Model
{
use HasFactory;
protected function casts(): array
{
return ['is_active' => 'boolean'];
}
public function category(): BelongsTo
{
return $this->belongsTo(Category::class);
}
}
Đọc code cũ: trước Laravel 13, cột cho phép gán hàng loạt khai báo bằng thuộc tính
protected $fillable = [...](và cột ẩn bằng$hidden). Cách này vẫn chạy, bạn sẽ gặp rất nhiều trong dự án có sẵn. Model User của dự án mới là ví dụ chuẩn cho kiểu viết Laravel 13.
Truy vấn
Product::all();
Product::find(1);
Product::where('is_active', true)->orderByDesc('price')->paginate(12);
Product::where('price', '<', 200000)->count();
$product = Product::create(['name' => 'Áo thun', 'slug' => 'ao-thun', 'price' => 150000, 'category_id' => 1]);
$product->update(['price' => 120000]);
$product->delete();
Kết quả nhiều dòng là Collection, có map, filter, sum, groupBy... giống mảng JS nhưng mạnh hơn:
$total = Product::all()->sum('price');
Quan hệ
// Category.php
public function products(): HasMany
{
return $this->hasMany(Product::class);
}
$category->products; // danh sách sản phẩm của danh mục
$product->category->name; // danh mục của sản phẩm
Các loại thường gặp: hasOne, hasMany, belongsTo, belongsToMany (nhiều-nhiều qua bảng trung gian).
Bài toán N+1
$products = Product::all(); // 1 truy vấn
foreach ($products as $product) {
echo $product->category->name; // mỗi vòng thêm 1 truy vấn: 100 sản phẩm = 101 truy vấn
}
$products = Product::with('category')->get(); // chỉ 2 truy vấn
Bật chế độ báo lỗi khi lỡ tải lười, trong app/Providers/AppServiceProvider.php:
public function boot(): void
{
Model::preventLazyLoading(! $this->app->isProduction());
}
Scope: đặt tên cho truy vấn hay dùng
use Illuminate\Database\Eloquent\Attributes\Scope;
#[Scope]
protected function active(Builder $query): void
{
$query->where('is_active', true);
}
Product::active()->get();
Code cũ viết scope bằng tên hàm bắt đầu với scope (ví dụ scopeActive); cách này vẫn chạy.
Bài tập
- Thêm quan hệ products vào Category và category vào Product.
- Trang danh sách sản phẩm: hiển thị tên danh mục, dùng with() để tránh N+1.
- Bật preventLazyLoading rồi thử bỏ with() để thấy lỗi xuất hiện.
- Viết scope active và dùng nó ở trang danh sách, phân trang 12 sản phẩm.
Xem thêm
- 30 Days to Learn Laravel, Ep 13 - Eager Loading and the N+1 Problem (kênh Laracasts, tiếng Anh, 11 phút)
- Eloquent N+1 Query: All You Need to Know (kênh Laravel Daily, tiếng Anh, 12 phút)
- Bài 13: Xây dựng chức năng CRUD Với Eloquent ORM (kênh Hải Đăng Dev, tiếng Việt, 31 phút)