Completed
Push — master ( aa2083...9ba778 )
by Mauro
05:00
created

QueryBuilder   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 304
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 35
dl 0
loc 304
rs 9
c 0
b 0
f 0

20 Methods

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