json-logic-php
json-logic-php copied to clipboard
[Feature request] New variables
Hello. First of all, thank you for this project. Secondly, this is not PR, but some thoughts on the new look of JsonLogic.
Callable $data
Sometimes we need dynamic data using sql/cache/etc
JWadhams\JsonLogic::apply(
[
"in" => [
"my_tag",
["var" => "post_tags"]
]
],
function (?string $tags_type = null) {
switch ($tags_type) {
...
case "post_tags": {
return DB::query("SELECT ...")->toArray();
}
...
}
return null;
}
);
Static variables/iterations + some sugar
The problem with var logic is recursions like some, reduce, etc. This is due to the fact that we overwrite data, e.g:
...
} elseif ($op === "filter") {
$scopedData = static::apply($values[0], $data);
$scopedLogic = $values[1];
if (!$scopedData || !is_array($scopedData)) {
return [];
}
return array_values(
array_filter($scopedData, function ($datum) use ($scopedLogic) {
return static::truthy(static::apply($scopedLogic, $datum)); // <-- Now our data has been overwritten
})
);
} elseif ($op === "map") {
...
https://github.com/jwadhams/json-logic-php/blame/e4ea3a46f44d3d34740276f7a21f8f052b029743/src/JWadhams/JsonLogic.php#L263-L267C15
We have lost the original $data, but sometimes we need access to it.
Example. My post has some tags, such as: ["php", "js", "webdev", "docker"], I want to group all cloud posts into a separate category. For searching I want to use logic like:
JsonLogic::apply(
[
"some" => [
["k8s", "docker", "cloud native"],
[
"in": [
["var" => ""],
["var" => "tags"] // <-- here problem
]
]
]
],
["tags" => ["php", "js", "webdev", "docker"]
);
Right now we can't access the original $data in recursion.
Here's what I suggest.
Add new logic for the $var keys (like var) and $iteration to look like this:
JsonLogic::apply(
[
"some" => [
["k8s", "docker", "cloud native"],
[
"in": [
"$iteration",
["$var" => "tags"]
]
]
]
],
["tags" => ["php", "js", "webdev", "docker"]]
);
(in sample i use sugar for "$iteration", it can be used similarly: ["$iteration"], ["$iteration" => null], etc)
Why i think it is best solution:
- Full compatibility with current logic, no modification of old rules/logic required
- Logical separation between user-variables and iterative-variables
Problem/Todo
- [ ]
$iterationonly at current level, I think we should make access to upper levels of$iteration. - [x] Cache for called $data, n+1 recursion logic problem
- [ ] We need to switch to OOP. Static accessor - I like it, but we need some structure in code
What does the community think about this?
Cache for callable
Simple and stupid cache for callable $data.
$cache_key = md5(implode(':', [
json_encode($logic),
(new \ReflectionFunction($data))->__toString(),
$a
]));
if (isset(static::$callable_cache[$cache_key])) {
return static::$callable_cache[$cache_key];
}
if no change in $logic, $a (params) and function reflection (the most important thing -- a start line of code), then we don't need to call this function again
Callable params
In the current version, we access our $data via var, or its key if it is an object/array. For example: {'var': ['items.0.qty']}. In the case of callable $data, it is much more important to be able to pass multiple parameters than to be able to "reach" the right key. Example:
JWadhams\JsonLogic::apply(
[
"in" => [
"k8s",
['$var' => [["tags", 2]]]
]
],
function ($type, $post_id) {
if ($type === 'tags') {
if ($post_id == 1) return ["php", "js"];
if ($post_id == 2) return ["docker", "k8s"];
}
return [];
}
)
Important: To maintain backward compatibility with $default, you must pass the first element of the array as an array to get the argument list on the input to the function.