Completed
Push — master ( e9031f...b67bb6 )
by Roman
07:03 queued 05:06
created

Collection::validateObject()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 2
nc 2
nop 1
dl 0
loc 4
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 array_key_exists($offset, $this->container);
40
    }
41
42
    public function offsetGet($offset)
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()
107
    {
108
        reset($this->container);
109
110
        return $this->container[key($this->container)];
111
    }
112
113
    /**
114
     * @param $item
115
     *
116
     * @throws Exception\InvalidElement
117
     */
118
    public function validate($item): void
119
    {
120
        $type = $this->type();
121
122
        if (!$item instanceof $type) {
123
            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

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