kodilab / laravel-filters
Laravel 过滤系统
Requires
- php: >=7.0
- illuminate/database: 5.5.*|5.6.*|5.7.*|5.8.*
- illuminate/support: 5.5.*|5.6.*|5.7.*|5.8.*
Requires (Dev)
- fzaninotto/faker: ^1.4
- orchestra/testbench: ~3.0
- phpunit/phpunit: ^7.0
This package is auto-updated.
Last update: 2020-09-06 11:10:15 UTC
README
Laravel-filters
是一个用于处理 Eloquent 模型过滤和集合过滤的 Laravel 包。该项目基于 Laracasts 视频教程。
使用 laravel-filters
,您可以通过简单、清晰且易于维护的方式应用过滤器。
默认情况下,过滤器直接与数据结构工作。当您正在过滤一个 Collection
时,过滤基于集合的 array
结构。如果您正在过滤一个 Eloquent model
,则过滤基于该 model
的数据库结构。
但是,您可以覆盖特定的过滤器或创建一个新的过滤器来定义过滤器的工作方式。我们将在下一节中介绍。现在让我们先使用默认过滤器。
例如,这是在 Controller
中调用过滤器的样子
// GET /cars?color=red&order_desc=created_at
$cars = Car::where(...)->filters(QueryFilter::class, $request->all())->get();
我们调用过滤器并传递请求查询参数数组(在这种情况下,['color' => 'red', 'order_desc' => 'created_at']
)。因此,laravel-filters
将应用一个名为 color
的过滤器,其值为 red
,以及“过滤器”(它不是一个真正的过滤器,我们稍后会解释)order_desc
,其值为 created_at
。
因为我们既没有覆盖也没有创建任何自定义过滤器,所以过滤器将使用前面解释的默认行为应用。
因此,在这种情况下,我们正在请求数据库中 color
列包含 red
值的汽车 Eloquent model
,并按 created_at
列降序排序。如您所见,我们通过没有额外代码的方式过滤了结果。简单且清晰。
如前所述,这仅是默认过滤行为。您可以通过覆盖过滤器或创建新的过滤器来获得所需的过滤行为。但让我们一步一步来。
1 - 入门
只需使用 composer
安装此包
composer require kodilab/laravel-filters ^1.0.0
2 - Eloquent 模型过滤器
如简介中所述,您能够过滤 Eloquent models
和 Collections
。为了使 model
准备就绪以便可过滤,添加 Filterable
特性
use Illuminate\Database\Eloquent\Model;
use Kodilab\LaravelFilters\Traits\Filterable;
class Car extends Model
{
use Filterable;
...
}
这就足够了。现在您可以使用过滤器,就像使用该 model
的 scope
一样
Car::filters(QueryFilters::class, ['filterA' => 'valueFilterA'])->get();
2.1 - filters()
范围
Filterable
特性只为模型添加了一个范围,即 filters()
,其签名如下(作为范围签名)
filters(string $filter_class, array $input = [], string $prefix = '')
- filter_class:过滤器类。您可以使用默认的一个(QueryFilters)或扩展它以创建新的过滤器或覆盖它们(这一步稍后会解释)。目前我们使用
QueryFilters:class
。 - input:一个关联数组,包含
[filter => value]
项。 - 前缀:有时,尤其是当你直接使用输入的
Request
数组($request->all()
)时,你不想使用该数组的所有项目。你可以使用前缀来标识你想要使用的项目。例如,如果你定义qf-
作为前缀,则qf-name
将从数组中作为过滤器(并通过name
列进行过滤)提取,而color
将被忽略,因为它不以qf-
开头。
2.2 - 默认过滤器行为解释
当过滤过程开始时,输入数组中的每个项目都会经过相同的处理。让我们假设 $input = ['color' => 'red']
是输入数组。 laravel-filters
将在 $filter_class
类上查找名为 color
的自定义方法。如果存在,则应用该方法所做的操作(这就是你如何定义自定义过滤器和覆盖过滤器的。我们将在下一节中详细说明)。如果没有自定义方法存在,则触发默认行为:它会尝试在模型的数据库表上查找名为 color
的列。如果存在,则按该列进行过滤。否则,它将简单地忽略该过滤器。
2.3 - 使用运算符处理默认行为
到目前为止,默认行为过滤器是按等式过滤。你可以进一步操作,添加一个 operator
来改变比较方式。想象你定义了这个输入: $input = ['year' => '2000', 'year-op' => 'gte']
。当一个过滤器有 -op
后缀时,它有特殊的意义:是一个过滤器运算符附加组件。它将修改过滤的默认行为。在这种情况下,由于我们定义了运算符为 gte
,它将按 year
列的值大于等于 2000
进行过滤(而不是使用 =
)。
这里你可以看到可用的默认运算符及其含义
"eq" => '='
"neq"=> '<>'
"gt" => '>'
"gte" => '>='
"lt" => '<'
'lte' => '<='
让我们用一个更复杂的例子来说明在控制器方法中使用请求数组
// GET /cars?color=red&color-op=neq&year=2000&year-op=gt
public function index(Request $request)
{
$cars = Cars::filters(QueryFilters:class, $request->all());
}
在这种情况下,$cars
将包含所有颜色不是红色(使用 neq
运算符)且年份大于 2000 的汽车。
排序方法
排序不被视为“过滤器”,但 laravel-filters
提供了一些帮助排序的实用方法。你可以使用“过滤器” order_desc
和 order_asc
来指示如何排序结果。就像我们在过滤器中做的那样,你只需要指示用于排序的列名。
以上一个例子为例,你可以这样定义排序
// GET /cars?color=red&color-op=neq&year=2000&year-op=gt&order_desc=color
public function index(Request $request)
{
$cars = Cars::filters(QueryFilters:class, $request->all());
}
我们将得到颜色不是红色且年份大于 2000 的汽车,并按 color
列排序。
3 - 集合过滤器
集合过滤器的功能与集合过滤器的工作方式相同。为了在集合中使用过滤器,你有两种选择
3.1 - 手动实例化过滤器
这是一种最保守的方法,因为你不需要创建一个扩展的 Collection
。然而,你必须每次想要过滤时都自己实例化过滤器。
这是一个在 Controller
方法中使用过滤器的例子
public function index(Request $request)
{
//Cars contains a collection
$data = new Collection($data);
//Instance the filters
$filters = new CollectionFilters();
//Then apply the filters. Apply() will return the filtered collection
$cars = $filters->apply($data, $request->all());
}
在这种情况下,我们不是使用 QueryFilters
过滤类,而是使用 CollectionFilters
。这很重要,当你与 Eloquent 模型
一起工作时,你必须使用 QueryFilters
或其扩展类。当你与 Collection
一起工作时,必须使用 CollectionFilters
或其扩展类。
3.2 - 扩展 Collection
这种方法稍微复杂一些,但它将让您以与使用 Eloquent 模型
相似的方式使用过滤器。首先,您应该创建一个继承自 \Illuminate\Support\Collection
的 Collection 类,并添加一个名为 filters()
的方法。记住,当您想过滤集合时,请使用这个新类而不是原始的 Collection
。
class Collection extends \Illuminate\Support\Collection
{
public function filters(string $filter_class, array $input = [], string $prefix = '')
{
/** @var CollectionFilters $filters */
$filters = new $filter_class();
return $filters->apply($this, $input, $prefix);
}
}
然后,您可以使用与模型过滤相似的方式使用 Collection
过滤器
public function index(Request $request)
{
//Cars contains a collection. Remember use the extended Collection you created before
$data = new Collection($data);
$cars = $data->filters(CollectionFilters::class, $request->all());
}
同样,我们在这里使用 CollectionFilters
而不是 QueryFilters
,因为我们正在处理 Collections
。
4 - 自定义过滤器
到目前为止,我们描述了默认行为。无需编写代码。所有操作都在后台进行。然而,有时您可能想要创建更多过滤器或覆盖现有的过滤器。这非常简单,只需扩展 QueryFilters
或 CollectionFilters
类并创建自己的方法。
通常,您将为每个模型创建一个扩展的 QueryFilters
类,因为每个模型都将有自己的自定义过滤器和要求。您将为您的项目中的每个集合创建一个扩展的 CollectionFilters
。
让我们为 Car
模型类创建一个扩展的 QueryFilters 类
class CarFilters extends QueryFilters
{
/*
* We are overridin the filter "color" in order to filter cars with an specific color which wheels are the same color
*/
protected function color($value)
{
//The idea here is adding statements to the $this->results (QueryBuilder containing the results)
// as we are extending a QueryFilters class
// If you are extending from CollectionFilters, $this->results contains the Collection.
//We change the behaviour, now filter color will filter by the car color AND the wheels color.
//The operator for this filter will be ignored
$this->results->where('color_wheels', $value)->where('color', $value);
//The new results MUST be returned
return $this->results;
}
}
现在,如果我们使用之前的相同请求
// GET /cars?color=red&color-op=neq&year=2000&year-op=gt&order_desc=color
public function index(Request $request)
{
$cars = Cars::filters(CarFilter:class, $request->all());
}
如您所见,我们更改了 filters()
的参数 QueryFilters:class
,以使用新的扩展类 CarFilters::class
。
在这种情况下,我们通过使用我们自定义的过滤器 color
获取到红色汽车,其轮子也是红色的。
您可以通过 $this->getFilterOperator(string $filter_name, $default = null)
轻松访问自定义过滤器中的操作符,它返回用于直接在 where
语句中使用(=, !=, <>, <, <=, >, >=
)的比较符号(如果存在)。