Collection   A
last analyzed

Complexity

Total Complexity 27

Size/Duplication

Total Lines 230
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 41
c 1
b 0
f 0
dl 0
loc 230
rs 10
wmc 27

18 Methods

Rating   Name   Duplication   Size   Complexity  
A fromJson() 0 9 2
A offsetUnset() 0 3 1
A set() 0 9 2
A __construct() 0 3 1
A addNew() 0 4 1
A offsetSet() 0 3 1
A getIterator() 0 3 1
A map() 0 9 2
A filter() 0 11 3
A add() 0 11 3
A appendToArray() 0 5 1
A toArray() 0 3 1
A offsetGet() 0 3 2
A get() 0 3 2
A addArray() 0 5 1
A offsetExists() 0 3 1
A toJson() 0 4 1
A count() 0 3 1
1
<?php declare(strict_types=1);
2
3
namespace One;
4
5
/**
6
 * Collection class
7
 *
8
 * @method mixed|null get(string $key)
9
 * @method self set(string $key, mixed $value)
10
 * @method self add(string $key, mixed $value)
11
 * @method self map(\Closure $callback, array $context)
12
 * @method self filter filter(\Closure $callback)
13
 */
14
class Collection implements \ArrayAccess, \IteratorAggregate, \Countable, ToArrayInterface, JsonInterface
15
{
16
    /**
17
     * Properties
18
     * @var array<mixed>
19
     */
20
    protected $props;
21
22
    /**
23
     * constructor
24
     */
25
    public function __construct(array $props = [])
26
    {
27
        $this->props = $props;
28
    }
29
30
    /**
31
     * ArrayAccess Implementations
32
     */
33
34
    /**
35
     * @inheritDoc
36
     */
37
    public function offsetExists($offset)
38
    {
39
        return isset($this->props[$offset]);
40
    }
41
42
    /**
43
     * @inheritDoc
44
     */
45
    public function offsetGet($offset)
46
    {
47
        return isset($this->props[$offset]) ? $this->props[$offset] : null;
48
    }
49
50
    /**
51
     * @inheritDoc
52
     */
53
    public function offsetSet($offset, $value): void
54
    {
55
        $this->props[$offset] = $value;
56
    }
57
58
    /**
59
     * @inheritDoc
60
     */
61
    public function offsetUnset($offset): void
62
    {
63
        unset($this->props[$offset]);
64
    }
65
66
    /**
67
     * IteratorAggregate Implementations
68
     */
69
70
    /**
71
     * @inheritDoc
72
     */
73
    public function getIterator()
74
    {
75
        return new \ArrayIterator($this->props);
76
    }
77
78
    /**
79
     * Countable Implementations
80
     */
81
82
    /**
83
     * @inheritDoc
84
     */
85
    public function count()
86
    {
87
        return count($this->props);
88
    }
89
90
    /**
91
     * ToArrayInterface Implementations
92
     */
93
94
    /**
95
     * @inheritDoc
96
     */
97
    public function toArray(): array
98
    {
99
        return $this->props;
100
    }
101
102
    /**
103
     * Json Implementations
104
     */
105
106
    /**
107
     * @inheritDoc
108
     */
109
    public function toJson(): string
110
    {
111
        return json_encode(
112
            $this->toArray()
113
        );
114
    }
115
116
    /**
117
     * @inheritDoc
118
     */
119
    public static function fromJson(string $stream): JsonInterface
120
    {
121
        $props = json_decode((string) $stream);
122
123
        if (! is_array($props)) {
124
            throw new \InvalidArgumentException('argument must be json formated, and could be decoded.');
125
        }
126
127
        return new self($props);
128
    }
129
130
    /**
131
     * get single value based on key
132
     *
133
     * @return mixed|null value of the requested key
134
     */
135
    public function get(string $key)
136
    {
137
        return isset($this->props[$key]) ? $this->props[$key] : null;
138
    }
139
140
    /**
141
     * set value of certain key on property cannot add new property, use add instead
142
     *
143
     * @param mixed $value
144
     */
145
    public function set(string $key, $value): self
146
    {
147
        if (! isset($this->props[$key])) {
148
            throw new \Exception('Cannot add new property from set. Use add()');
149
        }
150
151
        $this->props[$key] = $value;
152
153
        return $this;
154
    }
155
156
    /**
157
     * add new item to props
158
     *
159
     * @param mixed $value
160
     */
161
    public function add(string $key, $value): self
162
    {
163
        if (! array_key_exists($key, $this->props)) {
164
            return $this->addNew($key, $value);
165
        }
166
167
        if (is_array($this->props[$key])) {
168
            return $this->addArray($key, $value);
169
        }
170
171
        return $this->appendToArray($key, $value);
172
    }
173
174
    /**
175
     * map each props item against the callback and return the resulting object
176
     * IMMUTABLE
177
     *
178
     * @param array|string $context parameter context to be used inside callback
179
     * @return self that already mapped. Return new clone
180
     */
181
    public function map(\Closure $callback, $context = []): self
182
    {
183
        $collection = new static();
184
185
        foreach ($this->props as $key => $value) {
186
            $collection->add($key, $callback($value, $key, $context));
187
        }
188
189
        return $collection;
190
    }
191
192
    /**
193
     * filter the props againt rule on callback
194
     * IMMUTABLE
195
     *
196
     * @return self with filtered properties
197
     */
198
    public function filter(\Closure $callback): self
199
    {
200
        $collection = new static();
201
202
        foreach ($this->props as $key => $value) {
203
            if ($callback($value, $key)) {
204
                $collection->add($key, $value);
205
            }
206
        }
207
208
        return $collection;
209
    }
210
211
    /**
212
     * addNew item on props
213
     *
214
     * @param mixed $value
215
     */
216
    private function addNew(string $key, $value): self
217
    {
218
        $this->props[$key] = $value;
219
        return $this;
220
    }
221
222
    /**
223
     * add new child array
224
     *
225
     * @param mixed $value
226
     */
227
    private function addArray(string $key, $value): self
228
    {
229
        $this->props[$key][] = $value;
230
231
        return $this;
232
    }
233
234
    /**
235
     * appending to already existing array
236
     *
237
     * @param mixed $value
238
     */
239
    private function appendToArray(string $key, $value): self
240
    {
241
        $this->props[$key] = [$this->props[$key], $value];
242
243
        return $this;
244
    }
245
}
246