bjerke / api-query-builder
为Laravel提供的查询构建器,它解析请求并使用Eloquent ORM查询数据库
Requires
- php: ^7.3 || ^8.0
- illuminate/database: ^8.0 | ^9.0 | ^10.0
- illuminate/http: ^8.0 | ^9.0 | ^10.0
- illuminate/support: ^8.0 | ^9.0 | ^10.0
README
一个库,允许客户端以非常动态的方式查询模型,模仿Eloquent ORM。
安装
composer require bjerke/api-query-builder
配置
配置项不多,但可以配置查询本地化排序子句时使用哪种校对。默认配置为为sv
和sv-SE
地区使用utf8mb4_swedish_ci
。如果您不需要其他地区的特殊校对,则无需发布此配置。但是,如果您想为特定地区添加其他校对,则需要从库中发布配置文件,以便在您自己的应用程序中修改它。为此,请运行以下Artisan命令:
php artisan vendor:publish --provider="Bjerke\ApiQueryBuilder\QueryBuilderServiceProvider"
现在您将在/config
目录下有一个querybuilder.php
配置文件,您可以在其中添加额外的地区 => 校对组合
用法
要使用查询构建器,您将使用此库的2个主要组件:特性QueryBuilderModelTrait
和构建器本身QueryBuilder
。
该特性旨在帮助构建器验证请求的字段、关系、可追加属性和计数。以及一些辅助方法。有关如何使用关系、可追加属性和计数的更多信息,请参阅下文。此特性需要包含在您希望使用查询构建器的模型中。
在您的控制器方法中,您可以使用查询构建器根据请求编译Eloquent构建器类,如下所示:
public function index(Request $request) { // Setup the builder $queryBuilder = new QueryBuilder(new MyModel, $request); // Parse the request and return an Eloquent Builder instance $query = $queryBuilder->build(); // The instance can be extended/modified freely just as any other Eloquent Builder instance // For example, maybe we want to enable the option to turn pagination on/off? if (($pagination = $request->input('paginate')) !== null && ($pagination === false || $pagination === 'false' || $pagination === '0') ) { return $query->get(); } $perPage = $request->input('per_page'); return $query->paginate($perPage)->appends($request->except('page')); }
可用查询方法
大多数方法都包含一个or
对应方法,允许您在查询中创建OR语句。就像Eloquent一样。例如where
和orWhere
。
- where
- whereIn
- whereNotIn
- whereBetween
- whereNotBetween
- whereNull
- whereNotNull
- whereHas
- whereDoesntHave
- whereDate (whereDate / whereMonth / whereDay / whereYear / whereTime),
- search
- select
- orderBy
- groupBy
- limit
- with
- appends
- counts
- 分页
where / orWhere
执行一个where语句。它可以以多种方式定义。以下将执行一个精确匹配,其中first_name
等于test
。
?where[first_name]=test
您还可以通过定义操作符(=
、!=
、like
、>
、<
)进行更复杂的匹配。定义操作符时,您还需要定义一个value
参数。以下将执行一个匹配%test%
的like
查询。
?where[first_name][value]=%25test%25&where[first_name][operator]=like
这些方法都是递归的。这意味着您可以在父级"where"中包装多个语句,以匹配其中的所有语句。
whereIn / orWhereIn
类似于where / orWhere,但匹配一组值。值可以定义为逗号分隔的字符串或实际数组。
?whereIn[id]=1,2,3
or
?whereIn[id][]=1&whereIn[id][]=2&whereIn[id][]=3
whereNotIn / orWhereNotIn
与 whereNotIn / orWhereNotIn 相同,但匹配提供的值的缺失。
whereBetween / orWhereBetween
匹配的列值在提供的两个值之间。值可以定义为逗号分隔的字符串或实际数组。
?whereBetween[date]=2017-01-01,2018-01-01
or
?whereBetween[date][]=2017-01-01&whereBetween[date][]2018-01-01
whereNotBetween / orWhereNotBetween
与 whereBetween / orWhereBetween 相同,但匹配的值应在提供的范围之外。
whereNull / orWhereNull
?whereNull[]=updated_at
whereNotNull / orWhereNotNull
与 whereNull / orWhereNull 相同,但匹配的值不应为 null。
whereHas / orWhereHas
查询存在的关系。这需要你的关系被添加到模型上的 allowedApiRelations
数组。否则,它将忽略此查询。
简单的存在检查,只会返回与之相关的任何预订的结果。
?whereHas[]=bookings
根据列值过滤存在检查。只会返回与具有 id 1 的预订相关的结果。
?whereHas[][bookings][id]=1
高级查询。将接受大多数查询方法。
?whereHas[][bookings][whereIn][id]=1,2,3
whereDoesntHave / orWhereDoesntHave
与 whereHas / orWhereHas 相同,但匹配关系的缺失。
whereDate
按日期查询。此方法的缩写形式为:whereDate / whereMonth / whereDay / whereYear / whereTime。
?whereDate[created_at]=2016-12-31
您还可以通过定义一个运算符(=
,!=
,>
,<
)来进行更高级的匹配。在定义运算符时,您还需要定义一个 value
参数。
?whereDate[created_at][value]=2016-12-31&where[created_at][operator]=<
search
这是一个方法,使在多个列上执行搜索查询变得稍微容易一些,而不是执行高级的 where
-查询。
?search[value]=Jesper&search[columns]=first_name,last_name,phone&search[split]=true
参数
- value: Search query
- columns: Comma separated string or array of column names to search in
- split: Boolean. Defaults to false
Optionally set to true to treat spaces as delimiters for keywords,
i.e "Jesper Bjerke" will result a query for all "Jesper" and all "Bjerke"
Without split, it will treat it as a single keyword and match on full "Jesper Bjerke"
- json: Boolean. Defaults to false.
If the search column is json and you want the search to be case insensitive, set this to true.
select
将数据集限制为仅拉取特定的列。
?select=id,first_name,last_name
or
?select[]=id&select[]=first_name&select[]=last_name
如果您使用 with
加载,还可以选择关系属性。
?select[]=user.first_name
orderBy
根据一个或多个列对结果进行排序。
?orderBy=first_name,desc
或多个列
?orderBy[first_name]=desc&orderBy[created_at]=desc
使用 desc
或 asc
定义排序。还有一个特殊的排序 localizedDesc
和 localizedAsc
,它将根据当前区域设置运行预配置的排序。有关更多信息,请参阅 配置。
如果您使用 with
加载,也可以根据关系属性进行排序。
?orderBy=user.first_name,desc
groupBy
按列对结果进行分组。
?groupBy=first_name
limit
通过数字限制可能返回的总结果数量。
?limit=2
最多只返回 2 个结果。
with
预加载关系。这需要你的关系被添加到模型上的 allowedApiRelations
数组(阅读更多)。否则,它将忽略此查询。
注意加载大量关系时的性能。只有在您知道只会得到有限的结果集时才这样做。
?with=user,booking
or
?with[]=user&with[]=booking
appends
附加属性。这需要您的属性被添加到模型上的 allowedApiAppends
数组(阅读更多)。否则,它将忽略此查询。
注意加载大量可附加属性的性能。这些属性在每个模型上在查询结果之后进行处理。只有在您知道只会得到有限的结果集且附加属性不会过度压榨数据库等时才这样做。
?appends=full_name,generated_name
or
?appends[]=full_name&appends[]=generated_name
counts
关系计数。这将返回一个整数属性,表示此模型所拥有的关系的数量。
这需要你在模型的 allowedApiCounts
数组中添加你的属性(了解更多)。否则它将忽略这个查询。
注意大量关系计数可能会影响性能。它们会产生额外的数据库访问。
?counts=users,bookings
or
?counts[]=users&counts[]=bookings
分页 / 每页数量
分页不是由查询构建器专门处理的,但这里有一个示例说明你可以如何实现分页
public function index(Request $request) { // Setup the builder $queryBuilder = new QueryBuilder(new MyModel, $request); // Parse the request and return an Eloquent Builder instance $query = $queryBuilder->build(); // The instance can be extended/modified freely just as any other Eloquent Builder instance // For example, maybe we want to enable the option to turn pagination on/off? if (($pagination = $request->input('paginate')) !== null && ($pagination === false || $pagination === 'false' || $pagination === '0') ) { return $query->get(); } $perPage = $request->input('per_page'); return $query->paginate($perPage)->appends($request->except('page')); }
现在分页默认为开启状态,要控制查询的分页,你可以现在传递额外的URL参数。
要完全关闭分页
?pagination=false
要调整每页结果数量
?per_page=25
定义允许的字段、关系、可附加属性和数量
为了避免在你的模型上暴露所有内容,你必须定义你想要可查询的每个关系、附加属性或数量。验证在它们之间基本是相同的。唯一的例外是 allowedApiFields
,其中默认允许所有标准字段。在你的模型中包含 QueryBuilderModelTrait
后,你可以添加以下方法到其中
// ... public function allowedApiFields(): array { // Default is ['*'] return [ 'firstname', 'lastname' ]; } // ...
// ... public function allowedApiRelations(): array { return [ 'user' // Must be a relation on your model ]; } // ...
// ... public function allowedApiCounts(): array { return [ 'user' // Must be a relation on your model ]; } // ...
// ... public function allowedApiAppends(): array { return [ 'full_name' // Must be an appendable attribute on your model ]; } // ...