morfin/querystring-for-laravel

从 mehradsadeghi 分支而来。轻松根据 URL 查询字符串参数过滤查询。

v1.1.9 2022-02-01 07:13 UTC

README

轻松根据 URL 查询字符串参数过滤查询。

兼容 Laravel 5.x 6.x 7.x 8.x.

目录

描述问题

你可能遇到过需要根据 URL 查询字符串中的给定参数过滤查询的情况。在开发完逻辑后,你可能会有这样的代码

$users = User::latest();

if(request('username')) {
    $users->where('username', request('username'));
}

if(request('age')) {
    $users->where('age', '>', request('age'));
}

if(request('email')) {
    $users->where('email', request('email'));
}

return $users->get();

这可以工作,但这不是一种好的做法。

当参数数量开始增加时,这种 if 语句的数量也会增加,你的代码会变得庞大且难以维护。

这也违反了 SOLID 原则中的开放/关闭原则,因为当你有新的参数时,你需要进入现有的代码并添加新的逻辑(这可能会破坏现有的实现)。

因此,我们必须设计一种方法来使我们的过滤器逻辑相互分离,并将它们应用于最终的查询,这正是这个包背后的整个想法。

用法

  1. 首先,你需要安装这个包

$ composer require mehradsadeghi/laravel-filter-querystring

  1. 然后,你应该在你的模型中使用 FilterQueryString 特性,并定义 $filters 属性,它可以包含 可用过滤器 或你的 自定义过滤器
use Mehradsadeghi\FilterQueryString\FilterQueryString;

class User extends Model
{
    use FilterQueryString;

    protected $filters = [];

    ...
}
  1. 你需要在你的 Eloquent 查询中使用 filter() 方法。例如
User::select('name')->filter()->get();

可用方法

为了解释每个方法,假设我们在 users 表中有以下数据

假设我们的查询是这样的

User::filter()->get();

排序

排序相当于 SQL 语句中的 order by,可以在 FilterQueryString 中灵活使用

约定

?sort=field
?sort=field,sort_type
?sort[0]=field1&sort[1]=field2
?sort[0]=field1&sort[1]=field2,sort_type
?sort[0]=field1,sort_type&sort[1]=field2,sort_type

在 User.php 中

protected $filters = ['sort'];

单个 sort:

https://example.com?sort=created_at

输出

  • 注意:当没有定义 sort_type 时,默认为 asc

多个 sort:

https://example.com?sort[0]=age,desc&sort[1]=created_at,desc

输出

请注意:无效值的 sort 参数将被忽略并不会有任何影响。

比较

比较由 6 个过滤器组成

  • greater
  • greater_or_equal
  • less
  • less_or_equal
  • between
  • not_between

约定

?greater=field,value
?greater_or_equal=field,value
?less=field,value
?less_or_equal=field,value
?between=field,value1,value2
?not_between=field,value1,value2

在 User.php 中

protected $filters = [
    'greater',
    'greater_or_equal',
    'less',
    'less_or_equal',
    'between',
    'not_between'
];

例如,greater 的示例:

https://example.com?greater=age,20

输出

例如,not_between 的示例:

https://example.com?not_between=age,21,30

输出

请注意:无效值的比较参数将被忽略并不会有任何影响。

IN 子句相当于 SQL 语句中的 where in

约定

?in=field,value1,value2

在 User.php 中

protected $filters = ['in'];

示例:

https://example.com?in=name,mehrad,reza

输出

请注意:无效值的 in 参数将被忽略并不会有任何影响。

LIKE 子句相当于 SQL 语句中的 like '%value%'

约定

?like=field,value
?like[0]=field1,value1&like[1]=field2,value2

在 User.php 中

protected $filters = ['like'];

单个 like:

https://example.com?like=name,meh

输出

多个 like:

https://example.com?like[0]=name,meh&like[1]=username,dar

输出

请注意,如果like参数的值无效,则将从查询中忽略它,并且不会对结果产生影响。

Where子句(默认过滤器)

通常,当您的查询字符串参数不是之前可用方法之一时,它将通过默认过滤器进行过滤,该默认过滤器是where SQL语句。当您需要直接过滤您表中的一列时,这是一个合适的过滤器。

约定

?field=value
?field1=value&field2=value
?field1[0]=value1&field1[1]=value2
?field1[0]=value1&field1[1]=value2&field2[0]=value1&field2[1]=value2 

假设我们想要过滤数据库列nameusernameage,在User.php中

protected $filters = ['name', 'username', 'age'];

示例:

https://example.com?name=mehrad

输出

示例:

https://example.com?age=22&username=dariush123

输出

示例:

https://example.com?name[0]=mehrad&name[1]=dariush

输出

示例:

https://example.com?name[0]=mehrad&name[1]=dariush&username[0]=mehrad123&username[1]=reza1234

输出

请注意,如果default过滤器参数的值无效,则将从查询中忽略它,并且不会对结果产生影响。

自定义过滤器

通过自定义过滤器,您可以定义自己的方法作为过滤器。这有助于实现SOLID原则中的开放/封闭原则,因此每次需要新的过滤器时,您不必编辑以前的过滤器,而只需为它编写一个单独的方法。

让我们创建一个自定义过滤器。假设您想创建一个名为all_except的过滤器,该过滤器检索除指定用户之外的所有用户

在 User.php 中

protected $filters = ['all_except'];

public function all_except($query, $value) {
    return $query->where('name', '!=', $value);
}

为了测试我们新添加的过滤器

https://example.com?all_except=mehrad

输出

注意,您自定义定义的过滤器具有最高优先级,这意味着您可以覆盖现有过滤器。

例如,让我们将in过滤器修改为只接受3个值

在 User.php 中

protected $filters = ['in'];

public function in($query, $value) {
    
    $exploded = explode(',', $value);

    if(count($exploded) != 4) {
        // throwing an exception or whatever you like to do
    }

    $field = array_shift($exploded);

    return $query->whereIn($field, $exploded);
}

另一个自定义过滤器的良好示例是当您不想暴露数据库表的列名时。例如,假设我们不希望暴露在users表中有一个名为username的列

在 User.php 中

protected $filters = ['by'];

public function by($query, $value) {
    return $query->where('username', $value);
}

https://example.com?by=dariush123

输出

小贴士

为了防止您的模型变得混乱或被过滤器方法填充,您可以为此创建一个特质,并将有关过滤器的一切放入特质中。

条件过滤器

您的模型中的$filters属性对该模型的作用类似于全局属性。这意味着当您在eloquent查询上使用filter()方法时,它将始终执行所有$filters过滤器。

可能会出现这样的情况,基于条件您需要指定确切的过滤器,您希望对其进行过滤。

为了实现这一点,您可以在filter()方法中指定所需的过滤器作为参数。

示例

在您的查询中

User::filter('in')->get();

in=name,mehrad,reza&like=name,mehrad

输出

如果未指定in参数,查询的结果将只有一条记录(mehrad)。

另一个示例

在您的查询中

User::filter('like', 'name')->get();

like=name,mehrad,reza,dariush,hossein&name[0]=mehrad&name[1]=hossein&username=mehrad

输出

您的支持很重要

如果您觉得这个包很有用,并希望鼓励我维护和改进它,只需按下星号按钮即可表达您的意愿。

用一杯茶奖励我 🍵

请按照您所在国家的茶杯价值给我发来相应的金额,这样我就会有精力维护这个包。

  • Ethereum: 0x2D5BFdEc132F9F0E9498Fb0B58C800db4007D154