Php 基于json的动态雄辩查询
我想根据数据库中的payloadjson动态查询 例如:Php 基于json的动态雄辩查询,php,laravel,Php,Laravel,我想根据数据库中的payloadjson动态查询 例如: $data = [{"key":"age","relation":">","value":"15"},{"operator":"OR"},{"key":"age","relation":"<=","value":"20"}] 问题是,它可以工作,但我不认为这是最好的方法。我找不到任何使用操作键的解决方案。操作员的用法是更改到何处或在何处 有什么解决方案或技巧可以让它像这样动态调用吗?。我希望我在DB的专栏简洁明了。我只能这样
$data = [{"key":"age","relation":">","value":"15"},{"operator":"OR"},{"key":"age","relation":"<=","value":"20"}]
问题是,它可以工作,但我不认为这是最好的方法。我找不到任何使用操作键的解决方案。操作员的用法是更改到何处或在何处
有什么解决方案或技巧可以让它像这样动态调用吗?。我希望我在DB的专栏简洁明了。我只能这样想
谢谢 您可以这样进行原始查询
$data = '[{"key":"age","relation":">","value":"15"},{"operator":"OR"},{"key":"age","relation":"<=","value":"20"}]';
$query = "SELECT * FROM tablename WHERE";
$payload = json_decode($data, true);
foreach ($payload as $value) {
if (isset($value['operator'])) {
$query .= " " . $value['operator'];
} else {
if ($value['key'] == 'age') {
$query .= " 'birthday' " . $value['relation'] . " " . Carbon::now()->subYears($value['value'])->format('Y-m-d');
}
if ($value['key'] == 'gender') {
$query .= " 'gender' " . $value['relation'] . " " . $value['gender'];
}
}
}
这将产生如下查询:
SELECT * FROM tablename WHERE 'birthday' > 2001-07-02 OR 'birthday' <= 1996-07-02
当然,您可能会使用printf进行格式化,并以其他方式使其更清晰,但这将使您满怀希望地开始工作。您可以像这样进行原始查询
$data = '[{"key":"age","relation":">","value":"15"},{"operator":"OR"},{"key":"age","relation":"<=","value":"20"}]';
$query = "SELECT * FROM tablename WHERE";
$payload = json_decode($data, true);
foreach ($payload as $value) {
if (isset($value['operator'])) {
$query .= " " . $value['operator'];
} else {
if ($value['key'] == 'age') {
$query .= " 'birthday' " . $value['relation'] . " " . Carbon::now()->subYears($value['value'])->format('Y-m-d');
}
if ($value['key'] == 'gender') {
$query .= " 'gender' " . $value['relation'] . " " . $value['gender'];
}
}
}
这将产生如下查询:
SELECT * FROM tablename WHERE 'birthday' > 2001-07-02 OR 'birthday' <= 1996-07-02
当然,您可以使用printf进行格式化,并以其他方式使其更清晰,但这将使您满怀希望地开始工作。归根结底,这个想法是它自己的限制,因为存储的查询必须表示数据库的当前状态。这意味着,当数据以不同的方式存储时,这些查询的维护成本将是巨大的——如果将“生日”列更改为“出生日期”,则所有存储的查询都将中断。避免这种情况
相反,通过使用and将查询存储在模型上,可以更好地实现这一目标。如果您仍然需要请求的动态列表,您可以存储与查询相关联的关键字并循环查询。归根结底,这个想法是它自己的限制,因为存储的查询必须表示数据库的当前状态。这意味着,当数据以不同的方式存储时,这些查询的维护成本将是巨大的——如果将“生日”列更改为“出生日期”,则所有存储的查询都将中断。避免这种情况
相反,通过使用and将查询存储在模型上,可以更好地实现这一目标。如果您仍然需要请求的动态列表,则可以存储与查询关联的关键字并循环查询。您可以使用变量函数名添加orWhere逻辑:
只要您的json数据与您的数据库不匹配,即json有年龄,但数据库有生日,您将无法避免使用if/else语句。该自定义逻辑必须保留。您可以使用变量函数名添加orWhere逻辑:
只要您的json数据与您的数据库不匹配,即json有年龄,但数据库有生日,您将无法避免使用if/else语句。这种自定义逻辑将不得不保留。遇到这个问题,我同意。在这种方法中,您可以创建一个名为scopeJson的模型方法,或者任何您觉得更好的方法来处理其中的所有条件。我试图处理这里的大多数情况,而不仅仅是单一的地点和地点。我假设您的有效负载一次只包含一个生成器
public function scopeJson($query, $json)
{
$wheres = [
'between' => ['whereBetween', 'not' => 'whereNotBetween'],
'null' => ['whereNull', 'not' => 'whereNotNull'],
'or' => ['orWhere', 'not' => 'orWhereNot'],
'in' => ['whereIn', 'not' => 'whereNotIn'],
'and' => ['where', 'not' => 'orWhereNot'],
'raw' => 'whereRaw'
];
$builder = json_decode($json);
if (count($builder) > 0) {
$query->where(
$builder[0]->key,
$builder[0]->relation,
$builder[0]->value
);
// notBetween, notNull, notOr, notIn, notAnd
if (stripos($builder[1]->operator, 'not') !== false) {
$whereCondition = $wheres[strtolower(substr($builder[1]->operator, 3))]['not'];
} else {
$whereCondition = $wheres[strtolower($builder[1]->operator)];
}
if (count($builder[2]) == 3) {
if ($whereCondition == 'whereRaw') {
$query->$whereCondition(implode(" ", $builder[2]));
} else {
// where, whereNot
$query->$whereCondition(
$builder[2]->key,
$builder[2]->relation,
$builder[2]->value
);
}
} elseif (count($builder[2]) == 2) {
// whereBetween, whereNotBetween, where, whereNot
$query->$whereCondition(
$builder[2]->key,
$builder[2]->value
);
} elseif (count($builder[2]) == 1) {
// whereNull, whereNotNull, whereRaw
$query->$whereCondition(
$builder[2]->key ?? $builder[2]->value // PHP 7.0 Null Coalescing Operator
);
}
}
return $query;
}
如果此方法是在用户模型中定义的,则可以通过以下方式使用:
$users = User::json($data)->get();
PS:虽然它应该可以工作,但我没有测试它。遇到这个问题,我会同意。在这种方法中,您可以创建一个名为scopeJson的模型方法,或者任何您觉得更好的方法来处理其中的所有条件。我试图处理这里的大多数情况,而不仅仅是单一的地点和地点。我假设您的有效负载一次只包含一个生成器
public function scopeJson($query, $json)
{
$wheres = [
'between' => ['whereBetween', 'not' => 'whereNotBetween'],
'null' => ['whereNull', 'not' => 'whereNotNull'],
'or' => ['orWhere', 'not' => 'orWhereNot'],
'in' => ['whereIn', 'not' => 'whereNotIn'],
'and' => ['where', 'not' => 'orWhereNot'],
'raw' => 'whereRaw'
];
$builder = json_decode($json);
if (count($builder) > 0) {
$query->where(
$builder[0]->key,
$builder[0]->relation,
$builder[0]->value
);
// notBetween, notNull, notOr, notIn, notAnd
if (stripos($builder[1]->operator, 'not') !== false) {
$whereCondition = $wheres[strtolower(substr($builder[1]->operator, 3))]['not'];
} else {
$whereCondition = $wheres[strtolower($builder[1]->operator)];
}
if (count($builder[2]) == 3) {
if ($whereCondition == 'whereRaw') {
$query->$whereCondition(implode(" ", $builder[2]));
} else {
// where, whereNot
$query->$whereCondition(
$builder[2]->key,
$builder[2]->relation,
$builder[2]->value
);
}
} elseif (count($builder[2]) == 2) {
// whereBetween, whereNotBetween, where, whereNot
$query->$whereCondition(
$builder[2]->key,
$builder[2]->value
);
} elseif (count($builder[2]) == 1) {
// whereNull, whereNotNull, whereRaw
$query->$whereCondition(
$builder[2]->key ?? $builder[2]->value // PHP 7.0 Null Coalescing Operator
);
}
}
return $query;
}
如果此方法是在用户模型中定义的,则可以通过以下方式使用:
$users = User::json($data)->get();
PS:虽然它应该可以工作,但我没有测试它。如果您希望查询是直接的或简单的,那么在这种情况下,您应该更喜欢编写原始查询。那会更干净。@VishalSh谢谢你的建议。在我的例子中有原始查询的例子吗?@s您在有效负载中发送的是什么和运算符?@z3r0ck是的。你说得对。因此,我可以按自己的意愿设置任意多个键。@s您使用的是什么版本的laravel?如果您希望查询是直接的或简单的,那么在这种情况下,您应该更喜欢编写原始查询。那会更干净。@VishalSh谢谢你的建议。在我的例子中有原始查询的例子吗?@s您在有效负载中发送的是什么和运算符?@z3r0ck是的。你说得对。所以我可以放任意数量的钥匙。@s您使用的是什么版本的laravel?嗨。。但是如果json数组是空的呢。这意味着,若并没有给出任何条件,那个么查询将是select*from tablename,其中,这个查询将运行吗?一个简单的if检查可以实现这一点。正如我提到的,这只是一个起点。。但是如果json数组是空的呢。这意味着,若并没有给出任何条件,那个么查询将是select*from tablename,其中,这个查询将运行吗?一个简单的if检查可以实现这一点。正如我提到的,这只是一个起点。