使用 Laravel Scout 数据库驱动搜索 Eloquent 关系的实用指南
发布于 作者: Bilal Haidar
Laravel Scout 是一个用于为您的 Laravel 应用程序添加全文搜索功能的工具。它使用 Algolia、Meilisearch、SQL 数据库等驱动程序来搜索您的 Eloquent 模型。该包高度可定制,使其成为在您的应用程序中实现搜索功能的多功能选项。
让我们检查一下如何使用 Laravel Scout 和数据库驱动程序搜索 Eloquent 模型关系。请记住,Laravel Scout 驱动程序当前支持 MySQL 和 PostgreSQL。
让我们首先创建一个新的 Laravel 应用程序。为此,您可以查看 Laravel 文档.
创建模型和迁移
我们将使用两个 Eloquent 模型
- 帖子
- 类别
创建类别模型
运行以下命令以创建 Category
模型
php artisan make:model Category -m
此命令将在 app\Models 目录中创建一个新的 Category
模型类,并在数据库中生成一个用于创建 categories 表的迁移文件。
打开 database/migrations 目录中的迁移文件,并添加 categories 表所需的列。例如
public function up(){ Schema::create('categories', function (Blueprint $table) { $table->id(); $table->string('name'); $table->timestamps(); });}
创建帖子模型
运行以下命令以创建 Post 模型
php artisan make:model Post -m
该命令将在 app\Models 目录中创建一个新的 Post
模型类,并在数据库中生成一个用于创建 posts 表的迁移文件。
打开 database/migrations 目录中的迁移文件,并添加 posts 表所需的列。例如
public function up(){ Schema::create('posts', function (Blueprint $table) { $table->id(); $table->string('title'); $table->text('body'); $table->foreignId('category_id')->constrained(); $table->timestamps(); });}
应用迁移
假设您已为应用程序配置了数据库,请运行以下命令以应用迁移并在数据库中创建 posts 和 categories 表
php artisan migrate
使用数据库种子器生成虚拟数据
让我们创建一个数据库种子器,以生成 posts 和 categories 表的一些虚拟记录。
首先,通过运行以下 artisan 命令创建一个新的种子器类
php artisan make:seeder PostsCategoriesTableSeeder
打开位于 database/seeds 目录中的 PostsCategoriesTableSeeder 类,并将 run 方法更新为以下代码
<?php namespace Database\Seeders; use Illuminate\Database\Console\Seeds\WithoutModelEvents;use Illuminate\Database\Seeder;use Illuminate\Support\Facades\DB; class PostsCategoriesTableSeeder extends Seeder{ use WithoutModelEvents; public function run() { // Generate 5 categories $data = [ ['name' => 'News'], ['name' => 'Sports'], ['name' => 'Entertainment'], ['name' => 'Technology'], ['name' => 'Business'], ]; DB::table('categories')->insert($data); // Generate 1000 posts for ($i = 1; $i <= 1000; $i++) { DB::table('posts')->insert([ 'title' => "Post $i", 'body' => "Content for post $i", 'category_id' => rand(1, 5) ]); } }}
此种子器类生成五个虚拟类别和 1000 个虚拟帖子。每个类别的名称都是使用字符串和自动递增的 id 值的串联生成的,每个帖子的标题、正文和 category_id
是使用类似的方法生成的。category_id
是从类别列表中随机选择的。
要运行种子器,请将以下行添加到位于 database/seeds 目录中的 DatabaseSeeder
类的 run 方法中
$this->call(PostsCategoriesTableSeeder::class);
通过执行以下 artisan 命令运行种子器
php artisan db:seed
就是这样!现在,您有一个新的 Laravel 应用程序,其中包含 Post
和 Category
模型,以及已播种的虚拟数据。
配置应用程序以使用 Laravel Scout
要配置 Laravel 应用程序以使用 Laravel Scout 和数据库驱动程序,您需要按照以下步骤操作
首先,安装 Laravel Scout 包
composer require laravel/scout
接下来,发布 Scout 配置文件
php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"
现在在 .env 文件中,将 SCOUT_DRIVER 选项设置为 database
SCOUT_DRIVER=database
接下来,将 Laravel\Scout\Searchable 特性添加到您的模型中,以使其可搜索
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory;use Illuminate\Database\Eloquent\Model;use Laravel\Scout\Searchable; class Post extends Model{ use HasFactory; use Searchable;}
之后,在 Post
模型上定义 category()
关系,如下所示
public function category(){ return $this->belongsTo(Category::class);}
最后,在您的模型上定义 toSearchableArray() 方法,以指定 Laravel Scout 应该索引哪些字段
public function toSearchableArray(){ return [ 'title' => '', 'body' => '', 'categories.name' => '', ];}
要使用 Laravel Scout 对您的模型执行全文搜索,您需要在您的模型上定义一个 toSearchableArray()
方法。此方法应返回一个 Laravel Scout 应该索引的数据数组。
toSearchableArray()
方法应包含与搜索查询相关的数据。例如,如果您正在搜索属于特定类别的帖子,则可以在 toSearchableArray()
方法中包含 Category
模型的 name 字段。
就是这样!您现在应该能够使用 Laravel Scout 使用数据库驱动程序对您的模型执行全文搜索。
让我们搜索。
首先,创建一个新的 SearchController
来测试查询。
创建控制器
运行以下命令
php artisan make:controller SearchController --invokable
这将在 app/Http/Controllers 目录中创建一个新的 SearchController
类。控制器类将包含一个名为 __invoke()
的方法,该方法在调用控制器时被调用。
添加路由
要将 SearchController
用于您的应用程序,您需要在 routes/web.php 文件中为其定义一个路由
Route::get('/search', SearchController::class);
此路由将 GET 请求映射到 /search URL,以映射到 SearchController
的 __invoke() 方法。
编写搜索查询
打开 SearchController
类,并使用 Laravel Scout 添加我们的第一个查询。
<?php namespace App\Http\Controllers; use App\Models\Post;use Illuminate\Http\Request; class SearchController extends Controller{ public function __invoke(Request $request) { $posts = Post::search(trim($request->get('search')) ?? '') ->query(function ($query) { $query->join('categories', 'posts.category_id', 'categories.id') ->select(['posts.id', 'posts.title', 'posts.body', 'categories.name as category']) ->orderBy('posts.id', 'DESC'); }) ->get(); return response()->json(data: $posts, status: 200); }}
Post::search()
方法在 posts 数据库表上启动搜索查询。此方法返回 Builder 类 的实例。这意味着在通过 DatabaseEngine 实际执行查询之前,您可以应用一些函数,例如 where()
、whereIn()
、onlyTrashed()
、orderBy()
、take()
、paginate()
以及其他函数来进一步筛选您的结果。
trim($request->get('search')) ?? ''
输入参数从 HTTP 请求中检索查询字符串 search
,并修剪任何前导或尾随空格,如果搜索查询字符串不存在,则返回一个空字符串。
query() 函数允许您通过定义附加约束或修改查询的 SELECT
子句来自定义搜索查询。在这种情况下,查询使用 JOIN
子句与 categories 表联接,以搜索 posts 表列以及 categories 表的 name 列。此外,我通过用数据库名称加前缀列并添加 ORDER BY
子句(指定完整列名称,包括数据库表)来显式选择要返回的列。在没有对数据库表名称加前缀的情况下,查询将失败。
最后,get()
方法用于执行搜索查询并从数据库中检索匹配的帖子。
让我们在浏览器中运行应用程序,并提供值为“technology”的 search
查询字符串,以返回所有类别为“technology”的帖子。
结果的第一部分。
结果的最后部分。
让我们针对数据库运行一个查询,以检索类别为“Technology”的帖子,并进行比较。
相同查询的数据库结果。
如您所见,两者都返回相同的结果!
如您所见,search() 方法上的 query()
函数是搜索 Laravel Scout 数据库驱动程序中的关系的强大工具。
您可以在 GitHub 上下载源代码的副本。
您好 👋!我是 Bilal,Let's Remote 的创始人兼首席执行官。我是一名经验丰富的 Web 开发人员,拥有 16 年以上的经验。Laravel 是我的看家本领。