Passed
Push — collection ( f7b3ae )
by Greg
15:46
created

Arr::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php
2
3
/**
4
 * webtrees: online genealogy
5
 * Copyright (C) 2022 webtrees development team
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
 * GNU General Public License for more details.
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16
 */
17
18
declare(strict_types=1);
19
20
namespace Fisharebest\Webtrees;
21
22
use ArrayAccess;
23
use ArrayIterator;
24
use Closure;
25
use Countable;
26
use IteratorAggregate;
27
use ReturnTypeWillChange;
28
use Traversable;
29
30
use function array_chunk;
31
use function array_filter;
32
use function array_map;
33
use function array_reverse;
34
use function array_unshift;
35
use function count;
36
use function end;
37
use function in_array;
38
use function uasort;
39
40
use const ARRAY_FILTER_USE_BOTH;
41
42
/**
43
 * Fluent interface for PHP arrays
44
 *
45
 * @template TKey of array-key
46
 * @template TValue
47
 *
48
 * @implements ArrayAccess<TKey,TValue>
49
 * @implements IteratorAggregate<TKey,TValue>
50
 */
51
final class Arr implements ArrayAccess, Countable, IteratorAggregate
52
{
53
    /** @var array<TKey,TValue> */
54
    private array $data;
55
56
    /**
57
     * @param array<TKey,TValue> $data
58
     */
59
    public function __construct(array $data = [])
60
    {
61
        $this->data = $data;
62
    }
63
64
    /**
65
     * Fluent constructor.
66
     *
67
     * @param array<TKey,TValue> $data
68
     *
69
     * @return Arr<TKey,TValue>
70
     */
71
    public static function make(array $data): self
72
    {
73
        return new self($data);
74
    }
75
76
    /**
77
     * Implement ArrayAccess.
78
     *
79
     * @link https://php.net/manual/en/arrayaccess.offsetexists.php
80
     *
81
     * @param TKey $offset
0 ignored issues
show
Bug introduced by
The type Fisharebest\Webtrees\TKey was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
82
     *
83
     * @return bool
84
     */
85
    public function offsetExists($offset): bool
86
    {
87
        return isset($this->data[$offset]);
88
    }
89
90
    /**
91
     * Implement ArrayAccess.
92
     *
93
     * @link https://php.net/manual/en/arrayaccess.offsetget.php
94
     *
95
     * @param TKey $offset
96
     *
97
     * @return TValue
0 ignored issues
show
Bug introduced by
The type Fisharebest\Webtrees\TValue was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
98
     */
99
    #[ReturnTypeWillChange]
100
    public function offsetGet($offset)
101
    {
102
        return $this->data[$offset];
103
    }
104
105
    /**
106
     * Implement ArrayAccess.
107
     *
108
     * @link https://php.net/manual/en/arrayaccess.offsetset.php
109
     *
110
     * @param TKey $offset
111
     * @param TValue      $value
112
     *
113
     * @return void
114
     */
115
    public function offsetSet($offset, $value): void
116
    {
117
        $this->data[$offset] = $value;
118
    }
119
120
    /**
121
     * Implement ArrayAccess.
122
     *
123
     * @link https://php.net/manual/en/arrayaccess.offsetunset.php
124
     *
125
     * @param TKey $offset
126
     *
127
     * @return void
128
     */
129
    public function offsetUnset($offset): void
130
    {
131
        unset($this->data[$offset]);
132
    }
133
134
    /**
135
     * Implement Countable.
136
     *
137
     * @link https://php.net/manual/en/countable.count.php
138
     *
139
     * @return int
140
     */
141
    public function count(): int
142
    {
143
        return count($this->data);
144
    }
145
146
    /**
147
     * Implement IteratorAggregate.
148
     *
149
     * @link https://php.net/manual/en/iteratoraggregate.getiterator.php
150
     *
151
     * @return Traversable<TKey,TValue>
152
     */
153
    public function getIterator(): Traversable
154
    {
155
        return new ArrayIterator($this->data);
156
    }
157
158
    /**
159
     * @param TValue $value
160
     *
161
     * @return Arr<TKey,TValue>
162
     */
163
    public function append($value): self
164
    {
165
        $data = $this->data;
166
        $data[] = $value;
167
168
        return new self($data);
169
    }
170
171
    /**
172
     * @param int $size
173
     *
174
     * @return Arr<int,Arr<TKey,TValue>>
175
     */
176
    public function chunk(int $size): self
177
    {
178
        return new self(array_map(static fn (array $a): self => new self($a), array_chunk($this->data, $size, true)));
179
    }
180
181
    /**
182
     * @param null|Closure(TValue):bool $callback
183
     *
184
     * @return Arr<TKey,TValue>
185
     */
186
    public function filter(Closure $callback = null): self
187
    {
188
        $callback??= static fn ($value): bool => $value !== null;
189
190
        return new self(array_filter($this->data, $callback, ARRAY_FILTER_USE_BOTH));
191
    }
192
193
    /**
194
     * @param null|Closure(TValue):bool $callback
195
     *
196
     * @return TValue|null
197
     */
198
    public function first(Closure $callback = null)
199
    {
200
        foreach ($this->data as $value) {
201
            if ($callback === null || $callback($value)) {
202
                return $value;
203
            }
204
        }
205
206
        return null;
207
    }
208
209
    /**
210
     * @return Arr<int,mixed>
211
     */
212
    public function flatten(): self
213
    {
214
        $data = [];
215
216
        foreach ($this->data as $datum) {
217
            if ($datum instanceof self) {
218
                foreach ($datum->flatten() as $value) {
219
                    $data[] = $value;
220
                }
221
            } else {
222
                $data[] = $datum;
223
            }
224
        }
225
226
        return new self($data);
227
    }
228
229
    /**
230
     * @param null|Closure(TValue):bool $callback
231
     *
232
     * @return TValue|null
233
     */
234
    public function last(Closure $callback = null)
235
    {
236
        if ($this->data === []) {
237
            return null;
238
        }
239
240
        if ($callback === null) {
241
            return end($this->data);
242
        }
243
        foreach (array_reverse($this->data, true) as $value) {
244
            if ($callback($value)) {
245
                return $value;
246
            }
247
        }
248
249
        return null;
250
    }
251
252
    /**
253
     * @template TNewValue
254
     *
255
     * @param Closure(TValue):TNewValue $callback
256
     *
257
     * @return Arr<TKey,TNewValue>
258
     */
259
    public function map(Closure $callback): self
260
    {
261
        return new self(array_map($callback, $this->data));
262
    }
263
264
    /**
265
     * @param TValue $value
266
     *
267
     * @return Arr<TKey,TValue>
268
     */
269
    public function prepend($value): self
270
    {
271
        $data = $this->data;
272
        array_unshift($data, $value);
273
274
        return new self($data);
275
    }
276
277
    /**
278
     * @param null|Closure(TValue,TValue):int $callback
279
     *
280
     * @return Arr<TKey,TValue>
281
     */
282
    public function sort(Closure $callback = null): self
283
    {
284
        $callback??= static fn ($x, $y): int => $x <=> $y;
285
286
        $data = $this->data;
287
        uasort($data, $callback);
288
289
        return new self($data);
290
    }
291
292
    /**
293
     * @return Arr<TKey,TValue>
294
     */
295
    public function reverse(): self
296
    {
297
        return new self(array_reverse($this->data, true));
298
    }
299
300
    /**
301
     * @return array<TKey,TValue>
302
     */
303
    public function toArray(): array
304
    {
305
        return $this->data;
306
    }
307
308
    /**
309
     * @param bool $strict
310
     *
311
     * @return Arr<TKey,TValue>
312
     */
313
    public function unique(bool $strict): self
314
    {
315
        $data = [];
316
317
        foreach ($this->data as $key => $value) {
318
            if (!in_array($value, $data, $strict)) {
319
                $data[$key] = $value;
320
            }
321
        }
322
323
        return new self($data);
324
    }
325
}
326