Passed
Pull Request — master (#29)
by Roman
01:51
created

Collection::unserialize()   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 1
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 get_object_vars($this);
82
    }
83
84
    public function isCompatible(iterable $collection): bool
85
    {
86
        try {
87
            foreach ($collection as $item) {
88
                $this->validate($item);
89
            }
90
        } catch (Exception\InvalidElement $exception) {
91
            return false;
92
        }
93
94
        return true;
95
    }
96
97
    public function first(): object
98
    {
99
        reset($this->container);
100
101
        return $this->current();
102
    }
103
104
    public function last(): object
105
    {
106
        end($this->container);
107
108
        return $this->current();
109
    }
110
111
    /**
112
     * @param object $item
113
     *
114
     * @throws Exception\InvalidElement
115
     */
116
    public function validate(object $item): void
117
    {
118
        $type = $this->type();
119
120
        if (!$item instanceof $type) {
121
            throw new Exception\InvalidElement($item, $type);
122
        }
123
    }
124
125
    public function chunk(int $size): Collection
126
    {
127
        /** @var Collection $collection */
128
        $collection = new static(Collection::class);
129
        $chunked = array_chunk($this->container, $size);
130
131
        foreach ($chunked as $chunk) {
132
            $collection->append(new Collection($this->type(), $chunk));
133
        }
134
135
        return $collection;
136
    }
137
138
    public function column(\Closure $callback): Collection
139
    {
140
        $type = get_class(call_user_func($callback, $this->current()));
141
        $collection = new Collection($type);
142
        $fetched = [];
143
144
        foreach ($this->container as $item) {
145
            $fetched[] = call_user_func($callback, $item);
146
        }
147
148
        $collection->append(...$fetched);
149
150
        return $collection;
151
    }
152
153
    public function current()
154
    {
155
        return current($this->container);
156
    }
157
158
    public function pop(): object
159
    {
160
        return array_pop($this->container);
161
    }
162
163
    public function sum(\Closure $callback)
164
    {
165
        $sum = 0;
166
167
        foreach ($this as $element) {
168
            $sum += call_user_func($callback, $element);
169
        }
170
171
        return $sum;
172
    }
173
174
    public function count(): int
175
    {
176
        return count($this->container);
177
    }
178
179
    public function add($item, $index = null): void
180
    {
181
        $this->validate($item);
182
        $this->container[$index ?? $this->count()] = $item;
183
    }
184
185
    /**
186
     * @param string $name
187
     * @param array  $arguments
188
     *
189
     * @return Collection
190
     */
191
    public static function __callStatic(string $name, array $arguments = [])
192
    {
193
        if (!empty($arguments) && is_array($arguments[0])) {
194
            $arguments = $arguments[0];
195
        }
196
197
        static::validateObject($name);
198
199
        reset($arguments);
200
201
        if (current($arguments) instanceof Collection) {
202
            return new static($name, ...$arguments);
203
        } else {
204
            return new static($name, $arguments);
205
        }
206
    }
207
208
    protected static function validateObject(string $type): void
209
    {
210
        if (!class_exists($type)) {
211
            throw new Exception\UnprocessedType($type);
212
        }
213
    }
214
}
215