barisbora / laravel-query-builder
轻松从API请求构建Eloquent查询
Requires
- php: ^7.1
Requires (Dev)
- orchestra/testbench: ~3.5.0|~3.6.0
- phpunit/phpunit: ^6.1|^7.0
This package is not auto-updated.
Last update: 2024-06-26 23:41:57 UTC
README
轻松从API请求构建Eloquent查询
此包允许您根据请求过滤、排序并包含Eloquent关系。在此包中使用的QueryBuilder扩展了Laravel默认的Eloquent构建器。这意味着您仍然可以使用所有您喜欢的方法和宏。查询参数名称尽可能遵循JSON API规范。
基本用法
过滤API请求:/users?filter[name]=John
use Spatie\QueryBuilder\QueryBuilder; // ... $users = QueryBuilder::for(User::class) ->allowedFilters('name') ->get(); // all `User`s that contain the string "John" in their name
从API请求请求关系:/users?include=posts
$users = QueryBuilder::for(User::class) ->allowedIncludes('posts') ->get(); // all `User`s with their `posts` loaded
与现有查询配合良好
$query = User::where('active', true); $user = QueryBuilder::for($query) ->allowedIncludes('posts', 'permissions') ->where('score', '>', 42) // chain on any of Laravel's query builder methods ->first();
排序API请求:/users?sort=name
$users = QueryBuilder::for(User::class)->get(); // all `User`s sorted by name
请查看下面的用法部分以获取高级示例和功能。
安装
您可以通过composer安装此包
composer require spatie/laravel-query-builder
您可以选择使用以下命令发布配置文件:
php artisan vendor:publish --provider="Spatie\QueryBuilder\QueryBuilderServiceProvider" --tag="config"
这是发布配置文件的内容
return [ /* * By default the package will use the `include`, `filter`, `sort` and `fields` query parameters. * * Here you can customize those names. */ 'parameters' => [ 'include' => 'include', 'filter' => 'filter', 'sort' => 'sort', 'fields' => 'fields', ], ];
用法
包含关系
使用include
查询参数将在结果集合上加载任何Eloquent关系。默认情况下,不允许任何包含。所有包含都必须使用allowedIncludes()
指定。
// GET /users?include=posts $users = QueryBuilder::for(User::class) ->allowedIncludes('posts') ->get(); // $users will contain all users with their posts loaded
您可以通过逗号分隔来加载多个关系
// GET /users?include=posts,permissions $users = QueryBuilder::for(User::class) ->allowedIncludes('posts', 'permissions') ->get(); // $users will contain all users with their posts and permissions loaded
您还可以将包含数组传递给allowedIncludes()
方法。
// GET /users?include=posts,permissions $users = QueryBuilder::for(User::class) ->allowedIncludes(['posts', 'permissions']) ->get(); // $users will contain all users with their posts and permissions loaded
您可以使用点(.
)来加载嵌套关系
// GET /users?include=posts.comments,permissions $users = QueryBuilder::for(User::class) ->allowedIncludes('posts.comments', 'permissions') ->get(); // $users will contain all users with their posts, comments on their posts and permissions loaded
当尝试包含使用allowedIncludes()
不允许的关系时,将抛出InvalidIncludeQuery
异常。
关系/包含名称将在查找模型上对应关系时转换为驼峰命名法。这意味着/users?include=blog-posts
将尝试在User
模型上加载blogPosts()
关系。
一旦在结果集合上加载了关系,您就可以通过使用Eloquent API资源和条件关系来在响应中包含它们。
过滤
可以使用filter
查询参数根据部分属性值、精确属性值或属性值是否存在于给定的值数组中过滤结果。您还可以为更复杂的查询指定自定义过滤器。
默认情况下,不允许任何过滤器。所有过滤器都必须使用allowedFilters()
指定。当尝试在未使用allowedFilters()
允许的属性上过滤时,将抛出InvalidFilterQuery
异常。
// GET /users?filter[name]=john&filter[email]=gmail $users = QueryBuilder::for(User::class) ->allowedFilters('name', 'email') ->get(); // $users will contain all users with "john" in their name AND "gmail" in their email address
您还可以将过滤器数组传递给allowedFilters()
方法。
// GET /users?filter[name]=john&filter[email]=gmail $users = QueryBuilder::for(User::class) ->allowedFilters(['name', 'email']) ->get(); // $users will contain all users with "john" in their name AND "gmail" in their email address
您可以通过传递逗号分隔的值列表来指定多个匹配的过滤器值
// GET /users?filter[name]=seb,freek $users = QueryBuilder::for(User::class) ->allowedFilters('name') ->get(); // $users will contain all users that contain "seb" OR "freek" in their name
精确过滤器
当根据其ID、布尔值或字面字符串过滤模型时,您将希望使用精确过滤器。这样,/users?filter[id]=1
不会匹配ID中包含数字1
的所有用户。
可以在allowedFilters()
方法中使用Spatie\QueryBuilder\Filter::exact('property_name')
添加精确过滤器。
use Spatie\QueryBuilder\Filter; // GET /users?filter[name]=John%20Doe $users = QueryBuilder::for(User::class) ->allowedFilters(Filter::exact('name')) ->get(); // all users with the exact name "John Doe"
查询构建器将自动将'true'
和'false'
映射为布尔值,将逗号分隔的值列表映射为数组
use Spatie\QueryBuilder\Filter; // GET /users?filter[id]=1,2,3,4,5&filter[admin]=true $users = QueryBuilder::for(User::class) ->allowedFilters(Filter::exact('id'), Filter::exact('admin')) ->get(); // $users will contain all admin users with id 1, 2, 3, 4 or 5
作用域过滤器
有时你可能需要构建更高级的过滤查询。这时候作用域过滤和自定义过滤就派上用场了。
作用域过滤允许你通过向URL添加过滤条件,轻松地为查询添加局部作用域。
考虑以下模型的作用域
public function scopeStartsBefore(Builder $query, $date): Builder { return $query->where('starts_at', '>=', Carbon::parse($date)); }
要基于startsBefore
作用域进行过滤,只需将其添加到查询构建器的allowedFilters
中
QueryBuilder::for(Event::class) ->allowedFilters([ Filter::scope('starts_before'), ]) ->get();
以下过滤器现在会将startsBefore
作用域添加到底层查询中
GET /events?filter[starts_before]=2018-01-01
你甚至可以通过将逗号分隔的列表传递给过滤器来传递多个参数给作用域
GET /events?filter[starts_between]=2018-01-01,2018-12-31
自定义过滤器
你可以使用Filter::custom()
方法指定自定义过滤器。自定义过滤器是简单的可调用类,它实现了\Spatie\QueryBuilder\Filters\Filter
接口。这样你可以创建任何你想要的查询。
例如
use Spatie\QueryBuilder\Filters\Filter; use Illuminate\Database\Eloquent\Builder; class FiltersUserPermission implements Filter { public function __invoke(Builder $query, $value, string $property) : Builder { return $query->whereHas('permissions', function (Builder $query) use ($value) { $query->where('name', $value); }); } } use Spatie\QueryBuilder\Filter; // GET /users?filter[permission]=createPosts $users = QueryBuilder::for(User::class) ->allowedFilters(Filter::custom('permission', FiltersUserPermission::class)) ->get(); // $users will contain all users that have the `createPosts` permission
排序
sort
查询参数用于确定结果集合将按哪个属性排序。默认情况下,排序是升序的。在属性名称的开头添加一个连字符(-
)将反转结果集合。
// GET /users?sort=-name $users = QueryBuilder::for(User::class)->get(); // $users will be sorted by name and descending (Z -> A)
默认情况下,所有模型属性都可以用于排序结果。但是,你可以使用allowedSorts
方法来限制哪些属性可以在请求中使用。
当你尝试根据未在allowedSorts()
中指定的属性进行排序时,将抛出InvalidSortQuery
异常。
// GET /users?sort=password $users = QueryBuilder::for(User::class) ->allowedSorts('name') ->get(); // Will throw an `InvalidSortQuery` exception as `password` is not an allowed sorting property
要定义一个默认排序参数,它应该在请求中明确添加,你可以使用defaultSort
方法。
// GET /users $users = QueryBuilder::for(User::class) ->defaultSort('name') ->allowedSorts('name', 'street') ->get(); // Will retrieve the users sorted by name
你还可以将排序数组传递给allowedSorts()
方法。
// GET /users?sort=name $users = QueryBuilder::for(User::class) ->allowedSorts(['name', 'street']) ->get(); // Will retrieve the users sorted by name
你可以通过逗号分隔多个属性来按多个属性排序
// GET /users?sort=name,-street $users = QueryBuilder::for(User::class) ->allowedSorts('name', 'street') ->get(); // $users will be sorted by name in ascending order with a secondary sort on street in descending order.
选择特定列
有时你可能只想获取几个字段以减少SQL查询的整体大小。这可以通过使用fields
查询参数来完成。以下仅获取用户的有效id
和name
GET /users?fields[users]=id,name
SQL查询看起来像这样
SELECT "id", "name" FROM "users"
选择包含模型的字段的工作方式相同。这在需要包括整个关系但只需要几个列时特别有用。考虑以下示例
GET /posts?include=author&fields[author]=name
将获取所有帖子,包括作者的名字。
附加属性
有时你可能想将一些自定义属性附加到从模型获取的结果中。这可以通过使用append
参数来完成。
class User extends Model{
public function getFullnameAttribute()
{
return $this->firstname.' '.$this->lastname;
}
}
// GET /users?append=fullname
$users = QueryBuilder::for(User::class)
->allowedAppends('fullname')
->get();
当然,你可以传递一个要附加的属性列表。
// GET /users?append=fullname,ranking
其他查询方法
由于QueryBuilder
扩展了Laravel的默认Eloquent查询构建器,因此你可以使用任何你喜欢的函数或宏。你也可以指定一个基本查询而不是模型FQCN
QueryBuilder::for(User::where('id', 42)) // base query instead of model ->allowedIncludes('posts') ->where('activated', true) // chain on any of Laravel's query methods ->first(); // we only need one specific user
分页
此包不提供任何帮助您分页响应的方法。然而,如上所述,你可以使用Laravel的默认paginate()
方法。
如果你想完全遵守JSON API规范,你也可以使用我们自己的spatie/json-api-paginate!
在前端构建查询
如果你使用Vue,你可能会对vue-api-query包感兴趣,由Robson Tenório提供。
测试
composer test
变更日志
有关最近更改的更多信息,请参阅变更日志。
贡献
请参阅CONTRIBUTING以获取详细信息。
安全
如果您发现任何安全相关的问题,请发送电子邮件至freek@spatie.be,而不是使用问题跟踪器。
Postcardware
您可以使用此软件包,但如果它进入了您的生产环境,我们非常感激您从家乡给我们寄一张明信片,并说明您正在使用我们的哪个软件包。
我们的地址是:Spatie,Samberstraat 69D,2060 安特卫普,比利时。
我们将所有收到的明信片发布在我们的公司网站上。
致谢
支持我们
Spatie是一家位于比利时的安特卫普网络设计公司。您可以在我们的网站上找到我们所有开源项目的概述。
您的业务是否依赖于我们的贡献?在Patreon上联系我们并支持我们。所有承诺都将用于分配人力进行维护和开发新酷炫的功能。
许可
MIT许可证(MIT)。请参阅许可文件以获取更多信息。