Skip to content

Laravel Query Builder 是一个基于接口设计、具备高扩展性的渐进式搜索构建包,旨在让 Laravel 中的复杂搜索更简单、更清晰、更优雅。

Notifications You must be signed in to change notification settings

mitoop/laravel-query-builder

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

79 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Laravel Query Builder

Laravel Query Builder 是一个基于接口设计、具备高扩展性的渐进式搜索构建包,旨在让 Laravel 中的复杂搜索变得更简单、更清晰、更优雅

它将搜索逻辑从控制器中彻底解耦,使列表搜索功能的开发更加集中、可维护,同时支持高度复用和灵活扩展。

本包的设计灵感来源于 zhuzhichao/laravel-advanced-searchspatie/laravel-query-builder,并结合实际业务需求进行了增强与重构。


特性

  • DSL 搜索规则:集中定义搜索逻辑,支持声明式、结构化、可复用的规则。
  • 支持排序与分页:可自定义排序字段,兼容 paginate()get() 等链式调用。
  • 值处理器(ValueResolver):统一处理输入值转换,避免重复闭包。
  • 字段类型灵活:支持 JSON 字段、关联字段、表别名字段。
  • 高级扩展:支持原生 SQL、闭包、自定义操作符、模型 Scope。
  • 接口驱动:几乎所有功能可通过自定义类替换,实现高度扩展。

环境需求

  • PHP >= 8.2
  • Laravel ^11.0 | ^12.0

安装

composer require mitoop/laravel-query-builder

快速上手

创建 Filter 类

Filter 类用于集中定义搜索逻辑,可通过 Artisan 快速生成:

php artisan make:filter UserFilter
class UserFilter extends AbstractFilter
{
    protected array $allowedSorts = ['id'];

    protected function rules(): array
    {
        return [];
    }
}

调用示例:

$users = User::filter(UserFilter::class)->paginate();

返回的是原生 Eloquent 查询构建器,仍支持链式调用 with()paginate()get() 等。


DSL 搜索规则

传统写法(控制器硬编码)

if ($request->filled('name')) {
    $query->where('name', $request->input('name'));
}
if ($request->filled('email')) {
    $query->where('email', 'like', '%'.$request->input('email').'%');
}

使用 DSL(集中在 Filter 中)

protected function rules(): array
{
    return [
        'name',
        'email|like' => new Like,
    ];
}

DSL 优势

  • 集中管理:所有规则在 rules() 中定义,控制器无需关心细节。
  • 结构化:清晰、易于阅读和维护。
  • 高复用:支持自定义操作符和值处理器,可在多个 Filter 中复用。
  • 可扩展:轻松支持 JSON、关联字段、模型 Scope 等复杂查询。

规则格式

[前端字段名]:[数据库字段]|[操作符]
  • 冒号用于前端字段与数据库字段映射(可选)
  • 竖线用于指定操作符(可选)
  • 支持索引数组、关联数组混合定义

示例:

protected function rules(): array
{
    return [
        'name', // 默认 eq
        'email|like' => $this->value('email', fn($email)=> "%{$email}%"),
        'created_at|between' => new DateRange,
        'nickname:profile->nickname|like' => new Like,
        'position$name|like' => new Like,
    ];
}

支持的操作符

  • 基础:eq, ne, gt, lt, gte, lte, like, in, not_in, between, is_null, not_null
  • JSON:json_contains
  • 自定义操作符:在 AppServiceProvider 注册
app(OperatorFactoryInterface::class)->register('new_operator', fn($app) => new NewOperator);

值处理器 ValueResolver

用于统一处理输入值,例如模糊搜索或日期范围:

class Like implements ValueResolver
{
    public function __construct(protected string $prefix = '%', protected string $suffix = '%') {}

    public function resolve($value): string
    {
        return $this->prefix.$value.$this->suffix;
    }
}

class DateRange implements ValueResolver
{
    public function resolve($value): ?array
    {
        if (! is_array($value) || count($value) !== 2) return null;

        try {
            [$start, $end] = $value;
            $start = Carbon::parse($start)->startOfDay();
            $end = Carbon::parse($end)->endOfDay();
        } catch (Throwable) {
            return null;
        }

        return [$start, $end];
    }
}

使用示例:

protected function rules(): array
{
    return [
        'email|like' => new Like,
        'created_at|between' => new DateRange,
    ];
}

如果前端传入值为 null 或空数组,该规则会自动跳过,避免无效查询。


高级规则支持

  • 原生 SQLDB::raw(...)
  • 闭包查询
function (Builder $builder) {
    $builder->where('is_verified', true);
}
  • 模型 Scope:支持 scopeXxx()#[Scope] 注解
  • 关键词搜索
$this->whenValue('keyword', function(Builder $builder, $keyword) {
    $builder->whereAny(['name', 'email'], 'like', "%{$keyword}%");
});

排序:sorts 方法

默认通过请求参数 sorts 提取排序条件,例如:

sorts=-id,name
  • 字段前加 - 表示降序,其他为升序
  • 可通过 $allowedSorts 限制允许排序字段
protected array $allowedSorts = ['id', 'name', 'created_at'];
  • 自定义请求参数:
SortResolver::sortFieldUsing('order_by');
  • 完全自定义排序:
protected function sorts(): array
{
    return [
        'id' => 'desc',
        'created_at asc',
    ];
}

生命周期钩子

  • booting():执行构建逻辑前调用,适合设置默认参数
public function booting(): void
{
    $this->data['status'] ??= 'active';
}
  • boot():构建逻辑正式开始前调用,适合动态注册过滤器或修改行为
public function boot(): void
{
    if (method_exists($this, 'with')) {
        $this->builder->with($this->with());
    }
}

完整示例:UserFilter

use Mitoop\LaravelQueryBuilder\Filters\AbstractFilter;
use Mitoop\LaravelQueryBuilder\Operators\Like;

class UserFilter extends AbstractFilter
{
    protected array $allowedSorts = ['id', 'created_at'];

    protected function rules(): array
    {
        return [
            'id',
            'name|like'  => new Like,
            'email|like' => new Like,
            'status|in',
            'created_from:created_at|gte',
            'created_to:created_at|lte',
            'created_at|between' => new DateRange,
            'nickname:profile->nickname|like' => new Like,
            'tag:profile->tags|json_contains',
            'position$name|like' => new Like,
            'u.name',
            new Scope('active'),
            $this->whenValue('keyword', function (Builder $builder, $keyword) {
                $builder->whereAny(['name', 'email'], 'like', "%{$keyword}%");
            }),
            'keyword|like_any' => new LikeAny(['name', 'email']),
            DB::raw('users.score > 100'),
            function (Builder $builder) {
                $builder->where('is_verified', true);
            },
        ];
    }
}

控制器使用:

$users = User::filter(UserFilter::class)->paginate();

贡献

有什么新的想法和建议,欢迎提交 issuePull Requests


协议

MIT

About

Laravel Query Builder 是一个基于接口设计、具备高扩展性的渐进式搜索构建包,旨在让 Laravel 中的复杂搜索更简单、更清晰、更优雅。

Topics

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages