mehtadsadeghi / laravel-filter-querystring
轻松根据URL查询字符串参数过滤您的查询。
Requires
- php: ^7.1|^8.0
- laravel/framework: 5.*|6.*|7.*|8.*|9.*|10.*|11.*
Requires (Dev)
- orchestra/testbench: ^4.0
README
轻松根据URL查询字符串参数过滤您的查询。
兼容Laravel 5.x 6.x 7.x 8.x 9.x 10.x 11.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原则中的开/闭原则,因为当你有一个新参数时,你需要进入现有的代码并添加新的逻辑(这可能会破坏现有的实现)。
因此,我们需要设计一种方法来使我们的过滤器逻辑相互独立,并将它们应用到最终的查询中,这正是这个包背后的整个想法。
使用方法
- 首先,你需要安装这个包
$ composer require mehradsadeghi/laravel-filter-querystring
use Mehradsadeghi\FilterQueryString\FilterQueryString; class User extends Model { use FilterQueryString; protected $filters = []; ... }
- 你需要在你的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
假设我们想要过滤name
、username
和age
数据库列,在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