Passed
Push — version-4 ( 7cacf2...844ef0 )
by Sebastian
02:23
created

MapTrait::getIterator()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
declare(strict_types=1);
3
/*
4
 * Copyright (C) 2022 Sebastian Böttger <[email protected]>
5
 * You may use, distribute and modify this code under the
6
 * terms of the MIT license.
7
 *
8
 * You should have received a copy of the MIT license with
9
 * this file. If not, please visit: https://opensource.org/licenses/mit-license.php
10
 */
11
12
namespace Seboettg\Collection\Map;
13
14
use ReflectionException;
15
use ReflectionFunction;
16
use Seboettg\Collection\Assert\Exception\NotApplicableCallableException;
17
use Seboettg\Collection\Lists\ListInterface;
18
use Seboettg\Collection\NativePhp\ArrayAccessTrait;
19
use Seboettg\Collection\NativePhp\ArrayIteratorTrait;
20
use function Seboettg\Collection\Assert\assertScalar;
21
use function Seboettg\Collection\Assert\assertType;
22
use function Seboettg\Collection\Assert\assertValidCallable;
23
use function Seboettg\Collection\Lists\emptyList;
24
use function Seboettg\Collection\Lists\listOf;
25
26
/**
27
 * @property array $array base array of this data structure
28
 */
29
trait MapTrait
30
{
31
    use ArrayAccessTrait, ArrayIteratorTrait;
32
33
    /**
34
     * @inheritDoc
35
     */
36 1
    public function getEntries(): ListInterface
37
    {
38
        return listOf(...array_map(function (string $key, $value) {
39 1
            return pair($key, $value);
40 1
        }, array_keys($this->array), $this->array));
41
42
    }
0 ignored issues
show
Coding Style introduced by
Function closing brace must go on the next line following the body; found 1 blank lines before brace
Loading history...
43
44
    /**
45
     * @inheritDoc
46
     */
47 3
    public function getKeys(): ListInterface
48
    {
49 3
        return listOf(...array_keys($this->array));
50
    }
51
52
    /**
53
     * @inheritDoc
54
     */
55 2
    public function values(): ListInterface
56
    {
57 2
        return listOf(...array_values($this->array));
58
    }
59
60
    /**
61
     * {@inheritDoc}
62
     */
63 17
    public function count(): int
64
    {
65 17
        return count($this->array);
66
    }
67
68
    /**
69
     * @inheritDoc
70
     */
71 1
    public function size(): int
72
    {
73 1
        return $this->count();
74
    }
75
76
    /**
77
     * @inheritDoc
78
     */
79
    public function clear(): void
80
    {
81
        unset($this->array);
82
        $this->array = [];
83
    }
84
85
    /**
86
     * @inheritDoc
87
     * @param scalar $key
88
     * @return bool
89
     */
90 7
    public function contains($key): bool
91
    {
92 7
        assertScalar($key, "Key must be a scalar value");
93 5
        return array_key_exists($key, $this->array);
94
    }
95
96
    /**
97
     * @inheritDoc
98
     * @param array $array
99
     */
100
    public function setArray(array $array): void
101
    {
102
        $this->array = $array;
103
    }
104
105
    /**
106
     * @inheritDoc
107
     * @param scalar
108
     * @return string
109
     */
110 1
    public function containsKey($key): bool
111
    {
112 1
        return $this->contains($key);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->contains($key) returns the type boolean which is incompatible with the documented return type string.
Loading history...
113
    }
114
115
    /**
116
     * @inheritDoc
117
     * @param mixed $value
118
     * @return bool
119
     */
120
    public function containsValue($value): bool
121
    {
122
        return in_array($value, $this->array, true) !== false;
123
    }
124
125
    /**
126
     * @inheritDoc
127
     * @return bool
128
     */
129 2
    public function isEmpty(): bool
130
    {
131 2
        return $this->count() === 0;
132
    }
133
134
    /**
135
     * @inheritDoc
136
     * @param scalar
137
     * @return mixed
138
     */
139 6
    public function get($key)
140
    {
141 6
        return $this->array[$key] ?? null;
142
    }
143
144
    /**
145
     * @inheritDoc
146
     * @param scalar $key
147
     * @param mixed $value
148
     */
149 39
    public function put($key, $value): void
150
    {
151 39
        assertScalar($key, "Key must be a scalar value");
152 39
        $this->array[$key] = $value;
153 39
    }
154
155
    /**
156
     * @param MapInterface<scalar, mixed> $map
157
     * @return void
158
     */
159 1
    public function putAll(MapInterface $map): void
160
    {
161 1
        foreach ($map as $key => $value) {
162 1
            $this->array[$key] = $value;
163
        }
164 1
    }
165
166
    /**
167
     * @inheritDoc
168
     * @param scalar $key
169
     * @return void
170
     */
171 1
    public function remove($key): void
172
    {
173 1
        unset($this->array[$key]);
174 1
    }
175
176
    /**
177
     * @inheritDoc
178
     * @param callable $predicate
179
     * @return bool
180
     */
181 1
    public function all(callable $predicate): bool
182
    {
183 1
        return $this->count() === $this->filter($predicate)->count();
184
    }
185
186
    /**
187
     * @inheritDoc
188
     * @param callable $predicate
189
     * @return bool
190
     */
191 1
    public function any(callable $predicate): bool
192
    {
193 1
        return $this->filter($predicate)->count() > 0;
194
    }
195
196
    /**
197
     * @inheritDoc
198
     * @param callable|null $predicate
199
     * @return MapInterface
200
     */
201 5
    public function filter(callable $predicate = null): MapInterface
202
    {
203 5
        $map = emptyMap();
204 5
        if ($predicate !== null) {
205
            try {
206 5
                $reflected = new ReflectionFunction($predicate);
207 5
                if (count($reflected->getParameters()) === 1) {
208 3
                    assertValidCallable($predicate, [Pair::class]);
209 3
                    foreach ($this->array as $key => $value) {
210 3
                        if ($predicate(pair($key, $value)) === true) {
211 3
                            $map->put($key, $value);
212
                        }
213
                    }
214
                } else {
215 2
                    if (count($reflected->getParameters()) === 2) {
216 2
                        assertValidCallable($predicate, ["scalar", "mixed"]);
217
                    }
218 5
                    foreach ($this->array as $key => $value) {
219 2
                        if ($predicate($key, $value) === true) {
220 2
                            $map->put($key, $value);
221
                        }
222
                    }
223
                }
224
            } catch (ReflectionException $ex) {
225 5
                throw new NotApplicableCallableException("Invalid callback.");
226
            }
227
        } else {
228
            $map->array = array_filter($this->array, $predicate);
0 ignored issues
show
Bug introduced by
The property array is declared private in anonymous//src/Map/Functions.php$0 and cannot be accessed from this context.
Loading history...
229
        }
230 5
        return $map;
231
    }
232
233
    /**
234
     * @inheritDoc
235
     * @param scalar $key
236
     * @param callable $default
237
     * @return mixed
238
     */
239 2
    public function getOrElse($key, callable $default)
240
    {
241 2
        return $this[$key] ?? $default($this);
242
    }
243
244
    /**
245
     * @inheritDoc
246
     * @param callable $transform
247
     * @return ListInterface
248
     */
249 2
    public function map(callable $transform): ListInterface
250
    {
251 2
        $list = emptyList();
252 2
        foreach ($this->array as $key => $value) {
253 2
            $list->add($transform(pair($key, $value)));
254
        }
255 2
        return $list;
256
    }
257
258
    /**
259
     * @inheritDoc
260
     * @param callable $transform
261
     * @return ListInterface
262
     */
263 1
    public function mapNotNull(callable $transform): ListInterface
264
    {
265 1
        return $this->map($transform)->filter(fn($item) => $item !== null);
266
    }
267
268
    /**
269
     * @inheritDoc
270
     * @param iterable<scalar> $keys
271
     * @param MapInterface
272
     */
273 2
    public function minus(iterable $keys): MapInterface
274
    {
275 2
        $newInstance = emptyMap();
276 2
        foreach ($this->array as $key => $value) {
277 2
            if (!$this->iterableContainsKey($key, $keys)) {
278 2
                $newInstance[$key] = $value;
279
            }
280
        }
281 2
        return $newInstance;
282
    }
283
284 2
    private function iterableContainsKey($key, iterable $keys): bool
285
    {
286 2
        foreach ($keys as $k) {
287 2
            if ($k === $key) {
288 2
                return true;
289
            }
290
        }
291 2
        return false;
292
    }
293
294
    /**
295
     * @inheritDoc
296
     * @param iterable<Pair<scalar, mixed>> $pairs
297
     * @return MapInterface<scalar, mixed>
298
     */
299 2
    public function plus(iterable $pairs): MapInterface
300
    {
301 2
        $map = emptyMap();
302 2
        $map->array = $this->array;
0 ignored issues
show
Bug introduced by
The property array is declared private in anonymous//src/Map/Functions.php$0 and cannot be accessed from this context.
Loading history...
303 2
        if ($pairs instanceof MapInterface) {
304 1
            foreach ($pairs as $key => $value) {
305 1
                $map[$key] = $value;
306
            }
307
        } else {
308 1
            foreach ($pairs as $pair) {
309 1
                assertType($pair, Pair::class,
310 1
                    sprintf(
311 1
                        "Expected object of type %s, object of type %s given",
312 1
                        Pair::class,
313 1
                        gettype($pair) === "object" ? get_class($pair) : gettype($pair)
314
                    )
315
                );
316 1
                $map[$pair->getKey()] = $pair->getValue();
317
            }
318
        }
319 2
        return $map;
320
    }
321
322
    /**
323
     * @inheritDoc
324
     * @param callable $action f(entry: Pair<scalar, mixed>) -> mixed|void
325
     * @return void
326
     */
327 2
    public function forEach(callable $action): void
328
    {
329 2
        foreach ($this->array as $key => $value) {
330 2
            $action(pair($key, $value));
331
        }
332 2
    }
333
334
    /**
335
     * @inheritDoc
336
     * @return ListInterface<Pair<scalar, mixed>>
337
     */
338 2
    public function toList(): ListInterface
339
    {
340 2
        $list = emptyList();
341 2
        foreach ($this->array as $key => $value) {
342 2
            $list->add(pair($key, $value));
343
        }
344 2
        return $list;
345
    }
346
347 1
    public function toMap(): MapInterface
348
    {
349 1
        return mapOf(...$this->toList());
350
    }
351
352
    /**
353
     * {@inheritDoc}
354
     */
355
    public function toArray(): array
356
    {
357
        return $this->array;
358
    }
359
}
360