albetnov/laravel-filterable

基于查询字符串的 Laravel 过滤器

v1.0 2024-03-13 09:35 UTC

This package is auto-updated.

Last update: 2024-09-08 01:55:29 UTC


README

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status Total Downloads

Laravel 模型可过滤,可自动根据给定的查询字符串过滤模型

安装

您可以通过 composer 安装此包

composer require albetnov/laravel-filterable

用法

简单地在您的模型中添加 Filterable 特性,并定义 $filterableColumnsfilterableColumns()(如果需要额外逻辑)以定义可过滤的列

<?php

namespace App\Models;

use Albet\LaravelFilterable\Enums\FilterableType;
use Albet\LaravelFilterable\Traits\Filterable;
use Illuminate\Database\Eloquent\Model;

class Flight extends Model {
    use Filterable;
    
    protected arrray $filterableColumns = [
        'ticket_no' => FilterableType::NUMBER,
        'customer_name' => FilterableType::TEXT,
        'schedule' => FilterableType::DATE
    ];
    
    protected function filterableColumns(): array {
        return [
            'customer_address' => FilterableType::custom(),
        ];
    }
}

获取可过滤列

如果两者都已定义,则 Filterable 会优先使用方法而不是属性。如: Filterable.php

如果没有定义,则 Filterable 将抛出 PropertyNotExist 异常。

可过滤类型

有五种可过滤类型选项可用

  • 数字
    此类型将给定负载转换为 float 或 int,具体取决于字符串是否包含 . 前缀(表示 float)或没有(表示 int)。

  • 文本
    一种用于处理基于文本的过滤器的类型。

  • 日期
    一种旨在处理基于日期的过滤器的类型。这将把负载转换为 Carbon 格式,并相应地调整查询。

  • 布尔值
    一种旨在处理基于布尔值的过滤器的类型。此类型将根据 01 将负载转换为布尔值。

修饰符

每个 FilterableType 都支持一个修饰符来改变从分配的字段进行过滤的行为。目前您可以使用两个修饰符。

  • 限制
    允许您限制可用的运算符,使其他运算符无效并抛出 OperatorNotExist 异常。该函数有一个参数,接收一个 Operators 数组。用法示例
use Albet\LaravelFilterable\Enums\FilterableType;
use Albet\LaravelFilterable\Enums\Operators;

protected function filterableColumns(): array {
    return [
        'customer_name' => FilterableType::TEXT->limit([Operators::CONTAINS, Operators::NOT_CONTAINS, 
        Operators::STARTS_WITH, Operators::ENDS_WITH])
    ];
}
  • 相关
    允许您将查询替换为使用 whereHas,以便过滤器应用于关系级别。该函数接收两个参数,第一个是关系名称,第二个是可选的额外查询条件。用法示例
use Albet\LaravelFilterable\Enums\FilterableType;
use Illuminate\Database\Eloquent\Relations\HasOne;

protected function filterableColumns(): array {
    return [
        'flight_license' => FilterableType::NUMBER->related('flight', fn($query) => $query->where('status', 'A'))
    ];
}

public function flight(): HasOne {
    $this->hasOne(Flight::class);
}

修饰符可以一起使用: FilterableType::DATE->related()->limit() 以组合条件

自定义类型

自定义类型不支持修饰符。

如前所述,Filterable 有 5 种类型,最后一个是 custom,它被处理得不同。自定义类型是 FilterableType 的静态方法的一部分,因此您需要在使用 filterableColumns() 方法中定义它。

use Albet\LaravelFilterable\Enums\FilterableType;

FilterableType::custom();

自定义方法接受一个参数,$allowedOperators 是一个包含 Operators 的数组。此参数用于定义自定义过滤器的允许操作符白名单。

自定义类型需要一个处理器,处理器和字段都必须按照以下约定定义

use Albet\LaravelFilterable\Enums\FilterableType;
use Albet\LaravelFilterable\Enums\Operators;
use Albet\LaravelFilterable\Operator;
use Albet\LaravelFilterable\Traits\Filterable;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;

class Flight extends Model {
    use Filterable;
    
    public function filterableColumns(): array{
        return [
            'customer_address' => FilterableType::custom([Operators::CONTAINS, Operators::NOT_CONTAINS])
        ];
    }
    
    public function filterCustomAddress(Builder $builder, string $operator, string $value): void {
        dump($operator); // 'contains' or 'not_contains' (raw string operator)
        dump($value); // raw string value
        $builder->whereHas('customer', fn($query) => $query->where('name', 'LIKE', "%$value%"));
    }
}

注意,列使用蛇形命名法定义,而方法使用驼峰命名法。您的函数也应定义三个参数。第一个是 Builder,一个原始 operator,最后是一个原始 value。这里的 raw 意味着这些值未经格式化,它们从查询字符串快速传递过来。然而,它们是 经过验证的

在模型中使用

只需调用过滤作用域即可

<?php

use App\Models\Flight;

// In this example I choose to merge the request, alternatively you can hit endpoint like this:
// https://:8000/all-flights?filters[0][field]=customer_name&filters[0][operator]=eq&filters[0][value]=asep
request()->merge([
    'filters' => [
        [
            'operator' => 'eq',
            'field' => 'customer_name', 
            'value' => 'asep'
        ]
    ]
]);

dd(Flight::filter()->get()); // Flight[{customer_name: "asep", ticket_no: 20393, schedule: "2023-08-20"}]

请求模式

以下是 Laravel Filterable 可以读取的预期请求负载模式

{
  "filters": [
    {
        "operator": "eq",
        "field": "customer_name",
        "value": "asep"
    }
  ]
}

所有过滤器都必须放置在 filters 键下,值应该是包含以下内容的 object 数组

  • fields(字符串)
    确定应过滤哪个字段
  • operator (字符串)
    在过滤上下文中使用哪种操作符
  • value (字符串)
    预期的值

上述模式映射到查询字符串时将如下所示
?filters[0][field]=customer_name&filters[0][operator]=eq&filters[0][value]=asep

支持的操作符

  • eq:检查值是否等于指定的输入。
  • neq:检查值是否不等于指定的输入。
  • contains:检查值是否包含指定的输入。
  • starts_with:检查值是否以指定的输入开头。
  • ends_with:检查值是否以指定的输入结尾。
  • not_contains:检查值是否不包含指定的输入。
  • in (数组):检查值是否是指定的输入之一。
  • not_in (数组):检查值是否不是指定的任何输入。
  • have_all (数组):检查值是否包含所有指定的输入。
  • gt:检查值是否大于指定的输入。
  • lt:检查值是否小于指定的输入。
  • gte:检查值是否大于或等于指定的输入。
  • lte:检查值是否小于或等于指定的输入。

限制

值仅限于 字符串 类型,并且每个转换都是通过在 filterableColumns 中定义的类型来执行的。对于包含 , 作为值分隔符的 数组,可能会发生模糊转换。请避免在您的值中使用 ,,因为它们用作内部数组分隔符。另一种情况可能涉及包含多个 . 分隔符的 数字

测试

composer test

变更日志

请参阅变更日志,了解最近有哪些更改。

贡献

请参阅贡献指南以获取详细信息。

安全漏洞

请参阅我们的安全策略,了解如何报告安全漏洞。

鸣谢

许可

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