Php 如何获取大量GET参数并根据它们干净地过滤查询?
我在Laravel Lumen中为一个RESTful API构建了一个控制器,它接受相对大量的参数并将它们解析到查询的位置,根据是否提供了这些参数来获取数据。比如说,Php 如何获取大量GET参数并根据它们干净地过滤查询?,php,sql,arrays,laravel,lumen,Php,Sql,Arrays,Laravel,Lumen,我在Laravel Lumen中为一个RESTful API构建了一个控制器,它接受相对大量的参数并将它们解析到查询的位置,根据是否提供了这些参数来获取数据。比如说, GET /nodes?region=California GET /nodes?ip=127.0.0.1 我目前正在构造函数中使用它们,构建一个参数数组(因为我不知道如何获取Lumen中的原始get数组,这会很不方便,因为我已经有了其他参数),并过滤掉空值(如果它们不在查询中,我将值设置为null) 现在,当涉及到过滤数组中的每
GET /nodes?region=California
GET /nodes?ip=127.0.0.1
我目前正在构造函数中使用它们,构建一个参数数组(因为我不知道如何获取Lumen中的原始get数组,这会很不方便,因为我已经有了其他参数),并过滤掉空值(如果它们不在查询中,我将值设置为null)
现在,当涉及到过滤数组中的每个值时,我是通过foreach数组来完成的。这是我能想到的最干净的方法,没有太多的代码(我不想让我的控制器太胖)。
有没有其他干净的方法,比如分离函数/类
这是我的构造函数代码:
/**
* Get some values before using functions.
*
* @param Request $request Instance of request.
*/
public function __construct(Request $request)
{
$this->offset = (int) $request->input('offset', 0);
// TODO: I'm not sure how to implement this, code in question
$this->filters = [
'region' => $request->input('region', null),
'name' => $request->input('name', null),
'ip' => $request->input('ip', null)
];
$this->filters = array_filter($this->filters, function ($v) {
return !is_null($v);
});
// Set a sane SQL limit.
$this->limit = 5;
$this->request = $request;
}
以及控制器代码:
/**
* List all nodes.
*
* @return [string] [JSON containing list of nodes, if sorted.]
*/
public function all()
{
try {
// use filters provided
$data = Nodes::limit($this->limit)->offset($this->offset);
foreach ($this->filters as $filter => $value) {
$data->where($filter, $value);
}
$data = $data->get();
$response = $this->respond($data);
} catch (\Exception $e) {
$response = $this->respondServerError('Could not retrieve data from database.');
}
return $response;
}
因此,每当我必须在API中过滤资源列表时,我都会这样做 首先,在开始之前,我要介绍一个关于在控制器方法中获取请求对象的快速技巧:如果您添加
Request$Request
作为all()
函数的参数,您将可以访问那里的$Request变量,与构造函数相同。因此,完整的签名将是公共函数all(Request$Request)
。控制器方法具有与其他类构造函数在Laravel/Lumen中获得的相同的魔法依赖注入。或者,在函数中,您可以始终要求app()
函数为您提供特定类的对象。因为Request对象在容器中仅绑定到'Request',所以您可以请求完整的类名,或者只请求'Request':$Request=app('Request')代码>
因此,一旦我有了请求对象,在我的控制器方法中,我喜欢将每个过滤器作为一个组或一个接一个地进行检查,这取决于每个过滤器的复杂程度。有时过滤器很复杂,比如需要分解成数组的逗号分隔的ID列表。如果只是简单的字符串过滤器,我倾向于将列表放入一个数组中并运行它
下面是一个示例函数来说明一些想法:
public function getIndex(Request $request)
{
//Create a User object to append WHERE clauses onto
$user = app('App\Models\User');
//Run through our simple text fields
foreach(['first_name', 'last_name', 'region', 'ip'] as $field) {
if ($request->has($field)) {
$user->where($field, $request->input($field));
}
}
//This field uses a LIKE match, handle it separately
if ($request->has('email')) {
$user->where('email', LIKE, '%' . $request->input('email') . '%');
}
//This field is a list of IDs
if ($request->has('id')) {
$ids = explode(',', $request->input('id'));
$user->whereIn('id', $ids);
}
//Use pagination
$users = $user->paginate(25);
/**
* Continue with the rest of response formatting below here
*/
}
您会注意到我使用了paginate函数来限制结果。在构建列出资源的API端点时,您需要在标题(我的首选项)或响应正文中输入有关如何获取第一页、上一页、下一页和最后一页结果的信息。Laravel中的分页功能使这变得很容易,因为它可以使用links()
方法构造大多数链接
不幸的是,您需要告诉它在请求中传递了哪些过滤器参数,这样它才能确保将这些参数添加到它生成的链接中。否则,您将在没有过滤器的情况下返回链接,这对客户端分页没有多大好处
下面是一个更完整的示例,用于记录过滤器参数,以便将其附加到分页链接上:
public function getIndex(Request $request)
{
//Create a User object to append WHERE clauses onto
$user = app('App\Models\User');
//List of filters we found to append to links later
$appends = [];
//Run through our simple text fields
foreach(['first_name', 'last_name', 'region', 'ip'] as $field) {
if ($request->has($field)) {
$appends[$field] = $request->input($field);
$user->where($field, $request->input($field));
}
}
//This field uses a LIKE match, handle it separately
if ($request->has('email')) {
$appends['email'] = $request->input('email');
$user->where('email', LIKE, '%' . $request->input('email') . '%');
}
//This field is a list of IDs
if ($request->has('id')) {
$appends['id'] = $request->input('id');
$ids = explode(',', $request->input('id'));
$user->whereIn('id', $ids);
}
//Use pagination
$users = $user->paginate(25);
//Make sure we append our filter parameters onto the pagination object
$users->appends($appends);
//Now calling $users->links() will return the correct links with the right filter info
/**
* Continue with the rest of response formatting below here
*/
}
分页文档可在此处找到:
有关分页链接如何出色完成的示例,请查看Github的API文档:
最后,从概念上讲,它与你所做的并不太遥远。这里的优点是,您可以将代码移动到需要它的方法中,而不是每次初始化控制器时都让它在构造函数中运行,即使会调用不同的方法
希望有帮助 因此,每当我必须在API中过滤资源列表时,我都会这样做
首先,在开始之前,我要介绍一个关于在控制器方法中获取请求对象的快速技巧:如果您添加Request$Request
作为all()
函数的参数,您将可以访问那里的$Request变量,与构造函数相同。因此,完整的签名将是公共函数all(Request$Request)
。控制器方法具有与其他类构造函数在Laravel/Lumen中获得的相同的魔法依赖注入。或者,在函数中,您可以始终要求app()
函数为您提供特定类的对象。因为Request对象在容器中仅绑定到'Request',所以您可以请求完整的类名,或者只请求'Request':$Request=app('Request')代码>
因此,一旦我有了请求对象,在我的控制器方法中,我喜欢将每个过滤器作为一个组或一个接一个地进行检查,这取决于每个过滤器的复杂程度。有时过滤器很复杂,比如需要分解成数组的逗号分隔的ID列表。如果只是简单的字符串过滤器,我倾向于将列表放入一个数组中并运行它
下面是一个示例函数来说明一些想法:
public function getIndex(Request $request)
{
//Create a User object to append WHERE clauses onto
$user = app('App\Models\User');
//Run through our simple text fields
foreach(['first_name', 'last_name', 'region', 'ip'] as $field) {
if ($request->has($field)) {
$user->where($field, $request->input($field));
}
}
//This field uses a LIKE match, handle it separately
if ($request->has('email')) {
$user->where('email', LIKE, '%' . $request->input('email') . '%');
}
//This field is a list of IDs
if ($request->has('id')) {
$ids = explode(',', $request->input('id'));
$user->whereIn('id', $ids);
}
//Use pagination
$users = $user->paginate(25);
/**
* Continue with the rest of response formatting below here
*/
}
您会注意到我使用了paginate函数来限制结果。在构建列出资源的API端点时,您需要在标题(我的首选项)或响应正文中输入有关如何获取第一页、上一页、下一页和最后一页结果的信息。Laravel中的分页功能使这变得很容易,因为它可以使用links()
方法构造大多数链接
不幸的是,您需要告诉它在请求中传递了哪些过滤器参数,这样它才能确保将这些参数添加到它生成的链接中。否则,您将在没有过滤器的情况下返回链接,这对客户端分页没有多大好处
下面是一个更完整的示例,用于记录过滤器参数,以便将其附加到分页链接上:
public function getIndex(Request $request)
{
//Create a User object to append WHERE clauses onto
$user = app('App\Models\User');
//List of filters we found to append to links later
$appends = [];
//Run through our simple text fields
foreach(['first_name', 'last_name', 'region', 'ip'] as $field) {
if ($request->has($field)) {
$appends[$field] = $request->input($field);
$user->where($field, $request->input($field));
}
}
//This field uses a LIKE match, handle it separately
if ($request->has('email')) {
$appends['email'] = $request->input('email');
$user->where('email', LIKE, '%' . $request->input('email') . '%');
}
//This field is a list of IDs
if ($request->has('id')) {
$appends['id'] = $request->input('id');
$ids = explode(',', $request->input('id'));
$user->whereIn('id', $ids);
}
//Use pagination
$users = $user->paginate(25);
//Make sure we append our filter parameters onto the pagination object
$users->appends($appends);
//Now calling $users->links() will return the correct links with the right filter info
/**
* Continue with the rest of response formatting below here
*/
}
分页文档可在此处找到:
有关分页链接如何出色完成的示例,请查看Github的API文档:
最后它离你做的事情不远了,