Xây dựng phương thức truy vấn tuỳ chỉnh với Laravel Eloquent Builder Macro

Khi bạn đối mặt với việc lặp lại nhiều câu truy vấn giống nhau. Laravel Eloquent Builder Macro sẽ là công cụ cứu cánh cho sự trừu tượng hóa, giúp mã nguồn của bạn trở nên linh hoạt hơn và giảm bớt gánh nặng của sự phức tạp.

Ví dụ một chút nhé:
Bạn đang muốn tìm kiếm các ứng viên có xuất hiện từ {$key} trong tên hoặc địa chỉ. Đoạn code của bạn trông sẽ như thế này:

PHP
Candidate::query()
        ->where('name', 'like', "%{$key}%")
        ->orWhere('address', 'like', "%{$key}%")
        ->get();

Và mỗi lần thêm trường tìm kiếm, bạn sẽ phải viết thêm vài dòng where như thế này nữa, và còn nhiều nơi khác trong source code đang làm điều tương tự, quá nhiều where “like” đúng không nào.

Sử dụng Laravel Eloquent Builder Macro

Bạn chỉ cần vào App\Providers\AppServiceProvider và khai báo đoạn code sau vào phương thức boot().

PHP
public function boot()
{
  Builder::macro('whereLike', function ($column, $value = null, $boolean = 'and') {
      return $this->where($column, 'like', $value, $boolean);
  });
}

Hoặc bạn cũng có thể đăng ký một Service Providers như sau:

1. Sử dụng Artisan Command:

PHP
php artisan make:provider MarcoServiceProvider

Lệnh này sẽ tạo ra một file mới tên là MarcoServiceProvider.php trong thư mục app/Providers.

2. Khởi tạo chức năng với phương thức boot():

PHP
public function boot()
{
  Builder::macro('whereLike', function ($column, $value = null, $boolean = 'and') {
      return $this->where($column, 'like', $value, $boolean);
  });
}

3. Đăng ký Service Provider:
Mở file config/app.php và thêm Service Provider vào mảng providers.

PHP
'providers' => [
    // ...
    App\Providers\MarcoServiceProvider::class,
],

Bây giờ bạn đã có thể dùng câu truy vấn whereLike rồi (happy).

Đoạn code ví dụ sẽ được viết lại như thế này:

PHP
Candidate::query()
        ->whereLike('name', "%{$key}%")
        ->whereLike('address', "%{$key}%", 'or')
        ->get();

Làm một cái gì đó gọn hơn nhé.

PHP
// App\Providers\MacroServiceProvider
Builder::macro('whereLike', function ($columns = [], $value = null, $boolean = 'and') {
    return array_map(function ($column) use ($value, $boolean) {
        $this->where($column, 'like', $value, $boolean);
    }, $columns);
});

Và khi sử dụng thì bạn chỉ cần truyền một array vào whereLike là đã ok rồi.

PHP
Candidate::query()
        ->whereLike(['name', 'address'], "%{$key}%", 'or')
        ->get();

Nhưng nếu một lúc nào đó, bạn chỉ muốn tìm kiếm những ứng viên có đang hoạt động (status = 1) thôi thì whereLike này có thể sẽ không còn đúng nữa. Ví dụ:

PHP
Candidate::query()
        ->whereLike(['name', 'address'], "%{$key}%", 'or')
        ->where('status', 1)
        ->get();

Đoạn code được viết lại:

PHP
Candidate::query()
        ->where('name', 'like', "%{$key}%")
        ->orWhere('address', 'like', "%{$key}%")
        ->where('status', 1)
        ->get();

Vậy bây giờ, việc cần làm là định nghĩa thêm một truy vấn mới và tái sử dụng whereLike.

PHP
Builder::macro('subWhereLike', function ($columns = [], $value = null, $boolean = 'or') {
    return $this->where(function ($q) use ($columns, $value, $boolean) {
        $q->whereLike($columns, $value, $boolean);
    });
});

Đã ổn hơn rồi, câu truy vấn đã được viết lại.

PHP
Candidate::query()
        ->where(function ($q) use ($key) {
            $q->where('name', 'like', "%{$key}%")
            $q->orWhere('address', 'like', "%{$key}%")
        })
        ->where('status', 1)
        ->get();

Trong một vài trường hợp, bạn mong muốn thêm một câu truy vấn khác nữa thì việc truyền thêm một Closure là điều cần thiết.

PHP
Builder::macro('subWhereLike', function ($columns = [], $value = null, $boolean = 'or', Closure $closure = null) {
    $query = $this->where(function ($q) use ($columns, $value, $boolean, $closure) {
        $q->whereLike($columns, $value, $boolean);
        
        if ($closure !== null) {
            $closure($q);
        }
    });

    return $query;
});

Sử dụng thôi nào!

PHP
Candidate::query()
        ->subWhereLike(['email', 'lastname'], "%{$key}%", 'or', 
            function ($query) use ($key) {
                $query->orWhere('phone', $key);
        })
        ->where('status', 1)
        ->get();

Hết rồi, bạn hãy thực hành và cảm nhận nhé!!!

0 Shares:
1 comment
Leave a Reply

Your email address will not be published. Required fields are marked *

You May Also Like
Read More

20 Laravel Eloquent Tips and Tricks (P1)

Eloquent ORM được sủ dụng rất nhiều trong 1 project Laravel, tuy nhiên để sử dụng được tối đa những gì Laravel cung cấp thì không phải ai cũng biết. Trong bài viết này mình sẽ chỉ cho các bạn một vài thủ thuật, hi vọng sẽ giúp ích cho các bạn trong một vài trường hợp cụ thể.
Read More

SOLID Principles

Table of Contents Hide Single-responsibility PrincipleOpen/Closed Principle (OCP)Liskov Substitution Principle (LSP)Interface Segregation Principle (ISP)Dependency Inversion Principle (DIP)Advantages of…