Laravel Eloquent Builder Macro: phù phép whereLike trong dự án thực tế
Vẽ vời một chút
Trong project thực tế chuyện tìm kiếm thứ gì đó trong database bằng LIKE xảy ra như cơm bữa.
Ví dụ tìm về bảng users với Model là User nha
User::query()
->where('name', 'LIKE', "%{$searchTerm}%")
->orWhere('email', 'LIKE', "%{$searchTerm}%")
->get();
Và bạn sẽ còn tìm ở nhiều nơi nữa, Post, Comment, Category, Tag, ... và bạn chán ngấy giống như mấy thằng sở khanh nó ngấy con ghẹ của nó trong khi bạn vẫn FA =)) vậy thì đổi cơn gió mùa xem sao
Sử dụng Laravel Eloquent Builder Macro
Bạn hãy mở App\Providers\AppServiceProvider
lên, trong function boot()
thêm đoạn này vào
use Illuminate\Database\Eloquent\Builder;
// ...
Builder::macro('whereLike', function(string $attribute, string $searchTerm) {
return $this->orWhere($attribute, 'LIKE', "%{$searchTerm}%");
});
Với đoạn search ở trên bạn có thể dễ dàng viết lại
User::query()
->whereLike('name', $searchTerm)
->whereLike('name', $searchTerm)
->get();
Ơ khoan, cải tiến một chút...
Nếu như viết ở trên thì có mẹ gì đâu mà phải vẽ vời đúng không nào =))
Bạn sẽ cần search nhiều field với một dữ liệu đầu vào là searchTeam, ta viết lại đoạn macro
Builder::macro('whereLike', function($attributes, string $searchTerm) {
foreach(array_wrap($attributes) as $attribute) {
$this->orWhere($attribute, 'LIKE', "%{$searchTerm}%");
}
return $this;
});
array_wrap
quả thật là một nice helper, bạn nạp vào array nó trả về array, bạn nạp vào string nó cũng trả về array, và lặp, không phải ngại.
Vậy đoạn search ở trên được viết lại như sau
// search một field
User::whereLike('name', $searchTerm)->get();
// search nhiều field
User::whereLike(['name', 'email'], $searchTerm)->get();
Chờ một chút, có bug đấy 👻
Bạn định tìm kiếm một user có role là admin và name hoặc email là chung, à ha nhanh chóng bạn sẽ viết ngay
User::query()
->where('role', 'admin')
->whereLike(['name', 'email'], 'chung')
->get();
À ha, cuộc đời bạn sẽ ngập ngụa trong bug ngay 💩💩 where ở trên sử dụng AND, whereLike sử dụng OR, và chẳng khác gì bạn tự SQL Injection chính mình đâu.
Cải tiến chút nữa coi ~
Builder::macro('whereLike', function ($attributes, string $searchTerm) {
$this->where(function (Builder $query) use ($attributes, $searchTerm) {
foreach (array_wrap($attributes) as $attribute) {
$query->orWhere($attribute, 'LIKE', "%{$searchTerm}%");
}
});
return $this;
});
Đấy ~ bạn nào giỏi tìm ra bug coi 😁😁
Đừng tự mãn thế chứ, làm gì cho ngầu chút đi 🙄🤔🤔
Hỗ trợ search các bảng quan hệ
Talk is cheap, show me the code, OK
Builder::macro('whereLike', function ($attributes, string $searchTerm) {
$this->where(function (Builder $query) use ($attributes, $searchTerm) {
foreach (array_wrap($attributes) as $attribute) {
$query->when(
str_contains($attribute, '.'),
function (Builder $query) use ($attribute, $searchTerm) {
[$relationName, $relationAttribute] = explode('.', $attribute);
$query->orWhereHas($relationName, function (Builder $query) use ($relationAttribute, $searchTerm) {
$query->where($relationAttribute, 'LIKE', "%{$searchTerm}%");
});
},
function (Builder $query) use ($attribute, $searchTerm) {
$query->orWhere($attribute, 'LIKE', "%{$searchTerm}%");
}
);
}
});
return $this;
});
Giờ thì bạn có thể search cả relation, ví dụ tìm một bài post mà keyword có thể là name, text (content), tên tác giả, tags có trong bài viết đó
Post::whereLike(['name', 'text', 'author.name', 'tags.name'], $searchTerm)->get();
Hết rồi ~ rảnh đọc kết chơi
Kết
Đọc tới đây hẳn bạn sẽ thấy ghen tị với Chung phải không, dễ hiểu mà độ đệp trai thanh lịch của Chung mấy ai mà không sinh lòng ganh ghét cơ chứ 😄😄😁 - có gì đó sai nhưng mà thôi, bỏ qua đi. Bài viết lấy nguồn từ murze.be được Chung - (đáng lẽ ra là nhà văn nổi tiếng nhưng vì bố mẹ bắt đi lập trình) dịch và thêm muối cho vừa miệng
🎁🎁 💎 🎁🎁
Ủng hộ Chung Nguyễn Blog
Chung Nguyễn Blog sử dụng FlashVPS - Dịch vụ quản trị máy chủ chuyên nghiệp để quản lý VPS
#FlashVPS là dịch vụ cloud panel trên nền tảng web hỗ trợ khách hàng:
- * Quản lý máy chủ số lượng nhiều
- * Không có kinh nghiệm quản lý máy chủ
- * Thích sử dụng giao diện web đơn giản, trực quan hơn terminal
- * Quá nhàm chán với việc ghi nhớ và lặp lại việc gõ các câu lệnh
- * Muốn tự động hóa mọi thao tác
- * Muốn tiết kiệm thời gian quản trị máy chủ
- * Muốn tiết kiệm tiền bạc, nhân lực quản trị máy chủ 👉 https://flashvps.dev
Các bài viết trên website thường xuyên được đăng tải và cập nhật trên trang Facebook Chung Nguyễn Blog hãy tặng cho Chung một LIKE nhé! Mãi yêu các bạn!
813 👍
Bình luận
Nguyễn Duy Nguyên
Chung Nguyễn
Quốc Cường Nguyễn
Cho em hỏi xíu, em áp dụng thử thì ra lỗi "Class 'App\ProductDetails' not found"
app/Models
. Vậy làm sao custom lại để Builder hiểu tìm models ở trong thư mục "app/Models
" ạ. Hoặc có nếu em hiểu sai thì giải quyết như thế nào trong trường hợp này ạ.Chung Nguyễn
Nguyễn Văn Vũ
Chung Nguyễn
Lê Xuân Bình
Cho mình hỏi ngủ xíu:
ở đoạn code đầu tiên
Mình viết lại là
nó vẫn chạy, vậy query() đó dùng để làm gì vậy bạn ad?
Chung Nguyễn
Laravel sử dụng rất nhiều magic method, bản chất khi bạn gọi đến method where() Eloquent Model không hề có method này, nó tiến hành kích hoạt new Query Builder, vậy tác dụng của query() là kích hoạt new Query Builder để tạo câu lệnh SQL, và hệ thống bớt đi một bước xử lý.
Nguyen Manh
Cảm ơn tác giả, rất hay, mình sẽ thử áp dụng cho project hiện tại ^^
Nhân tiện mình đang có 1 vài vấn đề bác có thể hướng dẫn qua được không nhỉ ?
- 1 là orderBy với relationship được không nhỉ ? Ví dụ mình lấy ra Post::with(['author']), tuy nhiên mình lại muốn sắp sếp với author.name chẳng hạn.
- 2 là search like dữ liệu với mysql có cả tiếng Nhật, và yêu cầu là search phân biệt hiragana/katakana, nếu là alphabet thì phân biệt chữ hoa chữ thường, search đc cả ký tự đặc biệt kiểu như "&" và "%". Hiện tại giải phải của mình đang là để charset của field cần search like là "ujis", khi search thì sẽ thêm ký tự "\" trước param search để search được "%", và thêm UPPER($field) vào whereRaw. tuy nhiên mình thấy đang hơi cồng kềnh, và đi sửa thì cũng hơi mệt vì project khá rộng.
Cảm ơn bác :D
Chung Nguyễn
1. Được bạn nhé. Bạn sử dụng Closure (callback function cho relations)
2. Mình có làm một số dự án JP nhưng chưa có case phải search này nên chưa thể giúp gì cho bạn.
Trường hợp này bạn có thể dùng SearchEngine để tối ưu hơn nhé.
- Algolia
- Elastic Search