Completed
Push — master ( 9ba778...870b98 )
by Mauro
01:54
created

QueryBuilder::isAValidCriterionOperator()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
eloc 1
nc 1
nop 1
1
<?php
2
/**
3
 * This file is part of the ArrayQuery package.
4
 *
5
 * (c) Mauro Cassani<https://github.com/mauretto78>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace ArrayQuery;
12
13
use ArrayQuery\Exceptions\EmptyArrayException;
14
use ArrayQuery\Exceptions\InvalidArrayException;
0 ignored issues
show
Bug introduced by
The type ArrayQuery\Exceptions\InvalidArrayException 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...
15
use ArrayQuery\Exceptions\NotConsistentDataException;
16
use ArrayQuery\Exceptions\NotValidCriterionOperatorException;
17
use ArrayQuery\Exceptions\NotValidKeyElementInArrayException;
18
use ArrayQuery\Exceptions\NotValidLimitsOfArrayException;
19
use ArrayQuery\Exceptions\NotValidSortingOperatorException;
20
use ArrayQuery\Filters\CriterionFilter;
21
use ArrayQuery\Filters\JoinFilter;
22
use ArrayQuery\Filters\SortingFilter;
23
use ArrayQuery\Filters\LimitFilter;
24
use ArrayQuery\Helpers\ArrayConverter;
25
use ArrayQuery\Helpers\ConsistencyChecker;
26
27
class QueryBuilder
28
{
29
    /**
30
     * @var array
31
     */
32
    private $criteria;
33
34
    /**
35
     * @var array
36
     */
37
    private $sortedBy;
38
39
    /**
40
     * @var array
41
     */
42
    private $limit;
43
44
    /**
45
     * @var array
46
     */
47
    private $join;
48
49
    /**
50
     * @var array
51
     */
52
    private $array;
53
54
    /**
55
     * QueryBuilder constructor.
56
     * @param array $array
57
     */
58
    public function __construct(array $array)
59
    {
60
        $this->setArray($array);
61
    }
62
63
    /**
64
     * @param array $array
65
     * @return static
66
     */
67
    public static function create(array $array)
68
    {
69
        return new static($array);
70
    }
71
72
    /**
73
     * @param array $array
74
     * @throws EmptyArrayException
75
     * @throws NotConsistentDataException
76
     */
77
    private function setArray(array $array)
78
    {
79
        if (empty($array)) {
80
            throw new EmptyArrayException('Empty array provided.');
81
        }
82
83
        if (false === ConsistencyChecker::isValid($array)) {
84
            throw new NotConsistentDataException('Array provided has no consistent data.');
85
        }
86
87
        $this->array = $array;
88
    }
89
90
    /**
91
     * @param $key
92
     * @param $value
93
     * @param string $operator
94
     * @param null $dateFormat
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $dateFormat is correct as it would always require null to be passed?
Loading history...
95
     * @return $this
96
     * @throws NotValidCriterionOperatorException
97
     */
98
    public function addCriterion($key, $value, $operator = '=', $dateFormat = null)
99
    {
100
        if (!$this->isAValidCriterionOperator($operator)) {
101
            throw new NotValidCriterionOperatorException($operator.' is not a valid operator.');
102
        }
103
104
        $this->criteria[] = [
105
            'key' => $key,
106
            'value' => $value,
107
            'operator' => $operator,
108
            'date_format' => $dateFormat
109
        ];
110
111
        return $this;
112
    }
113
114
    /**
115
     * @param $operator
116
     * @return bool
117
     */
118
    private function isAValidCriterionOperator($operator)
119
    {
120
        return in_array($operator, array_keys(CriterionFilter::$operatorsMap));
121
    }
122
123
    /**
124
     * @param $key
125
     * @param string $operator
126
     *
127
     * @return $this
128
     *
129
     * @throws NotValidSortingOperatorException
130
     */
131
    public function sortedBy($key, $operator = 'ASC', $format = null)
132
    {
133
        if (!$this->isAValidSortingOperator($operator)) {
134
            throw new NotValidSortingOperatorException($operator.' is not a valid sorting operator.');
135
        }
136
137
        $this->sortedBy = [
138
            'key' => $key,
139
            'order' => $operator,
140
            'format' => $format
141
        ];
142
143
        return $this;
144
    }
145
146
    /**
147
     * @param $operator
148
     * @return bool
149
     */
150
    private function isAValidSortingOperator($operator)
151
    {
152
        return in_array($operator, SortingFilter::$operatorsMap);
153
    }
154
155
    /**
156
     * @param $offset
157
     * @param $length
158
     * @return $this
159
     * @throws NotValidLimitsOfArrayException
160
     */
161
    public function limit($offset, $length)
162
    {
163
        if (!is_integer($offset)) {
164
            throw new NotValidLimitsOfArrayException($offset.' must be an integer.');
165
        }
166
167
        if (!is_integer($length)) {
168
            throw new NotValidLimitsOfArrayException($length.' must be an integer.');
169
        }
170
171
        if ($offset > $length) {
172
            throw new NotValidLimitsOfArrayException($offset.' must be an < than '.$length.'.');
173
        }
174
175
        if ($length > count($this->array)) {
176
            throw new NotValidLimitsOfArrayException($length.' must be an > than array count.');
177
        }
178
179
        $this->limit = [
180
            'offset' => $offset,
181
            'lenght' => $length,
182
        ];
183
184
        return $this;
185
    }
186
187
    /**
188
     * @param $array
189
     * @param $arrayName
190
     * @param $parentKey
191
     * @param $foreignKey
192
     *
193
     * @return $this
194
     */
195
    public function join($array, $arrayName, $parentKey, $foreignKey)
196
    {
197
        $this->join[] = [
198
            'array' => $array,
199
            'arrayName' => $arrayName,
200
            'parentKey' => $parentKey,
201
            'foreignKey' => $foreignKey,
202
        ];
203
204
        return $this;
205
    }
206
207
    /**
208
     * @return array
209
     */
210
    public function getResults()
211
    {
212
        $results = $this->applySortingFilter($this->applyLimitFilter($this->applyCriteriaFilter($this->applyJoinFilter())));
213
214
        return array_map([$this, 'castElementToArray'], $results);
215
    }
216
217
    /**
218
     * @return array
219
     */
220
    public function getResult($n)
221
    {
222
        return $this->getResults()[$n-1] ?: [];
223
    }
224
225
    /**
226
     * @return array
227
     */
228
    public function getFirstResult()
229
    {
230
        return $this->getResults()[0] ?: [];
231
    }
232
233
    /**
234
     * @return array
235
     */
236
    public function getLastResult()
237
    {
238
        $count = count($this->getResults());
239
240
        return $this->getResults()[$count-1] ?: [];
241
    }
242
243
    /**
244
     * @return array
245
     */
246
    public function getShuffledResults()
247
    {
248
        $shuffledArray = [];
249
        $keys = array_keys($this->getResults());
250
        shuffle($keys);
251
252
        foreach ($keys as $key) {
253
            $shuffledArray[$key] = $this->getResults()[$key];
254
        }
255
256
        return $shuffledArray;
257
    }
258
259
    /**
260
     * @param array $array
261
     *
262
     * @return array
263
     */
264
    private function applySortingFilter(array $array)
265
    {
266
        return SortingFilter::filter($array, $this->sortedBy);
267
    }
268
269
    /**
270
     * @param array $array
271
     *
272
     * @return array
273
     */
274
    private function applyLimitFilter(array $array)
275
    {
276
        return LimitFilter::filter($array, $this->limit);
277
    }
278
279
    /**
280
     * @return array
281
     */
282
    private function applyJoinFilter()
283
    {
284
        return JoinFilter::filter($this->array, $this->join);
285
    }
286
287
    /**
288
     * @return array
289
     */
290
    private function applyCriteriaFilter(array $array)
291
    {
292
        if (count($this->criteria) === 0) {
293
            return $array;
294
        }
295
296
        foreach ($this->criteria as $criterion) {
297
            $results = array_filter(
298
                (isset($results)) ? $results : $array, function ($element) use ($criterion) {
299
                    return CriterionFilter::filter($criterion, $element);
300
                }
301
            );
302
303
            $results = array_map(function ($result) use ($criterion) {
304
                $key = explode(Constants::ALIAS_DELIMITER, $criterion['key']);
305
                if (count($key) > 1) {
306
                    $oldkey = explode(Constants::ARRAY_SEPARATOR, $key[0]);
307
                    $newkey = $key[1];
308
309
                    $result = ArrayConverter::convertToPlainArray($result);
310
                    $result[$newkey] = $result[$oldkey[0]];
311
                    unset($result[$oldkey[0]]);
312
                }
313
                return $result;
314
            }, $results);
315
        }
316
317
        return $results;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $results seems to be defined by a foreach iteration on line 296. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
318
    }
319
320
    /**
321
     * @param $element
322
     * @return array
323
     */
324
    private function castElementToArray($element)
325
    {
326
        return ArrayConverter::convertToPlainArray($element);
327
    }
328
329
    /**
330
     * @return int
331
     */
332
    public function getCount()
333
    {
334
        return count($this->getResults());
335
    }
336
}
337