backfron / laravel-finder
轻松构建和处理复杂的Eloquent搜索。
Requires
- php: ^8.2
- illuminate/support: ~11
Requires (Dev)
- orchestra/testbench: ~9.0
- phpunit/phpunit: ^11.0.1
README
backfron/laravel-finder 提供了一种使用 ELoquent 以可扩展的方式构建复杂数据库搜索的简单方法。如果您有一个包含多个字段以过滤数据的形式,LaravelFinder 可能符合您的需求。
// Instead of something like these $companies = (new App\Models\User)->newQuery(); if (request()->has('city')) { $companies->where('city', request('city')); } if (request()->has('status')) { $companies->where('status', request('status')); } if (request()->has('employess_number')) { $companies->where('employess_number', '<=' ,request('employess_number')); } // Now you can handle it like these $clients = CompanyFinder::filters([ 'city' => request('city'), 'status' => request('status'), 'employees_number' => request('employees_number'), ])->get();
这个包受到了 Amo Chohan 的 文章 的启发。
安装
通过 Composer
$ composer require backfron/laravel-finder
用法
搜索器
让我们假设我们需要为任务构建一个搜索功能。您有一个 Task 模型,并想根据状态、创建日期、所有者、完成日期等一个或多个条件执行查询。为此,您可能需要创建一个 搜索器。搜索器基本上是一个类,我们可以定义将要构建搜索的模型。LaravelFinder 提供了一个 artisan 命令来快速生成搜索器。
php artisan make:finder TaskFinder --model=Task
此命令将在 app/Finders/Tasks/TaskFinder.php 位置创建一个新的搜索器。如果您检查该文件,您会看到它是一个非常短的类,基本上存储了我们构建查询的模型。LaravelFinder 提供了一个 artisan 命令来快速生成搜索器。
namespace App\Finders\Tasks; use App\Models\Task; use Backfron\LaravelFinder\LaravelFinder; class TaskFinder extends LaravelFinder { protected static $model = Task::class; }
过滤器
接下来我们需要创建 过滤器。过滤器是写入查询逻辑的地方。每个过滤器应该处理单个字段条件。例如,如果我们需要通过状态搜索任务,我们只需创建一个针对该目的的过滤器。LaravelFinder 提供了一个 artisan 命令来快速生成您的过滤器。您必须指定过滤器的名称以及将要应用的模型。理想情况下,过滤器的名称应与数据库表中的字段名称匹配。
php artisan make:filter Status --model=Task
此命令将在 app/Finders/Tasks/Filters/Status.php 位置创建一个文件。这些文件包含一个类和一个名为 apply 的方法,该方法接收 Eloquent 查询构建器实例 (\Illuminate\Database\Eloquent\Builder) 和将用于搜索的值。
namespace App\Finders\Tasks\Filters; use Backfron\LaravelFinder\Contracts\FilterContract; use Illuminate\Database\Eloquent\Builder; class Status implements FilterContract { /** * Apply a filter to the query builder instance. * * @param Builder $builder * @param mixed $status * @return Builder $builder */ public static function apply(Builder $query, $status) { return $query->where('status', $status); } }
当然,您可以根据需要修改查询。例如
public static function apply(Builder $query, $status) { return $query->where('status', 'LIKE', "{$status}%"); }
您可以创建尽可能多的过滤器。例如,如果我们创建了状态、UserOwnerId 和 FinishedAt 过滤器,那么在您的控制器中,您可以接收包含这些字段的请求,并将其传递给您的搜索器的 filters 静态方法。
/* IMAGINE THIS INCOMING REQUEST [ status => 'completed', user_owner_id => 123, finished_at => '2021-10-01', ] */ use App\Finders\Tasks\TaskFinder; $tasks = TaskFinder::filters([ 'status' => request('status'), 'user_owner_id' => request('user_owner_id'), 'finished_at' => request('finished_at'), ])->get();
在内部,LaravelFinder 将获取字段名称并调用相应的过滤器。对于 status 字段,将调用 Status 过滤器,对于 user_owner_id 字段,将调用 UserOwnerId 过滤器,对于 finished_at 字段,将调用 FinishedAt 过滤器,依此类推。
设置过滤器后,您甚至可以调用在模型实例上通常调用的任何方法,这意味着您可以在应用过滤器后继续链接 Eloquent 方法。
use App\Finders\Tasks\TaskFinder; use Illuminate\Support\Facades\Auth; $tasks = TaskFinder::filters([ 'status' => request('status'), 'user_owner_id' => request('user_owner_id'), 'finished_at' => request('finished_at'), ]) ->where('user_id', Auth::id()) ->get();
如果一个字段没有匹配的过滤器会发生什么?不用担心,默认情况下 LaravelFinder 将忽略任何不匹配可用过滤器的字段。您可以通过发布配置文件 laravel-finder.php 来更改此行为
php artisan vendor:publish --tag=laravel-finder.config
一旦配置文件在 config/laravel-finder.php 中发布,您可以将 ignore-unexisting-filters 键设置为 false。当设置为 false 时,如果包含尚未存在的过滤器,LaravelFinder 将抛出 Backfron\LaravelFinder\Exceptions\FilterNotFoundException 异常。
您甚至可以在一个命令调用中创建您的搜索器和过滤器。
php artisan make:finder TaskFinder --model=Task --filter=Status --filter=UserOwnerId --filter=FinishedAt
全局过滤器
如果您想在查询中应用一个全局过滤器,您可以通过global方法并将闭包作为参数传递来实现。
use App\Finders\Tasks\TaskFinder; use Illuminate\Support\Facades\Auth; $tasks = TaskFinder::global(function ($query) { $query->where('user_owner_id', Auth::id()); }) ->filters([ 'status' => request('status'), 'finished_at' => request('finished_at'), ])->get();
如果您想将您创建的某些过滤器作为全局过滤器使用,您可以这样做
use App\Finders\Tasks\TaskFinder; use Illuminate\Support\Facades\Auth; use App\Finders\Tasks\Filters\Status; $tasks = TaskFinder::global(Status::class, 'completed') ->filters([ 'user_owner_id' => request('user_owner_id'), 'finished_at' => request('finished_at'), ])->get(); // Or add many global filters at once $tasks = TaskFinder::global([ [Status::class, 'completed'], function ($query) { $query->where('user_owner_id', Auth::id()); }, // ..., MORE // ..., GLOBAL // ..., FILTERS ]) ->filters([ 'finished_at' => request('finished_at'), ])->get();
待办事项
- 在过滤器文件蓝图包含一个条件,以避免在参数为空时应用过滤器。
变更日志
有关最近更改的更多信息,请参阅变更日志。
贡献
有关详细信息和工作清单,请参阅contributing.md。
安全
如果您发现任何与安全相关的问题,请通过jago86@gmail.com发送电子邮件,而不是使用问题跟踪器。
鸣谢
许可
有关更多信息,请参阅许可文件。