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)。有关更多信息,请参阅许可证文件。