backfron/laravel-finder

轻松构建和处理复杂的Eloquent搜索。

2.0.1 2024-06-12 13:56 UTC

This package is auto-updated.

Last update: 2024-09-12 14:28:05 UTC


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发送电子邮件,而不是使用问题跟踪器。

鸣谢

许可

有关更多信息,请参阅许可文件