Passed
Push — master ( 8bced3...4ee652 )
by Mathieu
05:22
created

Collection::collatedSortBy()   A

Complexity

Conditions 3
Paths 1

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 10
c 0
b 0
f 0
nc 1
nop 3
dl 0
loc 15
ccs 7
cts 7
cp 1
crap 3
rs 9.9332
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Suricate;
6
7
use Collator;
8
9
class Collection implements
10
    \Iterator,
11
    \Countable,
12
    \ArrayAccess,
13
    Interfaces\ICollection
14
{
15
    protected $iteratorPosition = 0;
16
17
    protected $items = [];
18
    public $pagination = [
19
        'nbPages' => 0,
20
        'page' => 1,
21
        'nbItems' => 0
22 36
    ];
23
24 36
    public function __construct($items = [])
25 36
    {
26
        $this->items = $items;
27 1
    }
28
29 1
    public function paginate($nbItemPerPage, $currentPage = 1)
30 1
    {
31 1
        $this->pagination['page'] = $currentPage;
32 1
        $this->pagination['nbItems'] = count($this->items);
33
        $this->pagination['nbPages'] = (int) ceil(
34
            $this->pagination['nbItems'] / $nbItemPerPage
35 1
        );
36 1
37 1
        $this->items = array_slice(
38
            $this->items,
39
            ($currentPage - 1) * $nbItemPerPage,
40
            $nbItemPerPage
41 1
        );
42
43
        return $this;
44 1
    }
45
46 1
    /**
47
     * Get current page number
48 1
     *
49 1
     * @return integer
50
     */
51
    public function getPaginationCurrentPage(): int
52
    {
53 1
        return $this->pagination['page'];
54 1
    }
55 1
56 1
    /**
57 1
     * Get total number of pages
58
     *
59
     * @return integer
60 1
     */
61 1
    public function getPaginationNbPages(): int
62 1
    {
63
        return $this->pagination['nbPages'];
64 1
    }
65
66
    public function getPossibleValuesFor($args, $key = null)
67
    {
68 1
        if (!is_array($args)) {
69
            $args = [
70
                'format' => '%s',
71 1
                'data' => [$args]
72
            ];
73 1
        }
74 1
75 1
        $values = [];
76
        foreach ($this->items as $item) {
77
            $itemValues = [];
78 1
            foreach ($args['data'] as $arg) {
79
                $itemValues[] = dataGet($item, $arg);
80
            }
81 14
82
            $arrayKey = $key !== null ? dataGet($item, $key) : null;
83 14
            if (is_null($arrayKey)) {
84
                $values[] = vsprintf($args['format'], $itemValues);
85
            } else {
86
                $values[$arrayKey] = vsprintf($args['format'], $itemValues);
87
            }
88
        }
89
90
        return $values;
91 4
    }
92
93 4
    public function getValuesFor($name)
94
    {
95
        $values = [];
96
        foreach ($this->items as $item) {
97
            $values[] = dataGet($item, $name);
98
        }
99
100
        return $values;
101
    }
102
103
    public function getItems()
104
    {
105
        return $this->items;
106
    }
107
108
    /**
109
     * Implementation of countable interface
110
     *
111
     * @return int
112
     */
113
    public function count(): int
114
    {
115
        return count($this->items);
116
    }
117
118
    public function key(): mixed
119
    {
120
        return $this->iteratorPosition;
121
    }
122
123 2
    public function next(): void
124
    {
125 2
        ++$this->iteratorPosition;
126
    }
127
    public function current(): mixed
128
    {
129
        return $this->offsetGet($this->iteratorPosition);
130
    }
131
    public function rewind(): void
132
    {
133
        $this->iteratorPosition = 0;
134 3
    }
135
    public function valid(): bool
136 3
    {
137 3
        return isset($this->items[$this->iteratorPosition]);
138
    }
139 1
    /**
140
     * Implementation of ArrayAccess interface
141
     *
142
     * @param  mixed $offset Offset to verify
143
     * @return bool
144
     */
145
    public function offsetExists($offset): bool
146
    {
147
        return \array_key_exists($offset, $this->items);
148 1
    }
149
150 1
    /**
151 1
     * Implementation of ArrayAccess Interface
152
     *
153 1
     * @param  mixed $offset Offset to get
154
     * @return mixed
155 1
     */
156
    public function offsetGet(mixed $offset): mixed
157
    {
158
        if (array_key_exists($offset, $this->items)) {
159
            return $this->items[$offset];
160
        }
161
        return null;
162 1
    }
163
164 1
    /**
165 1
     * Implementation of ArrayAccess Interface
166
     *
167
     * @param mixed $offset Offset to set
168
     * @param mixed $value  Value to set
169
     */
170
    public function offsetSet(mixed $offset, mixed $value): void
171
    {
172
        if (is_null($offset)) {
173
            $this->items[] = $value;
174 1
        } else {
175
            $this->items[$offset] = $value;
176 1
        }
177 1
    }
178
179 1
    /**
180
     * Implementation of ArrayAccess Interface
181
     *
182
     * @param mixed $offset Offset to unset
183
     */
184
    public function offsetUnset(mixed $offset): void
185
    {
186 1
        unset($this->items[$offset]);
187
    }
188 1
189 1
    // Helpers
190
191
    /**
192 1
     * Get first item of the collection
193
     *
194
     * @return mixed
195
     */
196
    public function first()
197
    {
198
        foreach ($this->items as $currentItem) {
199
            return $currentItem;
200 1
        }
201
    }
202 1
203
    /**
204
     * Get last item of the collection
205
     *
206
     * @return mixed
207
     */
208
    public function last()
209
    {
210
        if (count($this->items)) {
211 1
            return end($this->items);
212
        }
213 1
214 1
        return null;
215
    }
216 1
217 1
    /**
218 1
     * Check if collection is empty
219
     *
220 1
     * @return bool
221
     */
222
    public function isEmpty(): bool
223
    {
224
        return empty($this->items);
225
    }
226
227
    /**
228
     * Return the sum of the collection
229
     *
230
     * @param mixed $field Field to use for sum
231
     * @return double|integer
232
     */
233
    public function sum($field = null)
234
    {
235
        if ($field === null) {
236
            return array_sum($this->items);
237
        }
238
        $result = 0;
239
        foreach ($this->items as $item) {
240
            $result += dataGet($item, $field);
241
        }
242
        return $result;
243
    }
244
245 1
    public function random($nbItems = 1)
246
    {
247 1
        if ($this->isEmpty()) {
248
            return null;
249
        }
250
251
        $keys = array_rand($this->items, $nbItems);
252
253
        if (is_array($keys)) {
254
            return array_intersect_key($this->items, array_flip($keys));
255
        }
256
257
        return $this->items[$keys];
258
    }
259
260
    public function shuffle()
261
    {
262
        shuffle($this->items);
263
264
        return $this;
265
    }
266
267
    public function unique()
268
    {
269
        return new static(array_unique($this->items));
270
    }
271
272
    /**
273
     * Apply a closure to each element of the collection
274
     *
275
     * @param \Closure $callback Closure to apply
276
     * @return Collection
277
     */
278
    public function each(\Closure $callback): Collection
279
    {
280
        array_map($callback, $this->items);
281
        return $this;
282
    }
283
284
    /**
285
     * Sort a collection using a closure
286
     *
287
     * @param \Closure $closure Closure to apply for sorting, similar to uasort() closure
288
     * @return Collection
289
     */
290
    public function sort(\Closure $closure): Collection
291
    {
292
        uasort($this->items, $closure);
293
294
        return $this;
295
    }
296
297
    public function sortBy($field, $reverse = false)
298
    {
299
        if ($reverse) {
300
            $sortFunction = function ($a, $b) use ($field) {
301
                $first = dataGet($a, $field);
302 1
                $second = dataGet($b, $field);
303
                if ($first == $second) {
304 1
                    return 0;
305
                }
306
                return $first > $second ? -1 : 1;
307 1
            };
308
        } else {
309 1
            $sortFunction = function ($a, $b) use ($field) {
310
                $first = dataGet($a, $field);
311
                $second = dataGet($b, $field);
312 1
                if ($first == $second) {
313
                    return 0;
314 1
                }
315
                return $first < $second ? -1 : 1;
316
            };
317 1
        }
318
319 1
        usort($this->items, $sortFunction);
320
321
        return $this;
322 1
    }
323
324 1
    public function collatedSortBy(string $field, string $locale, bool $reverse = false) {
325
        $collator = new Collator($locale);
326 1
        $collator->setAttribute(Collator::NUMERIC_COLLATION, Collator::ON);
327
        $sortFunction = function ($a, $b) use ($field, $collator, $reverse) {
328
            $first = dataGet($a, $field, '');
329 1
            $second = dataGet($b, $field, '');
330
            $res = $collator->compare($first, $second);
331 1
            if ($res == 0) {
332
                return 0;
333 1
            }
334
335
            return $reverse ? (-1 * $res) : $res;
336 1
        };
337
338 1
        usort($this->items, $sortFunction);
339
    }
340 1
341
    public function filter(\Closure $closure)
342 1
    {
343
        return new static(array_filter($this->items, $closure));
344 1
    }
345
346
    public function search($value, $strict = false)
347 1
    {
348
        return array_search($value, $this->items, $strict);
349 1
    }
350
351
    public function has($key)
352 1
    {
353
        return $this->offsetExists($key);
354 1
    }
355
356
    public function keys()
357 1
    {
358
        return array_keys($this->items);
359 1
    }
360
361
    public function prepend($item)
362 2
    {
363
        array_unshift($this->items, $item);
364 2
365 2
        return $this;
366
    }
367
368
    public function push($item)
369 1
    {
370
        $this->items[] = $item;
371 1
372
        return $this;
373
    }
374
375 1
    public function put($key, $val)
376
    {
377
        $this->items[$key] = $val;
378
379
        return $this;
380
    }
381
    public function shift()
382
    {
383
        return array_shift($this->items);
384
    }
385
386
    public function pop()
387
    {
388
        return array_pop($this->items);
389
    }
390
391
    public function reverse()
392
    {
393
        return new static(array_reverse($this->items));
394
    }
395
396
    public function reduce(callable $callback, $initial = null)
397
    {
398
        return array_reduce($this->items, $callback, $initial);
399
    }
400
401
    public function slice($offset, $length = null, $preserveKeys = false)
402
    {
403
        return new static(
404
            array_slice($this->items, $offset, $length, $preserveKeys)
405
        );
406
    }
407
408
    public function take($limit = null)
409
    {
410
        if ($limit < 0) {
411
            return $this->slice(abs($limit), $limit);
412
        }
413
414
        return $this->slice(0, $limit);
415
    }
416
417
    public function splice($offset, $length = null, $replacement = [])
418
    {
419
        return new static(
420
            array_splice($this->items, $offset, $length, $replacement)
421
        );
422
    }
423
424
    public function chunk($size, $preserveKeys = false)
425
    {
426
        $result = new static();
427
        foreach (array_chunk($this->items, $size, $preserveKeys) as $chunk) {
428
            $result->push(new static($chunk));
429
        }
430
        return $result;
431
    }
432
}
433