aldemeery / sieve
一种简单、简洁且优雅的方式来过滤Eloquent模型。
Requires
- php: >=7.1
- illuminate/console: >=5.80
- illuminate/database: >=5.8
- illuminate/http: >=5.8
- illuminate/support: >=5.8
Requires (Dev)
- php: >=7.3
- illuminate/database: ^7.0
- illuminate/http: ^7.0
- illuminate/support: ^7.0
- phpunit/phpunit: ^9.0
README
此包允许您根据查询字符串值过滤检索到的记录。
安装后,过滤从这样
public function index(Request $request) { $query = Product::query(); if ($request->has('color')) { $query->where('color', $request->get('color')); } if ($request->has('condition')) { $query->where('condition', $request->get('condition')); } if ($request->has('price')) { $direction = $request->get('price') === 'highest' ? 'desc' : 'asc'; $query->orderBy('price', $direction); } return $query->get(); }
缩小到这样
public function index(Request $request) { return Product::filter($request)->get(); }
安装
此包可用于Laravel 5.8或更高版本。您可以通过Composer安装此包
composer require aldemeery/sieve
服务提供程序将自动注册。或者,您可以在您的 config/app.php
文件中手动添加服务提供程序
'providers' => [ // ... Aldemeery\Sieve\FiltersServiceProvider::class, ];
使用
为模型启用过滤就像将 Aldemeery\Sieve\Concerns\Filterable
特性添加到您的模型(s)一样简单
use Aldemeery\Sieve\Concerns\Filterable; use Illuminate\Database\Eloquent\Model; class Product extends Model { use Filterable; // ... }
Filterable
特性为您的模型添加了一个 filter
本地作用域,该作用域接受一个 Illuminate\Htpp\Request
实例,因此它可以用于过滤,如下所示
public function index(Request $request) { return Product::filter($request)->get(); }
一旦您将特性添加到您的模型中并使用了 filter
方法,您只需开始创建过滤器即可。
创建过滤器
过滤器类是扩展了 Aldemeery\Sieve\Filter
的类。
您可以手动创建一个过滤器类并将其放在您喜欢的位置,或者使用 make:filter
artisan命令创建一个过滤器,该过滤器将被放置在 app/Http/Filters
目录中。
php artisan make:filter Product/ColorFilter
这将通常创建以下类
<?php namespace App\Http\Filters\Product; use Aldemeery\Sieve\Filter; use Illuminate\Database\Eloquent\Builder; class ColorFilter extends Filter { /** * Values mappings. * * @var array */ protected $mappings = [ // Silence is golden... ]; /** * Filter records based on a given value. * * @param \Illuminate\Database\Eloquent\Builder $builder Eloquent builder instance. * @param string $value The resolved value of the filtration key sent in the query string. * * @return void */ public function filter(Builder $builder, $value) { // } }
过滤器类中的 filter
方法是您应该放置您的过滤逻辑的地方。参数 $value
保存传递给查询字符串的特定过滤键的值。
/** * Filter records based on a given value. * * @param \Illuminate\Database\Eloquent\Builder $builder Eloquent builder instance. * @param string $value The resolved value of the filtration key sent in the query string. * * @return void */ public function filter(Builder $builder, $value) { // Assuming the URL is https://example.com/products?color=red // $value here is equal to 'red' return $builder->where('color', $value); }
注意:上面示例中的键 'color' 是在您实际上 使用过滤器 时定义的
由于您有一个 Illuminate\Database\Eloquent\Builder
的实例,您拥有其所有功能,这意味着您可以做所有不同的事情
- 排序
public function filter(Builder $builder, $value) { return $builder->orderBy('price', $value); }
- 通过关系过滤
public function filter(Builder $builder, $value) { return $builder->whereHas('category', function($query) use ($value){ return $query->where('name', $value); }); }
映射
有时您可能希望使用更有意义的值来作为查询字符串键,但是这些值可能不同于您实际上需要的过滤值,这就是 $mappings
出来帮忙的地方。
您可以在 $mappings
数组中定义您的值映射,它们将在传递给 filter
方法之前自动解析,继续阅读...
示例:假设您想要按价格对产品列表进行排序,并且您不希望在URL中有: ..?price=asc
或 ..?price=desc
,而是希望有类似: ..?price=lowest
或 ..?price=highest
的内容
为此,您有以下过滤器类
<?php namespace App\Http\Filters\Product; use Aldemeery\Sieve\Filter; use Illuminate\Database\Eloquent\Builder; class ColorFilter extends Filter { /** * Values mappings. * * @var array */ protected $mappings = [ 'lowest' => 'asc', 'highest' => 'desc', ]; /** * Filter records based on a given value. * * @param \Illuminate\Database\Eloquent\Builder $builder Eloquent builder instance. * @param string $value The resolved value of the filtration key sent in the query string. * * @return void */ public function filter(Builder $builder, $value) { // URL: https://example.com/products?price=lowest // $value is automatically set to be 'asc' instead of 'lowest' if ($this->validateValue($value)) { $builder->orderBy('price', $value); } } /** * Determine if a given value is valid. * * @param string $value Value to validate. * * @return bool */ private validateValue($value) { return in_array($value, ['asc', 'desc']); } }
使用“单独”的过滤器
一旦您创建了您的过滤器并定义了您的过滤逻辑,现在是时候实际使用过滤器了,这可以通过三种方式完成
- 将过滤器数组 作为第二个参数传递给
filter
作用域。 - 在模型本身 定义模型过滤器。
- 使用 过滤器包。
将过滤器数组传递给filter
当您想要对一个单一查询应用过滤器时使用此方法
public function index(Request $request) { return Product::filter($request,[ // "color" here is the key to be used in the query string // e.g. https://example.com/products?color=red "color" => \App\Http\Filters\Product\ColorFilter::class, ])->get(); }
在上面的示例中,过滤器将仅在此查询中查找键color的值,并将其传递到过滤器类内的filter
方法中,您在那里放置了您的过滤逻辑。
定义模型过滤器
Filterable
特性提供了一个filters
方法,该方法应返回一个数组,包含每次调用filter
方法时应应用于模型的所有“键”和“过滤器”。
<?php namespace App; use Aldemeery\Sieve\Concerns\Filterable; use Illuminate\Database\Eloquent\Model; class Product extends Model { use Filterable; /** * List of individual filters to be used by the model. * * @return array */ protected function filters() { return [ 'color' => \App\Http\Filters\Product\ColorFilter::class, ]; } }
现在每次您在模型上调用filter
方法时,都会自动应用ColorFilter
,而无需传递任何外部参数。
public function index(Request $request) { // The ColorFilter is automatically applied. return Product::filter($request)->get(); }
过滤器包
有时您可能有一个过滤器列表很大,使得您的模型看起来很杂乱,或者您可能想要将过滤器列表分组,以便在不同模型之间共享。这就是您想要有一个过滤器包的时候。
过滤器包是一个扩展了Aldemeery\Sieve\FilterBag
的类,其中包含一组始终一起应用的过滤器。
您可以手动创建自己的过滤器包类并将其放置在您喜欢的位置,或者使用make:filter-bag
命令创建一个过滤器包类,并将其放置在app\Http\Filters
目录中。
php artisan make:filter-bag Product/ProductFilters
这将通常创建以下类
<?php namespace App\Http\Filters\Product; use Aldemeery\Sieve\FilterBag; class ProductFilters extends FilterBag { /** * Filters to be applied. * * @var array */ protected static $filters = [ // ]; }
再次,请将“键”和“过滤器”对放在$filters
数组中
/** * Filters to be applied. * * @var array */ protected static $filters = [ 'color' => \App\Http\Filters\Product\ColorFilter::class, 'condition' => \App\Http\Filters\Product\UsedFilter::class, 'q' => \App\Http\Filters\Product\NameFilter::class, 't' => \App\Http\Filters\TrashedFilter::class, ];
完成之后,您只需在您的模型中覆盖Filterable
特性内的filterBag
方法,以返回应使用的过滤器包。
<?php namespace App; use Aldemeery\Sieve\Concerns\Filterable; use App\Http\Filters\Product\ProductFilters; use Illuminate\Database\Eloquent\Model; class Product extends Model { use Filterable; /** * Filter bag used by the model. * * @return string */ protected function filterBags() { return [ ProductFilters::class, ]; } }
现在每次在模型上调用filter
方法时,都会应用ProductFilters
中的所有过滤器。
public function index(Request $request) { // The filters from ProductFilters are automatically applied. return Product::filter($request)->get(); }
许可证
MIT许可证(MIT)。有关更多信息,请参阅许可证文件。