Completed
Push — master ( c84bd8...87df9b )
by Mauro
01:57
created

QueryBuilder::sortedBy()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 7
nc 1
nop 3
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
     * @param array $array
230
     *
231
     * @return array
232
     */
233
    private function applySortingFilter(array $array)
234
    {
235
        return SortingFilter::filter($array, $this->sortedBy);
236
    }
237
238
    /**
239
     * @param array $array
240
     *
241
     * @return array
242
     */
243
    private function applyLimitFilter(array $array)
244
    {
245
        return LimitFilter::filter($array, $this->limit);
246
    }
247
248
    /**
249
     * @return array
250
     */
251
    private function applyJoinFilter()
252
    {
253
        return JoinFilter::filter($this->array, $this->join);
254
    }
255
256
    /**
257
     * @return array
258
     */
259
    private function applyCriteriaFilter(array $array)
260
    {
261
        if (count($this->criteria) === 0) {
262
            return $array;
263
        }
264
265
        foreach ($this->criteria as $criterion) {
266
            $results = array_filter(
267
                (isset($results)) ? $results : $array, function ($element) use ($criterion) {
268
                    return CriterionFilter::filter($criterion, $element);
269
                }
270
            );
271
        }
272
273
        return $results;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $results seems to be defined by a foreach iteration on line 265. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
274
    }
275
276
    /**
277
     * @param $element
278
     * @return array
279
     */
280
    private function castElementToArray($element)
281
    {
282
        return (array) $element;
283
    }
284
285
    /**
286
     * @return int
287
     */
288
    public function getCount()
289
    {
290
        return count($this->getResults());
291
    }
292
}
293