Tìm hiểu Laravel Scout
Bài đăng này đã không được cập nhật trong 5 năm
Laravel Scout là full-text
search dựa trên driver dành cho Eloquent. Ngoài ra, nó còn hỗ trợ Algolia, Elastic Search, và vì nó là full-text search dựa trên driver nên bất cứ ai cũng có thể tạo sự tích hợp của riêng mình với các hệ thông full-text search khác.
Laravel Scout hoạt động dựa trên nó thêm tính chất search
vào các model đã có. Sau đó chỉ việc đồng bộ hóa data với các dịch vụ tìm kiếm.
Đầu tiên chúng ta sẽ tải project mới về bằng composer
nhé
composer create-project --prefer-dist laravel/laravel demo_laravel_scout
Sau đó chúng ta vào file .env
để config database
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=scout
DB_USERNAME=root
DB_PASSWORD=
Sau đó để dùng được Scout
chúng ta phải cài package nó vào project thì mới chạy được
composer require laravel/scout
Khi bạn cài thành công Scout
rồi thì bạn dùng command line để publish config Scout nhé
php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"
Bây giờ bạn tưởng tượng rằng khi chúng ta đang search cũng chính là chúng ta đang tạo HTTP request tới Algolia
, Chúng có thể làm cho hệ thống của bạn chạy rất là chậm nếu hệ thống Algolia đang quá tải không trả kịp kết quả về cho hệ thống của chúng ta. Vậy phải có cách nào khắc phục chứ nhỉ, chúng ta sẽ mở file config/scout.php
set queue bằng true hoặc thêm dòng config này vào file .env
cũng dc nhé
SCOUT_QUEUE = true
Tiếp theo bạn cài Algolla Driver thông qua Composer
hoặc bạn cũng có thể dùng Elastic search nha.
composer require algolia/algoliasearch-client-php
Sau đó bạn phải khai báo id và secret của Algolia nhé. bạn vào website của Algolia sau đó tạo tài khoản. Sau đó login bạn lấy id
và secret
ở link này nhé : https://www.algolia.com/api-keys
Sau đó bạn mở file .env
ra rồi paste 2 dòng này vào
ALGOLIA_APP_ID = Bạn paste Application ID
ALGOLIA_SECRET = Bạn paste Admin API Key
Sau đó bạn sẽ import Laravel\Scout\Searchable
vào Model nào mà bạn muốn sử dụng tìm kiếm theo Scout
. Ví dụ mình sẽ import vào Post
Model nhé. Trước đó các bạn phải tạo bảng và seeder cho bảng posts
rồi đó nhé. Nếu các bạn chưa rõ thì các bạn có thể tham khảo bào viết Migration và Seeder nhé. Laravel sẽ đồng bộ hóa các record của posts với index Algolia mỗi khi vào bản ghi bài đăng được tạo mới , cập nhật hoặc xóa.
<?php
namespace App;
use App\Enums\PostVisibility;
use Laravel\Scout\Searchable;
use Carbon\Carbon;
class Post extends Model
{
use Searchable;
protected $fillable = [
'category_id',
'user_id',
'hash_id',
'title_vi',
'title_en',
'title_jp',
'views_count',
'published_at',
];
public function isPublished()
{
return $this->published_at !== null;
}
public function getRouteKeyName()
{
return 'hash_id';
}
/**
* Get the indexable data array for the model.
*
* @return array
*/
public function toSearchableArray()
{
$array = $this->only('title_vi', 'title_en', 'title_jp');
return $array;
}
}
Mình sẽ giới thiệu cho các bạn một số hàm khi dùng Scout
nhé
ĐỊnh nghĩa tên của chỉ mục Model bằng cách sử dụng ghi đè phương thức searchableAs()
. Nói một cách khác mỗi chỉ mục này nó giống như một bảng trong MySQL. Còn không mặc định nó sẽ là tên bảng ứng với Model.
public function searchableAs()
{
return 'posts_index';
}
Tiếp theo chúng ta sẽ định nghĩa những column nào trong bảng posts
sẽ có khả năng được tìm kiếm bằng cách sử dụng hàm toSearchableArray()
public function toSearchableArray()
{
$array = $this->only('title_vi', 'title_en', 'title_jp');
return $array;
}
Tiếp theo khi chúng ta chỉ muốn cho người dùng search những bài Post mà nó đã được published rồi thì chúng ta sẽ viết 2 phương thức sau trong model
public function isPublished()
{
return $this->published_at !== null;
}
public function toSearchableArray()
{
if (! $this->isPublished()) {
return [];
}
$array = $this->only('title_vi', 'title_en', 'title_jp');
return $array;
}
Nhưng thật may mắn, Scout
nó đã có phương thức giúp chúng ta có thể tách biệt, không còn phải sử dụng câu lệnh if
trong phương thức toSearchableArray()
nữa
public function isPublished()
{
return $this->published_at !== null;
}
public function shouldBeSearchable()
{
return $this->isPublished();
}
public function toSearchableArray()
{
$array = $this->only('title_vi', 'title_en', 'title_jp');
return $array;
}
Và đó nếu như mà phương thức shouldBeSearchable()
trả về giá trị true thì phương thức toSearchableArray()
sẽ trả về bình thường, nếu như là false
thì nó sẽ trả về một mảng rỗng.
public function getScoutKey()
{
return $this->hash_id;
}
Theo mặc định, Scout sẽ sử dụng khóa chính của Post Model như là unique ID
được lưu trữ trong search index
. Nếu bạn muốn custom , bạn có thể định nghĩa hàm trên nhé, nhưng nhớ là phải chọn trường nào nó unique
nhé.
Tiếp theo này, nếu như bạn cài Scout
khi bảng posts
nó có nhiều bản ghi rồi thì bạn cần phải import những bản ghi vào trong search driver
để nó có thể đánh được index search. Scout
cung cấp phương thực import
php artisan scout:import "App\Post"
Ngược lại, phương thức flush
sẽ loại bỏ tát cả các bản ghi của Post Model từ search index
php artisan scout:flush "App\Post"
Và từ các lần sau, khi bạn add mới bản ghi vào trong bảng posts
thì Scout sẽ tự động add record đó vào search index
.
Rồi ok, tiếp theo là làm thế nào để chúng ta có thể search được này )
Tiếp theo chúng ta tạo 1 file view blade
có 1 ô nhập từ khóa chúng ta search, và ở ngay dưới là danh sách trả về kết quả sau khi search.
Tiếp theo tạo controller và route
php artisan make:controller PostController
Route::get('index', 'PostController@index);
file PostController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Post;
class PostController extends Controller
{
public function search(Request $request)
{
if ($request->has('search')) {
$posts = Post::search($request->get('search'))->get();
} else {
$posts = Post::get();
}
return view('index', compact('posts'));
}
}
Hàm search()
nó nhận tham số đầu vào là giá trị mà chúng ta muốn tìm kiếm, thật dễ dãng phải không nào.
Giả sử
VD chúng ta đã sử dụng hàm searchableAs
ở trong model để quy định chỉ search theo title_vi
chẳng hạn thì chúng ta sẽ có thể thay đổi được nó khi sử dụng hàm within()
$posts = Post::search($request->get('search'))
->within('title_en')
->get();
// Lúc này nó sẽ search theo title_en
Sử dụng mệnh đề where()
$posts = Post::search($request->get('search'))
->where('category_id', 1)
->get();
paginate()
$posts = Post::search($request->get('search'))->paginate(10);
Nếu như trong trường hợp mà chúng ta muốn search cả những bản ghi mà chúng ta đã xóa mềm thì các bạn nhớ config trong file config/scout.php
như sau:
'soft_delete' => true
Khi đó các bạn mới dùng được các phương thức withTrashed()
và onlyTrashed()
trong truy vấn
// Khi chúng ta muốn lấy tất cả các bản ghi bao gồm đã xóa mềm
$posts = Post::search($request->get('search'))
->withTrashed()
->get();
// Khi chúng ta chỉ muốn lấy những bản ghi đã bị xóa mềm
$posts = Post::search($request->get('search'))
->onlyTrashed()
->get();
file web.php
<?php
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function () {
return view('welcome');
});
Route::get('index', 'PostController@search');
Vậy qua ví dụ nho nhỏ ở trên cũng phần nào sương sương giới thiệu đến các bạn Laravel Scout
nó làm cái gì. Cảm ơn các bạn đã đọc bài chia sẻ của mình.
All rights reserved