Passed
Push — master ( e94cf7...1fa749 )
by Mauro
04:55
created

QueryBuilder::removeElement()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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