
Vì sao cần Advanced Eloquent?
Khi project lớn dần, bạn sẽ thấy:
- Query logic lặp lại ở nhiều nơi
- Controller chứa nhiều điều kiện filter
- Khó maintain và khó test
Advanced Eloquent giúp bạn:
- Tái sử dụng query
- Tách business rule khỏi controller
- Kiểm soát dữ liệu ở mức model
Tài liệu chính thức:
https://laravel.com/docs/eloquent
1️⃣ Local Scope – Tái sử dụng Query
Local scope giúp bạn đóng gói logic truy vấn trong model.
Ví dụ:
class User extends Model
{
public function scopeActive($query)
{
return $query->where('active', true);
}
}
Sử dụng:
User::active()->get();
Thay vì:
User::where('active', true)->get();
Ưu điểm:
- Clean controller
- Dễ đọc
- Tái sử dụng logic
Scope có tham số
public function scopeRole($query, $role)
{
return $query->where('role', $role);
}
Dùng:
User::role('admin')->get();
2️⃣ Global Scope – Áp dụng tự động
Global scope tự động áp dụng cho mọi query của model.
Ví dụ soft delete (mặc định Laravel đã dùng global scope).
Ví dụ custom global scope:
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;class ActiveScope implements Scope
{
public function apply(Builder $builder, Model $model)
{
$builder->where('active', true);
}
}
Đăng ký trong model:
protected static function booted()
{
static::addGlobalScope(new ActiveScope);
}
Giờ mọi query:
User::all();
Tự động thêm điều kiện active = true.
3️⃣ Multi-Tenant với Global Scope
Trong SaaS, mỗi user thuộc một tenant.
Bạn có thể tạo TenantScope:
class TenantScope implements Scope
{
public function apply(Builder $builder, Model $model)
{
$builder->where('tenant_id', auth()->user()->tenant_id);
}
}
Điều này giúp:
- Ngăn data leak
- Tự động filter dữ liệu
⚠ Cẩn thận khi dùng auth() trong global scope nếu chạy queue hoặc CLI.
4️⃣ Bỏ Global Scope Khi Cần
Bạn có thể bypass:
User::withoutGlobalScope(ActiveScope::class)->get();
Hoặc:
User::withoutGlobalScopes()->get();
Hữu ích cho admin panel hoặc report.
5️⃣ Attribute Casting Nâng Cao
Casting giúp đảm bảo kiểu dữ liệu.
protected $casts = [
'is_active' => 'boolean',
'settings' => 'array',
'published_at' => 'datetime',
];
Laravel còn hỗ trợ custom cast class.
Ví dụ:
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;class JsonCast implements CastsAttributes
{
public function get($model, $key, $value, $attributes)
{
return json_decode($value, true);
} public function set($model, $key, $value, $attributes)
{
return json_encode($value);
}
}
Dùng:
protected $casts = [
'metadata' => JsonCast::class,
];
6️⃣ Accessor & Mutator (Cách mới Laravel 9+)
Laravel hỗ trợ cú pháp mới:
use Illuminate\Database\Eloquent\Casts\Attribute;protected function fullName(): Attribute
{
return Attribute::make(
get: fn () => $this->first_name . ' ' . $this->last_name
);
}
Giúp code rõ ràng và type-safe hơn.
7️⃣ Khi nào nên tách Repository?
Nếu query bắt đầu:
- Phức tạp
- Có nhiều join
- Có nhiều điều kiện động
Bạn có thể tách sang:
- Repository
- Query object
- Service layer
Không phải lúc nào cũng cần repository.
Chỉ dùng khi có giá trị thực sự.
8️⃣ Performance Considerations
Global scope có thể:
- Ảnh hưởng performance nếu thêm điều kiện nặng
- Làm query phức tạp hơn
Luôn kiểm tra:
EXPLAIN SELECT ...
Tránh:
- Subquery không index
- Condition không cần thiết
Kết luận
Advanced Eloquent giúp bạn:
- Tái sử dụng query với Local Scope
- Bảo vệ dữ liệu với Global Scope
- Đảm bảo type với Casting
- Viết model sạch và maintainable
