Completed
Push — master ( 132094...4f9d9f )
by Roman
02:53 queued 57s
created

Collection::last()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace kartavik\Collections;
4
5
use kartavik\Collections\Exception;
6
7
/**
8
 * Class Collection
9
 * @package kartavik\Collections
10
 */
11
class Collection implements \ArrayAccess, \Countable, \IteratorAggregate, \JsonSerializable
12
{
13
    /** @var string */
14
    private $type = null;
15
16
    /** @var array */
17
    protected $container = [];
18
19
    public function __construct(string $type, iterable ...$iterables)
20
    {
21
        static::validateObject($type);
22
23
        $this->type = $type;
24
25
        foreach ($iterables as $iterable) {
26
            foreach ($iterable as $index => $item) {
27
                $this->add($item, $index);
28
            }
29
        }
30
    }
31
32
    final public function type(): string
33
    {
34
        return $this->type;
35
    }
36
37
    public function offsetExists($offset): bool
38
    {
39
        return isset($this->container[$offset]);
40
    }
41
42
    public function offsetGet($offset): object
43
    {
44
        return $this->container[$offset];
45
    }
46
47
    public function offsetUnset($offset): void
48
    {
49
        if ($this->offsetExists($offset)) {
50
            unset($this->container[$offset]);
51
        }
52
    }
53
54
    public function getIterator(): \ArrayIterator
55
    {
56
        return new \ArrayIterator($this->container);
57
    }
58
59
    public function append(): void
60
    {
61
        $items = func_get_args();
62
63
        foreach ($items as $item) {
64
            $this->add($item);
65
        }
66
    }
67
68
    /**
69
     * @param mixed $index
70
     * @param mixed $value
71
     *
72
     * @throws Exception\InvalidElement
73
     */
74
    public function offsetSet($index, $value): void
75
    {
76
        $this->add($value, $index);
77
    }
78
79
    public function jsonSerialize(): array
80
    {
81
        return $this->container;
82
    }
83
84
    public function isCompatible($var): bool
85
    {
86
        try {
87
            if ($var instanceof self) {
88
                return true;
89
            } elseif (is_array($var)) {
90
                foreach ($var as $item) {
91
                    try {
92
                        $this->validate($item);
93
                    } catch (Exception\InvalidElement $ex) {
94
                        return false;
95
                    }
96
                }
97
98
                return true;
99
            }
100
        } catch (\InvalidArgumentException $exception) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
101
        } finally {
102
            return false;
103
        }
104
    }
105
106
    public function first(): object
107
    {
108
        reset($this->container);
109
110
        return current($this->container);
111
    }
112
113
    public function last(): object
114
    {
115
        end($this->container);
116
117
        return current($this->container);
118
    }
119
120
    /**
121
     * @param $item
122
     *
123
     * @throws Exception\InvalidElement
124
     */
125
    public function validate($item): void
126
    {
127
        $type = $this->type();
128
129
        if (!$item instanceof $type) {
130
            throw new Exception\UnprocessedType($item, $type);
0 ignored issues
show
Bug introduced by
$type of type string is incompatible with the type integer expected by parameter $code of kartavik\Collections\Exc...ssedType::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

130
            throw new Exception\UnprocessedType($item, /** @scrutinizer ignore-type */ $type);
Loading history...
131
        }
132
    }
133
134
    public function chunk(int $size): Collection
135
    {
136
        $mappedType = get_class($this->offsetGet(0));
137
        /** @var Collection $collection */
138
        $collection = Collection::{Collection::class}();
139
        $chunked = array_chunk($this->jsonSerialize(), $size);
140
141
        foreach ($chunked as $index => $chunk) {
142
            $collection->append(Collection::{$mappedType}());
143
144
            foreach ($chunk as $item) {
145
                $collection[$index]->append($item);
146
            }
147
        }
148
149
        return $collection;
150
    }
151
152
    public function column(string $property, callable $callback = null): Collection
153
    {
154
        $getterType = get_class($this->offsetGet(0)->$property);
155
156
        if (!is_null($callback)) {
157
            /** @var Collection $collection */
158
            $collection = Collection::{$getterType}();
159
160
            foreach ($this->jsonSerialize() as $item) {
161
                $collection->append(call_user_func($callback, $item->$property));
162
            }
163
164
            return $collection;
165
        } else {
166
            return Collection::{$getterType}(array_map(
167
                function ($item) use ($property) {
168
                    return $item->$property;
169
                },
170
                $this->jsonSerialize()
171
            ));
172
        }
173
    }
174
175
    public function pop(): object
176
    {
177
        return array_pop($this->container);
178
    }
179
180
    public function sum(callable $callback)
181
    {
182
        $sum = 0;
183
184
        foreach ($this as $element) {
185
            $sum += call_user_func($callback, $element);
186
        }
187
188
        return $sum;
189
    }
190
191
    /**
192
     * @param string $name
193
     * @param array  $arguments
194
     *
195
     * @return Collection
196
     */
197
    public static function __callStatic(string $name, array $arguments = [])
198
    {
199
        if (!empty($arguments) && is_array($arguments[0])) {
200
            $arguments = $arguments[0];
201
        }
202
203
        static::validateObject($name);
204
205
        reset($arguments);
206
207
        if (current($arguments) instanceof Collection) {
208
            return new static($name, ...$arguments);
209
        } else {
210
            return new static($name, $arguments);
211
        }
212
    }
213
214
    public function count(): int
215
    {
216
        return count($this->container);
217
    }
218
219
    public function add($item, $index = null): void
220
    {
221
        $this->validate($item);
222
        $this->container[$index ?? $this->count()] = $item;
223
    }
224
225
    protected static function validateObject(string $type): void
226
    {
227
        if (!class_exists($type)) {
228
            throw new Exception\UnprocessedType($type);
229
        }
230
    }
231
}
232