Completed
Push — master ( b3d518...aa2083 )
by Mauro
02:00
created

QueryBuilder::getShuffledResults()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 6
nc 2
nop 0
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 getFirstResult()
214
    {
215
        return $this->getResults()[0] ?: [];
216
    }
217
218
    /**
219
     * @return array
220
     */
221
    public function getLastResult()
222
    {
223
        $count = count($this->getResults());
224
225
        return $this->getResults()[$count-1] ?: [];
226
    }
227
228
    /**
229
     * @return array
230
     */
231
    public function getShuffledResults()
232
    {
233
        $shuffledArray = [];
234
        $keys = array_keys($this->getResults());
235
        shuffle($keys);
236
237
        foreach ($keys as $key) {
238
            $shuffledArray[$key] = $this->getResults()[$key];
239
        }
240
241
        return $shuffledArray;
242
    }
243
244
    /**
245
     * @param array $array
246
     *
247
     * @return array
248
     */
249
    private function applySortingFilter(array $array)
250
    {
251
        return SortingFilter::filter($array, $this->sortedBy);
252
    }
253
254
    /**
255
     * @param array $array
256
     *
257
     * @return array
258
     */
259
    private function applyLimitFilter(array $array)
260
    {
261
        return LimitFilter::filter($array, $this->limit);
262
    }
263
264
    /**
265
     * @return array
266
     */
267
    private function applyJoinFilter()
268
    {
269
        return JoinFilter::filter($this->array, $this->join);
270
    }
271
272
    /**
273
     * @return array
274
     */
275
    private function applyCriteriaFilter(array $array)
276
    {
277
        if (count($this->criteria) === 0) {
278
            return $array;
279
        }
280
281
        foreach ($this->criteria as $criterion) {
282
            $results = array_filter(
283
                (isset($results)) ? $results : $array, function ($element) use ($criterion) {
284
                    return CriterionFilter::filter($criterion, $element);
285
                }
286
            );
287
288
            $results = array_map(function($result) use ($criterion) {
289
                $key = explode(Constants::ALIAS_DELIMITER, $criterion['key']);
290
                if(count($key) > 1){
291
                    $oldkey = explode(Constants::ARRAY_SEPARATOR, $key[0]);
292
                    $newkey = $key[1];
293
294
                    $result = (array)($result);
295
                    $result[$newkey] = $result[$oldkey[0]];
296
                    unset($result[$oldkey[0]]);
297
                }
298
                return $result;
299
            }, $results);
300
        }
301
302
        return $results;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $results seems to be defined by a foreach iteration on line 281. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
303
    }
304
305
    /**
306
     * @param $element
307
     * @return array
308
     */
309
    private function castElementToArray($element)
310
    {
311
        return (array) $element;
312
    }
313
314
    /**
315
     * @return int
316
     */
317
    public function getCount()
318
    {
319
        return count($this->getResults());
320
    }
321
}
322