railgun1v9 / lara-spf
用于Laravel构建器和集合的排序、分页和筛选,利用URI的查询参数。
Requires
- php: >=7.0.0
- illuminate/config: 5.*
- illuminate/database: 5.*
- illuminate/support: 5.*
- laravel/framework: >=5.1
This package is auto-updated.
Last update: 2022-03-01 00:29:46 UTC
README
用于Laravel构建器和集合的排序、分页和筛选,利用URI的查询参数。
致谢
此包使用了以下功能的实现:
johannesschobel/dingoquerymapper - 排序和分页功能
CamiloManrique/laravel-filter - 筛选功能
这两个库都有满足我需求的功能,但在安全性和其他需求方面有所不足。通过一点编辑和组合,我创建了一个集排序、分页和筛选于一体的解决方案。
安装
使用Composer安装包
composer require railgun1v9/lara-spf
将railgun1v9\LaraSPF
添加到config/app.php
中的服务提供者
'providers' => [ railgun1v9\LaraSPF\FilterServiceProvider::class ]
您可以将配置文件发布以更改默认设置
php artisan vendor:publish
从URI与LaraSPF交互
排序
默认情况下,LaraSPF按id
以升序排序结果。以下是一个示例查询参数来执行此操作。
/customer?sort=id
要按不同的列和降序排序,可以在字段前加上减号。
/customer?sort=-name
分页
默认情况下,LaraSPF每页限制为15个结果。但您可以通过URI中的limit
参数更改限制。
/customer?sort=id&limit=25
要转到结果的下一页,请附加一个page
参数,其值为您想要查看的页码。
/customer?sort=id&limit=25&page=2
筛选
您可以根据以下示例通过键和值筛选结果。
/customer?name=BOB&sort=id&limit=25
注意,此筛选是大小写敏感的。
但是,您可以通过在您要筛选的键后附加/like
来执行不区分大小写的搜索。
/customer?nam/like=bOb&sort=id&limit=25
使用
使用LaraSPF与集合
此包向Collection类添加了两个宏方法,增加了筛选和分页功能
$customers->filter($request)->paginate($request);
paginate方法可以与filter方法一起使用,为集合提供排序、分页和筛选功能。
使用LaraSPF与构建器
此包向Builder类添加了两个宏方法,允许在不进行任何其他设置的情况下使用筛选方法。这两个方法都可以接收一个HttpRequest、一个Collection或一个数组作为参数。下面将解释这两个方法。
方法名称注意事项: 宏方法名称可以在配置文件中进行自定义,以防Builder类宏中出现命名冲突。示例中将使用默认名称。
获取查询构建器实例
User::filter($request)
使用此方法,您可以获取一个查询构建器实例,在其中可以持续应用查询构建器方法,包括get()
、first()
、paginate()
等。
获取模型实例
User::filterandGet($request)
此方法为您处理查询构建和获取。它甚至可以开箱即用地处理分页。默认情况下,使用此方法自动分页是开启的,但您可以通过发布配置文件并编辑它来更改此行为。
这些方法也可以不带参数调用,在这种情况下,查询不会应用任何过滤。
由于这些方法是Builder类的宏,因此在使用模型实例上的相关模型时也可以链式调用。例如,假设模型User与Post模型有关联,您可以使用它如下
$user = User::find(1) $user->posts()->filterAndGet($request);
实际使用示例
从路由返回
Route::get('/users', function(){ return User::filterAndGet(request()); });
从控制器返回
public function index(Request $request){ return User::filterAndGet($request); }
关于Eloquent API资源的说明:如果您正在使用Laravel 5.5,您也可以使用此包与Eloquent Resources的新功能一起使用。
Route::get('/users', function(){ return UserResource::collection(User::filterAndGet(request())); });
过滤规则
现在,这是一个重要的部分。我们已解释了如何安装和调用过滤方法,但您如何实际定义您的过滤器呢?对于基本查询来说很简单,如果您需要基于相关模型进行查询,那么会稍微复杂一些。
定义过滤列
在您的请求中,您只需将列名称用作键,将比较值用作值。
示例
假设您的应用程序URL为http://www.example.com,并且您定义了一个路由/users,该路由指向一个名为filter的控制器方法,如下所示
namespace App\Http\Controllers; use App\Users; class UsersController extends Controller { public function filter(Request $request) { return User::filterAndGet($request); } }
假设您想要检索来自德国的用户。您的HTTP请求对象应该有一个名为country的键,其值设为德国。URI请求如下所示
http://www.example.com/users?country=Germany
现在假设您想要更具体一些,并且您想要检索不仅是来自德国,而且是男性的用户。您的URI将变为如下所示
http://www.example.com/users?country=Germany&gender=Male
请记住,您也可以使用集合和数组来传递所需的过滤器。以下示例使用数组作为参数的等效形式
$filters = ["country" => "Germany", "gender" => "Male"] User::filterAndGet($filters);
查询比较运算符
上述示例仅适用于精确匹配,但您可能需要一个更宽松的比较,如>、<、LIKE和!=运算符提供的那种。为了使用这些运算符,您需要在列名称末尾附加一个关键字,并用斜杠字符分隔。此分隔字符可以在配置文件中更改。
以下是关键字及其对应运算符的列表
- start: >= value
- end: <= value
- like: LIKE %value%
- not: != value
示例
检索来自德国且年龄小于30岁的用户
http://www.example.com/users?country=Germany&age%2Fend=30
在先前的示例中,%2F是斜杠字符的编码。
使用数组作为参数的等效形式
$filters = ["country" => "Germany", "age/end" => 30] User::filterAndGet($filters);
高级使用
将相关模型添加到响应中
有时您可能需要从查询中检索额外的相关模型。您可以通过在输入中添加关键字"relationships"并将其值设置为要包含的关联(如模型类中定义,而非表名)的逗号分隔列表来实现。
如果您的模型中有一个名为"relationships"的列,则过滤器将表现异常。在这种情况下,请在配置文件中更改搜索关系键的数组中的关键词,并将其值更改为任何不会与您的列名冲突的词。
例如,假设您有一个包含两个相关模型(帖子(Posts)和评论(Comments))的用户模型,这些模型之间有一个一对多关系(一个用户可以有多个帖子)。现在,您只想获取来自德国的用户,但您想将用户的帖子评论包含在响应中。输入将如下所示
$filters = ["country" => "Germany", "relationships" => "posts,comments"] User::filterAndGet($filters);
这样,每个用户的帖子(Posts)和评论(Comments)模型都将包含在响应中。
当加载具有许多模型的关联时请小心,因为它们都会被加载,这可能会导致非常慢的响应时间。
基于相关模型进行过滤
就像您可以在结果中包含相关模型一样,您也可以根据相关模型过滤结果。您只需在列名前加上关系和"@"字符。例如,假设一个用户模型有一个名为"account_info"的一对一关系,对应一个名为AccountInfo的模型,并且这个模型有一个名为"name"的属性。为了基于AccountInfo模型中的"name"列对用户模型进行过滤,输入将是
$filters = ["account_info@name" => "John"] User::filterAndGet($filters);
获取求和聚合
有时,您不需要查询的实际模型。相反,您可能需要获取一个或多个属性的总和。在这种情况下,您应在输入中添加关键字"sum",并将其值设置为要获取总和的列或列(列应逗号分隔)。例如,获取某些用户帖子的总投票数
$filters = ["user_id" => 1, sum" => "votes"] User::filterAndGet($filters);
另一个选项是使用Eloquent关系方法
$user = User::find(1) $filters = ["sum" => "votes"] $user->posts()->filterAndGet($filters);