Laravel Eloquent cung cấp hai phương thức để sửa đổi các chức năng truy vấn của một Model: phạm vi cục bộ (local scopes) và phạm vi toàn cục (global scopes). Trong bài mẹo này, chúng ta sẽ tập trung vào global scopes để sửa đổi câu truy vấn được áp dụng cho Model mỗi khi nó được gọi/truy xuất.
local scopes
global scopes
Khi viết một global scope, bạn có thể thêm nó trực tiếp trong hàm booted() của Class dưới dạng một hàm ẩn danh hoặc đăng ký nó thành một Class khác. Trong tài liệu của Laravel viết về một global scope dựa trên một Class khá là chuyên biệt cho một trường hợp duy nhất trong một ứng dụng, do đó, đừng để bị nó đánh lừa bạn, bởi vì tính năng này rất mạnh mẽ.
global scope
booted()
Một trong những điều mà chúng ta sử dụng global scope khá thường xuyên là áp dụng sắp xếp (sort) các kết quả trả về trong một Model. Tùy thuộc vào từng Model, mà bạn có thể có những kiểu sắp xếp khác nhau một cách hợp lý. Ví dụ hóa đơn có thể sắp xếp theo ngày tạo hoặc ngày gửi, hoặc các thành phố có thể được sắp xếp theo tên chẳng hạn.
Nếu bạn thấy rằng mình đang viết khá nhiều global scope thế này, thì đã đến lúc học các tái sử dụng chúng một cách tốt nhất để áp dụng cho các global scope của mình trong Model. Trong ví dụ dưới đây, hãy thêm một dòng vào hàm booted() của Model để sắp xếp kết quả của nó theo trường và direction unique cho Model này.
Dưới đây là cách dùng ở 2 model khác nhau:
File: app/Models/Country.php
namespace App\Models; use App\Scopes\OrderBy; class Country extends Model { protected static function booted() { static::addGlobalScope(new OrderBy('name', 'asc')); } ...
File: app/Models/User.php
namespace App\Models; use App\Scopes\OrderBy; class User extends Model { protected static function booted() { static::addGlobalScope(new OrderBy('email_verified_at', 'desc')); } ...
Vậy, global scope tái sử dụng sẽ trông như thế nào?
File: app/Scopes/Orderby.php
namespace App\Scopes; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Scope; class OrderBy implements Scope { protected $column; protected $direction; public function __construct(string $column, string $direction = 'asc') { $this->column = $column; $this->direction = $direction; } public function apply(Builder $builder, Model $model) { $builder->orderBy($this->column, $this->direction); } }
Vậy là chúng ta đã có được một global scope có thể tái sử dụng. Và đây chỉ là một ví dụ cơ bản. Nếu bất kỳ lúc nào bạn thấy bản thân viết nhiều biến thể khác nhau của một scope giống nhau, hãy nhớ tới điều này và xem xét viết cho mình một global scope để tái sử dụng nó. Vì lập trình không phải là viết đi viết lại một đoạn code giống nhau.
Đến đây thì mẹo thứ năm đã kết thúc, rất cảm ơn bạn đã chịu khó đọc đến đây, nếu có chỗ nào khó hiểu, bạn có thể để lại bình luận, mình sẽ trả lời lại cho các bạn trong sự hiểu biết của mình nhé. Hẹn gặp lại bạn trong mẹo tiếp theo.