Laravel Query Builder:API 请求到 Eloquent 查询的优雅转换器

Laravel Query Builder:API 请求到 Eloquent 查询的优雅转换器

【免费下载链接】laravel-query-builder Easily build Eloquent queries from API requests 【免费下载链接】laravel-query-builder 项目地址: https://gitcode.com/gh_mirrors/la/laravel-query-builder

你是否曾经为构建复杂的 API 查询参数而头疼?是否厌倦了在控制器中编写重复的过滤、排序和关联查询逻辑?Laravel Query Builder 正是为了解决这些痛点而生!

什么是 Laravel Query Builder?

Laravel Query Builder 是一个强大的开源包,它允许你通过简单的 API 请求参数来构建复杂的 Eloquent 查询。这个包遵循 JSON API 规范,提供了优雅的方式来处理过滤、排序、字段选择和关联包含等常见需求。

核心优势一览

功能传统方式使用 Query Builder
基本过滤手动解析参数并构建 where 条件->allowedFilters('name')
关联查询复杂的 with 和 whereHas 组合->allowedIncludes('posts')
排序功能手动处理 sort 参数->allowedSorts('created_at')
字段选择手动 select 字段->allowedFields(['id', 'name'])
安全性需要手动验证参数内置白名单机制

快速开始:5分钟上手

安装配置

composer require spatie/laravel-query-builder

发布配置文件(可选):

php artisan vendor:publish --provider="Spatie\QueryBuilder\QueryBuilderServiceProvider"

基础使用示例

use Spatie\QueryBuilder\QueryBuilder;

class UserController extends Controller
{
    public function index()
    {
        $users = QueryBuilder::for(User::class)
            ->allowedFilters(['name', 'email', 'status'])
            ->allowedIncludes(['posts', 'profile'])
            ->allowedSorts(['created_at', 'name'])
            ->paginate();
            
        return UserResource::collection($users);
    }
}

现在你的 API 支持以下查询:

  • /users?filter[name]=John - 按名称过滤
  • /users?include=posts,profile - 包含关联数据
  • /users?sort=-created_at - 按创建时间倒序

深度解析:过滤功能详解

过滤类型对比表

过滤类型使用方法适用场景示例 URL
部分匹配allowedFilters('name')文本搜索?filter[name]=john
精确匹配AllowedFilter::exact('status')枚举值、ID?filter[status]=active
范围过滤AllowedFilter::scope('price_range')价格区间?filter[price_range]=100,500
关联过滤AllowedFilter::exact('posts.title')关联表查询?filter[posts.title]=Laravel
自定义过滤AllowedFilter::custom()复杂业务逻辑自定义实现

过滤功能流程图

mermaid

高级过滤示例

use Spatie\QueryBuilder\AllowedFilter;
use Spatie\QueryBuilder\Enums\FilterOperator;

$users = QueryBuilder::for(User::class)
    ->allowedFilters([
        // 基本部分匹配
        'name',
        'email',
        
        // 精确匹配
        AllowedFilter::exact('status'),
        AllowedFilter::exact('role_id'),
        
        // 范围操作符
        AllowedFilter::operator('salary', FilterOperator::GREATER_THAN),
        AllowedFilter::operator('age', FilterOperator::LESS_THAN_OR_EQUAL),
        
        // 关联过滤
        AllowedFilter::exact('posts.category_id'),
        AllowedFilter::partial('posts.title'),
        
        // 作用域过滤
        AllowedFilter::scope('created_between'),
        AllowedFilter::scope('has_premium_subscription'),
        
        // 自定义回调过滤
        AllowedFilter::callback('min_rating', function ($query, $value) {
            $query->whereHas('reviews', function ($q) use ($value) {
                $q->where('rating', '>=', $value);
            });
        }),
    ])
    ->get();

关联包含:优雅的 Eager Loading

关联包含类型

mermaid

关联包含示例

$products = QueryBuilder::for(Product::class)
    ->allowedIncludes([
        // 普通关联
        'category',
        'tags',
        'vendor',
        
        // 嵌套关联
        'category.parent',
        'reviews.user',
        
        // 关联计数
        AllowedInclude::count('reviews_count'),
        AllowedInclude::count('tags_count'),
        
        // 关联存在检查
        AllowedInclude::exists('has_discount'),
        
        // 自定义包含
        AllowedInclude::callback('related_products', function ($query) {
            $query->with(['relatedProducts' => function ($q) {
                $q->where('status', 'active');
            }]);
        }),
    ])
    ->get();

支持的 URL 查询:

  • /products?include=category,vendor - 包含分类和供应商
  • /products?include=reviews_count - 包含评论计数
  • /products?include=category.parent - 包含分类的父分类

排序功能:灵活的数据排序

排序配置示例

use Spatie\QueryBuilder\AllowedSort;

$users = QueryBuilder::for(User::class)
    ->allowedSorts([
        // 简单字段排序
        'name',
        'email',
        'created_at',
        
        // 自定义排序
        AllowedSort::field('registration_date', 'created_at'),
        AllowedSort::field('full_name', 'CONCAT(first_name, " ", last_name)'),
        
        // 回调排序
        AllowedSort::callback('popularity', function ($query, $direction) {
            $query->orderByRaw('(likes_count - dislikes_count) ' . $direction);
        }),
        
        // 关联表排序
        AllowedSort::field('category_name', 'categories.name'),
    ])
    ->get();

排序参数示例

排序方式URL 示例说明
升序?sort=name按名称升序排列
降序?sort=-created_at按创建时间降序
多字段?sort=category,-price先按分类升序,再按价格降序

字段选择:优化数据返回

字段选择配置

$users = QueryBuilder::for(User::class)
    ->allowedFields([
        'id',
        'name',
        'email',
        'created_at',
        'profile.avatar',
        'profile.bio',
    ])
    ->get();

支持的 URL 查询:

  • /users?fields[users]=id,name,email - 只返回用户的基本信息
  • /users?fields[users]=id,name&fields[profiles]=avatar - 返回用户信息和头像

安全最佳实践

白名单机制的重要性

Laravel Query Builder 采用白名单机制,确保只有明确允许的参数才会被处理,这提供了良好的安全性保障。

// 安全配置示例
$query = QueryBuilder::for(User::class)
    ->allowedFilters([ // 只允许这些过滤字段
        'name',
        'email',
        'status',
        AllowedFilter::exact('role_id'),
    ])
    ->allowedIncludes([ // 只允许这些关联
        'profile',
        'posts',
    ])
    ->allowedSorts([ // 只允许这些排序字段
        'name',
        'created_at',
    ])
    ->allowedFields([ // 只允许这些字段
        'id',
        'name',
        'email',
    ]);

配置选项

config/query-builder.php 中可以配置:

return [
    'parameters' => [
        'include' => 'include',
        'filter' => 'filter',
        'sort' => 'sort',
        'fields' => 'fields',
        'append' => 'append',
    ],
    
    'disable_invalid_filter_query_exception' => false,
    'disable_invalid_sort_query_exception' => false,
    'disable_invalid_include_query_exception' => false,
    'disable_invalid_field_query_exception' => false,
];

实际应用场景

电商产品搜索

public function searchProducts(Request $request)
{
    $products = QueryBuilder::for(Product::class)
        ->allowedFilters([
            'name',
            AllowedFilter::exact('category_id'),
            AllowedFilter::exact('brand_id'),
            AllowedFilter::scope('price_between'),
            AllowedFilter::scope('in_stock'),
            AllowedFilter::exact('tags.id'),
        ])
        ->allowedIncludes([
            'category',
            'brand',
            'images',
            'reviews',
            'reviews_count',
        ])
        ->allowedSorts([
            'price',
            'created_at',
            'popularity',
            'rating',
        ])
        ->allowedFields([
            'id',
            'name',
            'price',
            'image',
            'rating',
            'category.name',
        ])
        ->paginate($request->per_page ?? 20);
        
    return ProductResource::collection($products);
}

用户管理系统

public function getUsers(Request $request)
{
    $users = QueryBuilder::for(User::class)
        ->allowedFilters([
            'name',
            'email',
            AllowedFilter::exact('status'),
            AllowedFilter::exact('department_id'),
            AllowedFilter::scope('created_between'),
            AllowedFilter::trashed(),
        ])
        ->allowedIncludes([
            'profile',
            'roles',
            'department',
            'posts_count',
        ])
        ->allowedSorts([
            'name',
            'email',
            'created_at',
            'last_login_at',
        ])
        ->withTrashed() // 包含软删除的用户
        ->paginate($request->per_page ?? 15);
        
    return UserResource::collection($users);
}

性能优化建议

索引优化

-- 为常用的过滤字段创建索引
CREATE INDEX users_name_index ON users(name);
CREATE INDEX users_email_index ON users(email);
CREATE INDEX users_status_index ON users(status);

-- 为排序字段创建索引
CREATE INDEX users_created_at_index ON users(created_at);

查询优化技巧

  1. 避免 N+1 问题:使用 allowedIncludes 自动处理 eager loading
  2. 限制返回字段:使用 allowedFields 减少数据传输量
  3. 分页处理:始终使用 paginate() 而不是 get() 对于大量数据
  4. 缓存策略:对频繁查询的结果实施缓存

常见问题解答

Q: 如何处理复杂的业务逻辑过滤?

A: 使用 AllowedFilter::callback()AllowedFilter::custom() 来自定义过滤逻辑

Q: 如何支持多值过滤?

A: 使用逗号分隔的值,如 ?filter[category_id]=1,2,3

Q: 如何禁用异常处理?

A: 在配置文件中设置相应的 disable_*_exception 为 true

Q: 如何处理关联表的复杂查询?

A: 使用点符号,如 AllowedFilter::exact('posts.comments.user_id')

总结

Laravel Query Builder 是一个功能强大且灵活的包,它极大地简化了 API 查询参数的处理。通过白名单机制、丰富的过滤类型、灵活的排序和字段选择功能,它能够满足大多数 API 开发需求。

核心价值总结

  1. 开发效率:减少重复代码,提高开发速度
  2. 代码质量:统一的查询处理逻辑,更易维护
  3. 安全性:白名单机制防止非法参数
  4. 灵活性:支持各种复杂的查询场景
  5. 性能:自动优化查询,减少 N+1 问题

无论是简单的 CRUD 应用还是复杂的企业级系统,Laravel Query Builder 都能为你提供优雅的解决方案。开始使用它,让你的 API 开发体验更加愉快!

【免费下载链接】laravel-query-builder Easily build Eloquent queries from API requests 【免费下载链接】laravel-query-builder 项目地址: https://gitcode.com/gh_mirrors/la/laravel-query-builder

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值