ConditionExpression::parseBetweenCondition()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 11
c 0
b 0
f 0
rs 10
cc 1
nc 1
nop 3
1
<?php
2
3
namespace Hoooklife\DynamodbPodm\Parsers;
4
5
use Aws\DynamoDb\Marshaler;
6
use Hoooklife\DynamodbPodm\ComparisonOperator;
7
use Hoooklife\DynamodbPodm\NotSupportedException;
0 ignored issues
show
Bug introduced by
The type Hoooklife\DynamodbPodm\NotSupportedException was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
8
use Hoooklife\DynamodbPodm\Facades\DynamoDb;
0 ignored issues
show
Bug introduced by
The type Hoooklife\DynamodbPodm\Facades\DynamoDb was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
9
10
class ConditionExpression
11
{
12
    const OPERATORS = [
13
        ComparisonOperator::EQ           => '%s = :%s',
14
        ComparisonOperator::LE           => '%s <= :%s',
15
        ComparisonOperator::LT           => '%s < :%s',
16
        ComparisonOperator::GE           => '%s >= :%s',
17
        ComparisonOperator::GT           => '%s > :%s',
18
        ComparisonOperator::BEGINS_WITH  => 'begins_with(%s, :%s)',
19
        ComparisonOperator::BETWEEN      => '(%s BETWEEN :%s AND :%s)',
20
        ComparisonOperator::CONTAINS     => 'contains(%s, :%s)',
21
        ComparisonOperator::NOT_CONTAINS => 'NOT contains(%s, :%s)',
22
        ComparisonOperator::NULL         => 'attribute_not_exists(%s)',
23
        ComparisonOperator::NOT_NULL     => 'attribute_exists(%s)',
24
        ComparisonOperator::NE           => '%s <> :%s',
25
        ComparisonOperator::IN           => '%s IN (%s)',
26
    ];
27
28
    /**
29
     * @var ExpressionAttributeValues
30
     */
31
    protected $values;
32
33
    /**
34
     * @var ExpressionAttributeNames
35
     */
36
    protected $names;
37
38
    /**
39
     * @var Placeholder
40
     */
41
    protected $placeholder;
42
43
    public function __construct(
44
        Placeholder $placeholder,
45
        ExpressionAttributeValues $values,
46
        ExpressionAttributeNames $names
47
    )
48
    {
49
        $this->placeholder = $placeholder;
50
        $this->values = $values;
51
        $this->names = $names;
52
    }
53
54
    /**
55
     * @param array $where
56
     *   [
57
     *     'column' => 'name',
58
     *     'type' => 'EQ',
59
     *     'value' => 'foo',
60
     *     'boolean' => 'and',
61
     *     'type' => 'key'
62
     *   ]
63
     *
64
     * @return string
65
     */
66
    public function parse($wheres)
67
    {
68
        if (empty($wheres)) {
69
            return '';
70
        }
71
72
        $parsed = [];
73
74
        foreach ($wheres as $condition) {
75
            $boolean = array_get($condition, 'boolean');
76
            $value = array_get($condition, 'value');
77
            $operator = array_get($condition, 'operator');
78
79
            $prefix = '';
80
81
            if (count($parsed) > 0) {
82
                $prefix = strtoupper($boolean) . ' ';
83
            }
84
85
            if ($operator === 'Nested') {
86
                $parsed[] = $prefix . $this->parseNestedCondition($value);
0 ignored issues
show
Bug introduced by
It seems like $value can also be of type null; however, parameter $conditions of Hoooklife\DynamodbPodm\P...:parseNestedCondition() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

86
                $parsed[] = $prefix . $this->parseNestedCondition(/** @scrutinizer ignore-type */ $value);
Loading history...
87
                continue;
88
            }
89
            $parsed[] = $prefix . $this->parseCondition(
90
                    array_get($condition, 'column'),
91
                    $operator,
92
                    $value
93
                );
94
        }
95
96
        return implode(' ', $parsed);
97
    }
98
99
    public function reset()
100
    {
101
        $this->placeholder->reset();
102
        $this->names->reset();
103
        $this->values->reset();
104
    }
105
106
    protected function getSupportedOperators()
107
    {
108
        return static::OPERATORS;
109
    }
110
111
    protected function parseNestedCondition(array $conditions)
112
    {
113
        return '(' . $this->parse($conditions) . ')';
114
    }
115
116
    protected function parseCondition($name, $operator, $value)
117
    {
118
        $operators = $this->getSupportedOperators();
119
        if (empty($operators[$operator])) {
120
            throw new NotSupportedException("$operator is not supported");
121
        }
122
123
        $template = $operators[$operator];
124
125
        $this->names->set($name);
126
127
        if ($operator === ComparisonOperator::BETWEEN) {
128
            return $this->parseBetweenCondition($name, $value, $template);
129
        }
130
131
        if ($operator === ComparisonOperator::IN) {
132
            return $this->parseInCondition($name, $value, $template);
133
        }
134
135
        if ($operator === ComparisonOperator::NULL || $operator === ComparisonOperator::NOT_NULL) {
136
            return $this->parseNullCondition($name, $template);
137
        }
138
139
        $placeholder = $this->placeholder->next();
140
141
        $this->values->set($placeholder, (new Marshaler())->marshalValue($value));
142
143
        return sprintf($template, $this->names->placeholder($name), $placeholder);
144
    }
145
146
    protected function parseBetweenCondition($name, $value, $template)
147
    {
148
        $first = $this->placeholder->next();
149
150
        $second = $this->placeholder->next();
151
152
        $this->values->set($first, DynamoDb::marshalValue($value[0]));
153
154
        $this->values->set($second, DynamoDb::marshalValue($value[1]));
155
156
        return sprintf($template, $this->names->placeholder($name), $first, $second);
157
    }
158
159
    protected function parseInCondition($name, $value, $template)
160
    {
161
        $valuePlaceholders = [];
162
163
        foreach ($value as $item) {
164
            $placeholder = $this->placeholder->next();
165
166
            $valuePlaceholders[] = ":" . $placeholder;
167
168
            $this->values->set($placeholder, DynamoDb::marshalValue($item));
169
        }
170
171
        return sprintf($template, $this->names->placeholder($name), implode(', ', $valuePlaceholders));
172
    }
173
174
    protected function parseNullCondition($name, $template)
175
    {
176
        return sprintf($template, $this->names->placeholder($name));
177
    }
178
}
179
180
function array_get($array, $key, $default = null)
181
{
182
    if (is_null($key)) {
183
        return $array;
184
    }
185
186
    if (isset($array[$key])) {
187
        return $array[$key];
188
    }
189
190
    foreach (explode('.', $key) as $segment) {
191
        if (!is_array($array) || !array_key_exists($segment, $array)) {
192
            return $default;
193
        }
194
195
        $array = $array[$segment];
196
    }
197
    return $array;
198
}