ambengers / query-filter
Laravel 资源过滤包,用于通过请求查询字符串过滤模型
Requires
- php: ^7.1|^8.0
Requires (Dev)
- laravel/legacy-factories: ^1.0.4
- mockery/mockery: ~1.0
- orchestra/testbench: ^6.0|^7.0|^8.0
- phpunit/phpunit: ^8.0|^9.0
README
此包提供了一种优雅的方式来通过请求查询字符串过滤 Eloquent 模型。
灵感来自 Laracasts
特性
此包允许您通过请求查询字符串创建过滤器。开箱即用,此包还提供对 Eloquent 模型的排序、分页和搜索功能。
安装
在终端中运行以下命令。
composer require ambengers/query-filter
然后通过运行以下命令发布配置文件。
php artisan vendor:publish --tag=query-filter-config
配置文件包含过滤类命名空间和路径的配置。默认命名空间为 App\Filters
,默认路径为 app/Filters
。
使用方法
基于方法的过滤器
您可以使用 make:query-filter
命令生成过滤器类。
php artisan make:query-filter PostFilter
在过滤器类中,您还可以定义自己的自定义过滤器。例如,让我们添加一个过滤器 /posts?published
以获取仅发布过的帖子
use Ambengers\QueryFilter\AbstractQueryFilter; class PostFilter extends AbstractQueryFilter { /** * Filter the post to get the published ones * * @return Illuminate\Database\Eloquent\Builder */ public function published() { return $this->builder->whereNotNull('published_at'); } }
现在,您可以在控制器中应用此过滤器。例如
use App\Filters\PostFilter; class PostController extends Controller { /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index(PostFilter $filters) { $posts = Post::filter($filters); return PostResource::collection($posts); } }
基于对象的过滤器
如果您更喜欢面向对象的方式来创建过滤器,您可以在 Filter 类中创建一个 $filters
数组来声明您的过滤器。
use Ambengers\QueryFilter\AbstractQueryFilter; class PostFilter extends AbstractQueryFilter { /** * List of filters. * * @var array */ protected $filters = [ 'published' => \App\Filters\Published::class, ]; }
$filters
数组将接收一个键值对,其中键是查询字符串中的参数,值是处理过滤的过滤器对象。
然后您可以使用 make:query-filter-object
命令生成您的过滤器对象。注意:过滤器对象将使用与您的过滤器类相同的命名空间。
php artisan make:query-filter-object Published
过滤器对象是一个简单的可调用类,它接受 Eloquent\Builder
作为第一个参数,将查询字符串值作为第二个参数。在 invoke 方法中包含过滤逻辑,如下所示。
use Illuminate\Database\Eloquent\Builder; class Published { /** * Handle the filtering * * @param Illuminate\Database\Eloquent\Builder $builder * @param string|null $value * @return Illuminate\Database\Eloquent\Builder */ public function __invokable(Builder $builder, $value = null) { $builder->whereNotNull('published_at'); } }
排序
此包还允许您通过 field|direction
语法对模型进行排序。
/** Sorting */
/posts?sort=created_at|desc
分页
此包还允许您按照如下方式对模型进行分页。
/** Pagination */ /posts?page=2
在幕后,它使用 Laravel 的分页,默认的 per_page
大小为 15。当然,您可以像这样覆盖此行为。
/** Pagination */ /posts?page=2&per_page=10
注意:如果请求查询字符串中不存在分页键,则将返回一个集合结果。
搜索
此包还允许您定义可搜索的列。默认情况下,当您使用 make:query-filter
命令生成过滤器类时,该类将包含一个 $searchableColumns
数组。然后,在此数组中列出您模型的可搜索列。
class PostFilter extends AbstractQueryFilter { /** * List of searchable columns * * @var array */ protected $searchableColumns = ['subject', 'body']; }
可搜索的关系列
如果要让模型通过关系字段进行搜索,则 $searchableColumns
可以接受一个键值对。
class PostFilter extends AbstractQueryFilter { /** * List of searchable columns * * @var array */ protected $searchableColumns = [ 'subject', 'body', 'comments' => ['body'], ]; }
可加载的关系
此包允许您使用查询字符串加载模型的关联关系。首先,使用 make:query-loader
命令创建您的加载类。
php artisan make:query-loader PostLoader
然后,在过滤器类中声明加载类。
use App\Loaders\PostLoader; class PostFilter extends AbstractQueryFilter { /** * Loader class * * @var string */ protected $loader = PostLoader::class; }
然后在加载类中,在 $loadables
数组中声明可以预加载/延迟加载的关联关系。
class PostLoader extends AbstractQueryLoader { /** * Relationships that can be lazy/eager loaded * * @var array */ protected $loadables = [ 'comments', 'author' ]; }
就这样!现在在您的查询字符串中使用 load
参数来加载关联关系。
/posts?load=comments,author
注意:在$loadables
数组中,可以使用驼峰式或蛇形命名法来声明多词关系的实体。该包会自动将关系转换为蛇形命名法,这是您编写关系方法时通常使用的方式。另外,即使在使用查询字符串时,未在$loadables
数组中声明的关联关系也不会进行延迟加载。
在控制器@show操作中使用Loader
Controller@show
操作通常返回单个模型实例而不是集合。但是,有时您可能需要通过查询字符串来可选地加载关联关系。
将加载器类作为参数注入到您的show
方法中,然后在您的对象上调用filter
方法并传入加载器实例。
class PostController extends Controller { /** * Display the specified resource. * * @param App\Models\Post $post * @param App\Loaders\PostLoader $loader * @return Illuminate\Http\JsonResponse */ public function show(Post $post, PostLoader $loader) { $post = $post->filter($loader); return response()->json($post); } }
现在您应该能够从查询字符串中加载您的关联关系了。
/posts/1?load=comments,author
包含软删除约束
当使用管道符号请求延迟加载的模型时,请包含软删除约束。
/posts/1?load=comments|withTrashed // comments will include soft deleted models /posts/1?load=comments|onlyTrashed // comments will include only soft deleted models
防止方法名冲突
要自定义在模型上调用以使用查询过滤器的方法名称,只需更新query_filter配置文件中的method
键的值。
return [ // The method to call to use the query filter 'method' => 'fooBar', // Now call $post->fooBar($loaders) ... ]
与Laravel Livewire一起使用
Livewire在向后端发送请求时遵循自己的结构。这使得查询过滤器包无法自动从请求查询字符串中读取参数。
然而,您仍然可以在运行时手动分配参数,通过从容器中解析查询过滤器类并设置parameters
,如下所示...
public function render () { $filters = app(PostFilter::class)->parameters(['search' => 'foo']); $posts = Post::filter($filters); return view('livewire.posts.index', ['posts' => $posts]); }