xbhub/laravel-filter

一种简单、清晰且优雅的过滤 Eloquent 模型的方法。

维护者

详细信息

gitee.com/xbhub/laravel-filter

安装: 1,027

依赖者: 0

建议者: 0

安全: 0

2.1.0 2023-02-08 07:51 UTC

This package is auto-updated.

Last update: 2024-09-07 11:45:22 UTC


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.3 或更高版本。您可以通过 composer 安装此包

composer require xbhub/filter

服务提供程序将自动注册。或者您可以在您的 config/app.php 文件中手动添加服务提供程序

'providers' => [
    // ...
    Xbhub\Filter\FiltersServiceProvider::class,
];

用法

为模型启用过滤与将 Xbhub\Filter\Concerns\Filterable 特性添加到您的模型一样简单

use Xbhub\Filter\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 方法,您只需开始创建过滤器。

创建过滤器

过滤器类是一个扩展 Xbhub\Filter\Filter 的类。

您可以手动创建一个过滤器类并将其放在您喜欢的位置,或者使用 make:filter artisan 命令创建一个过滤器,该过滤器将被放置在 app/Http/Filters 目录中。

php artisan make:filter Product/ColorFilter

这将通常创建以下类

<?php

namespace App\Http\Filters\Product;

use Xbhub\Filter\Filter;
use Illuminate\Database\Eloquent\Builder;

class ColorFilter extends Filter
{
    /**
     * Filter values mappings.
     *
     * @var array
     */
    protected $mappings = [
        //
    ];

    /**
     * Filter records.
     *
     * @param Builder $builder
     * @param mixed   $value
     *
     * @return Builder
     */
    public function filter(Builder $builder, $value)
    {
        //
    }
}

过滤器类中的 filter 方法是您应该放置您的过滤逻辑的地方。$value 参数持有传递给此特定过滤器键的查询字符串值。

/**
 * Filter records.
 *
 * @param Builder $builder
 * @param mixed   $value
 *
 * @return Builder
 */
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 数组中定义您的值映射,然后使用过滤器类中的 resolveValue 方法来解决这些值。

resolveValue 方法从 $mappings 数组中解析值,如果找不到值则返回 null

注意 null,因为它有时会在过滤或排序记录时导致意外的行为。

示例:假设您想要按价格对产品列表进行排序,并且您不希望在 URL 中有 ..?price=asc..?price=desc,而是希望有 ..?price=lowest..?price=highest

为了实现这一点,您有以下过滤器类

<?php

namespace App\Http\Filters\Product;

use Xbhub\Filter\Filter;
use Illuminate\Database\Eloquent\Builder;

class ColorFilter extends Filter
{
    /**
     * Filter values mappings.
     *
     * @var array
     */
    protected $mappings = [
        'lowest' => 'asc',
        'highest' => 'desc',
    ];

    /**
     * Filter records.
     *
     * @param Builder $builder
     * @param mixed   $value
     *
     * @return Builder
     */
    public function filter(Builder $builder, $value)
    {
        // Assume $value is 'lowest'
        $value = $this->resolveValue($value);
        // $value now is 'asc'

        // URL doesn't have neither 'asc' nor 'desc'
        if ($value === null) {
            return $builder // Don't do anything
        }

        return $builder->orderBy('price', $value);
    }
}

使用“单个”过滤器

一旦您创建了您的过滤器和定义了您的过滤逻辑,现在是时候实际使用过滤器了,这可以通过以下三种方式完成

将过滤器数组传递给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 Xbhub\Filter\Concerns\Filterable;
use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    use Filterable;

    protected $fieldSearchable = [
        'name' => 'like',
        'id' => '=',
        'email' => 'like'
    ];

    /**
     * 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();
}

过滤器包

有时您可能有一个大型过滤器列表,这会让您的模型看起来很杂乱,或者您可能想将过滤器列表分组,以便在不同的模型之间共享。这就是您需要过滤器包的时候。

过滤器包是一个扩展自Xbhub\Filter\FilterBag的类,它包含一组总是一起应用的过滤器。

您可以选择手动创建过滤器包类并将其放置在您喜欢的位置,或者使用make:filter-bag命令来创建一个放在app\Http\Filters目录内的过滤器包类。

php artisan make:filter-bag Product/ProductFilters

这将通常创建以下类

<?php

namespace App\Http\Filters\Product;

use Xbhub\Filter\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 Xbhub\Filter\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();
}

默认过滤器


/users?search=name:John;email:john@gmail.com
/users?search=age:17;email:john@gmail.com&searchJoin=and
/users?filter=id;name
/users?filter=id;name&orderBy=id&sortedBy=desc
/users?orderBy=posts|title&sortedBy=desc
/users?with=groups
/users?withCount=groups

灵感来源

许可证

MIT许可证(MIT)。请参阅许可证文件以获取更多信息。