1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* JSONText database backend that encapsulates a Postgres-like syntax for JSON querying. |
5
|
|
|
* |
6
|
|
|
* @package silverstripe-jsontext |
7
|
|
|
* @subpackage models |
8
|
|
|
* @author Russell Michell <[email protected]> |
9
|
|
|
* @see https://www.postgresql.org/docs/9.6/static/functions-json.html |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
namespace PhpTek\JSONText\Backend; |
13
|
|
|
|
14
|
|
|
use PhpTek\JSONText\Exception\JSONTextInvalidArgsException; |
15
|
|
|
|
16
|
|
|
class PostgresJSONBackend extends JSONBackend |
17
|
|
|
{ |
18
|
|
|
/** |
19
|
|
|
* An array of acceptable operators for this backend. |
20
|
|
|
* |
21
|
|
|
* @var array |
22
|
|
|
* @config |
23
|
|
|
*/ |
24
|
|
|
private static $allowed_operators = [ |
25
|
|
|
'matchOnInt' => '->', |
26
|
|
|
'matchOnStr' => '->>', |
27
|
|
|
'matchOnPath' => '#>' |
28
|
|
|
]; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* @inheritdoc |
32
|
|
|
*/ |
33
|
|
View Code Duplication |
public function matchOnInt() |
|
|
|
|
34
|
|
|
{ |
35
|
|
|
if (!\is_int($this->operand)) { |
36
|
|
|
$msg = 'Non-integer passed to: ' . __FUNCTION__ . '()'; |
37
|
|
|
throw new JSONTextInvalidArgsException($msg); |
38
|
|
|
} |
39
|
|
|
|
40
|
|
|
$expr = '$.[' . $this->operand . ']'; |
41
|
|
|
$fetch = $this->jsonText->getJSONStore()->get($expr); |
42
|
|
|
$vals = \array_values($fetch); |
43
|
|
|
|
44
|
|
|
if (isset($vals[0])) { |
45
|
|
|
return [$this->operand => $vals[0]]; |
46
|
|
|
} |
47
|
|
|
|
48
|
|
|
return []; |
49
|
|
|
} |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* @inheritdoc |
53
|
|
|
*/ |
54
|
|
View Code Duplication |
public function matchOnStr() |
|
|
|
|
55
|
|
|
{ |
56
|
|
|
if (!\is_string($this->operand)) { |
57
|
|
|
$msg = 'Non-string passed to: ' . __FUNCTION__ . '()'; |
58
|
|
|
throw new JSONTextInvalidArgsException($msg); |
59
|
|
|
} |
60
|
|
|
|
61
|
|
|
$expr = '$..' . $this->operand; |
62
|
|
|
$fetch = $this->jsonText->getJSONStore()->get($expr); |
63
|
|
|
$vals = \array_values($fetch); |
64
|
|
|
|
65
|
|
|
if (isset($vals[0])) { |
66
|
|
|
return [$this->operand => $vals[0]]; |
67
|
|
|
} |
68
|
|
|
|
69
|
|
|
return []; |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* @inheritdoc |
74
|
|
|
*/ |
75
|
|
|
public function matchOnPath() |
76
|
|
|
{ |
77
|
|
|
if (!\is_string($this->operand) || !$this->jsonText->isValidJson($this->operand)) { |
78
|
|
|
$msg = 'Invalid JSON passed as operand on RHS.'; |
79
|
|
|
throw new JSONTextInvalidArgsException($msg); |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
$operandAsArray = $this->jsonText->toArray($this->operand); |
83
|
|
|
|
84
|
|
|
if (!\count($operandAsArray)) { |
85
|
|
|
return []; |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
$keys = \array_keys($operandAsArray); |
89
|
|
|
$vals = \array_values($operandAsArray); |
90
|
|
|
|
91
|
|
|
if (\count($keys) > 1 || \count($vals) > 1) { |
92
|
|
|
$msg = 'Sorry. I can\'t handle complex operands.'; |
93
|
|
|
throw new JSONTextInvalidArgsException($msg); |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
$source = $this->jsonText->getStoreAsArray(); |
97
|
|
|
$sourceAsIterator = new \RecursiveIteratorIterator( |
98
|
|
|
new \RecursiveArrayIterator($source), |
99
|
|
|
\RecursiveIteratorIterator::SELF_FIRST |
100
|
|
|
); |
101
|
|
|
|
102
|
|
|
$data = []; |
103
|
|
|
foreach ($sourceAsIterator as $sourceKey => $sourceVal) { |
104
|
|
|
if ($keys[0] === $sourceKey && is_array($sourceVal) && !empty($sourceVal[$vals[0]])) { |
105
|
|
|
$data[] = $sourceVal[$vals[0]]; |
106
|
|
|
} |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
return $data; |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
} |
113
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.