• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

voku / Arrayy / 9348187936

03 Jun 2024 10:03AM UTC coverage: 90.439%. Remained the same
9348187936

Pull #130

github

web-flow
Merge f86904e89 into e88173fba
Pull Request #130: Update shivammathur/setup-php action to v2.30.5

2535 of 2803 relevant lines covered (90.44%)

257.66 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.01
/src/Collection/AbstractCollection.php
1
<?php
2

3
/** @noinspection ClassOverridesFieldOfSuperClassInspection */
4
/** @noinspection PropertyInitializationFlawsInspection */
5
/** @noinspection PhpSuperClassIncompatibleWithInterfaceInspection */
6

7
declare(strict_types=1);
8

9
namespace Arrayy\Collection;
10

11
use Arrayy\Arrayy;
12
use Arrayy\ArrayyIterator;
13
use Arrayy\Type\TypeInterface;
14
use Arrayy\TypeCheck\TypeCheckArray;
15
use Arrayy\TypeCheck\TypeCheckInterface;
16
use Arrayy\TypeCheck\TypeCheckSimple;
17

18
/**
19
 * This class provides a full implementation of `CollectionInterface`, to
20
 * minimize the effort required to implement this interface.
21
 *
22
 * INFO: this collection thingy is inspired by https://github.com/ramsey/collection/
23
 *
24
 * @template   TKey of array-key
25
 * @template   T
26
 * @extends    Arrayy<TKey,T>
27
 * @implements CollectionInterface<TKey,T>
28
 */
29
abstract class AbstractCollection extends Arrayy implements CollectionInterface
30
{
31
    /**
32
     * @var bool
33
     */
34
    protected $checkPropertyTypes = true;
35

36
    /**
37
     * @var bool
38
     */
39
    protected $checkPropertiesMismatch = false;
40

41
    /**
42
     * @var bool
43
     */
44
    protected $checkForMissingPropertiesInConstructor = true;
45

46
    /**
47
     * Constructs a collection object of the specified type, optionally with the
48
     * specified data.
49
     *
50
     * @param mixed  $data
51
     *                                             <p>
52
     *                                             The initial items to store in the collection.
53
     *                                             </p>
54
     * @param string $iteratorClass                optional <p>
55
     *                                             You can overwrite the ArrayyIterator, but mostly you don't
56
     *                                             need this option.
57
     *                                             </p>
58
     * @param bool   $checkPropertiesInConstructor optional <p>
59
     *                                             You need to extend the "Arrayy"-class and you need to set
60
     *                                             the $checkPropertiesMismatchInConstructor class property
61
     *                                             to
62
     *                                             true, otherwise this option didn't not work anyway.
63
     *                                             </p>
64
     *
65
     * @phpstan-param array<TKey,T>|\Arrayy\Arrayy<TKey,T>|\Closure():array<TKey,T>|mixed $data
66
     * @phpstan-param class-string<\Arrayy\ArrayyIterator> $iteratorClass
67
     */
68
    public function __construct(
69
        $data = [],
70
        string $iteratorClass = ArrayyIterator::class,
71
        bool $checkPropertiesInConstructor = true
72
    ) {
73
        $type = $this->getType();
896✔
74

75
        $type = self::convertIntoTypeCheckArray($type);
896✔
76

77
        $this->properties = $type;
896✔
78

79
        // cast into array, if needed
80
        if (
81
            !\is_array($data)
896✔
82
            &&
83
            !($data instanceof \Traversable)
896✔
84
            &&
85
            !($data instanceof \Closure)
896✔
86
        ) {
87
            $data = [$data];
16✔
88
        }
89

90
        parent::__construct(
896✔
91
            $data,
896✔
92
            $iteratorClass,
784✔
93
            $checkPropertiesInConstructor
784✔
94
        );
448✔
95
    }
356✔
96

97
    /**
98
     * Append a (key) + value to the current array.
99
     *
100
     * @param mixed $value
101
     * @param mixed $key
102
     *
103
     * @return $this
104
     *               <p>(Mutable) Return this CollectionInterface object, with the appended values.</p>
105
     *
106
     * @phpstan-param T|static $value
107
     * @phpstan-param TKey|null $key
108
     * @phpstan-return static<TKey,T>
109
     */
110
    public function append($value, $key = null): Arrayy
111
    {
112
        if (
113
            $value instanceof self
56✔
114
            &&
115
            !$value instanceof TypeInterface
56✔
116
        ) {
117
            foreach ($value as $valueTmp) {
8✔
118
                parent::append($valueTmp, $key);
8✔
119
            }
120

121
            return $this;
8✔
122
        }
123

124
        /* @phpstan-ignore-next-line | special? */
125
        $return = parent::append($value, $key);
48✔
126
        $this->array = $return->array;
40✔
127
        $this->generator = null;
40✔
128

129
        return $this;
40✔
130
    }
131

132
    /**
133
     * Assigns a value to the specified offset + check the type.
134
     *
135
     * @param int|string|null $offset
136
     * @param mixed           $value
137
     *
138
     * @return void
139
     *
140
     * @phpstan-param T $value
141
     */
142
    #[\ReturnTypeWillChange]
143
    public function offsetSet($offset, $value)
144
    {
145
        if (
146
            $value instanceof self
32✔
147
            &&
148
            !$value instanceof TypeInterface
32✔
149
        ) {
150
            foreach ($value as $valueTmp) {
×
151
                parent::offsetSet($offset, $valueTmp);
×
152
            }
153

154
            return;
×
155
        }
156

157
        parent::offsetSet($offset, $value);
32✔
158
    }
12✔
159

160
    /**
161
     * Prepend a (key) + value to the current array.
162
     *
163
     * @param mixed $value
164
     * @param mixed $key
165
     *
166
     * @return $this
167
     *               <p>(Mutable) Return this CollectionInterface object, with the prepended value.</p>
168
     *
169
     * @phpstan-param T|static $value
170
     * @phpstan-param TKey|null $key
171
     * @phpstan-return static<TKey,T>
172
     */
173
    public function prepend($value, $key = null): Arrayy
174
    {
175
        if (
176
            $value instanceof self
24✔
177
            &&
178
            !$value instanceof TypeInterface
24✔
179
        ) {
180
            foreach ($value as $valueTmp) {
×
181
                parent::prepend($valueTmp, $key);
×
182
            }
183

184
            return $this;
×
185
        }
186

187
        /* @phpstan-ignore-next-line | special? */
188
        $return = parent::prepend($value, $key);
24✔
189
        $this->array = $return->array;
8✔
190
        $this->generator = null;
8✔
191

192
        return $this;
8✔
193
    }
194

195
    /**
196
     * {@inheritdoc}
197
     */
198
    public function column(string $keyOrPropertyOrMethod): array
199
    {
200
        // init
201
        $temp = [];
8✔
202

203
        foreach ($this->getGenerator() as $item) {
8✔
204
            $temp[] = $this->extractValue($item, $keyOrPropertyOrMethod);
8✔
205
        }
206

207
        return $temp;
8✔
208
    }
209

210
    /**
211
     * @return array
212
     *
213
     * @phpstan-return array<T>
214
     */
215
    public function getCollection(): array
216
    {
217
        return $this->getArray();
56✔
218
    }
219

220
    /**
221
     * The type (FQCN) associated with this collection.
222
     *
223
     * @return string|string[]|TypeCheckArray|TypeCheckInterface[]
224
     *
225
     * @phpstan-return string|string[]|class-string|class-string[]|TypeCheckArray<array-key,TypeCheckInterface>|TypeCheckInterface[]
226
     */
227
    abstract public function getType();
228

229
    /**
230
     * Merge current items and items of given collections into a new one.
231
     *
232
     * @param CollectionInterface|static ...$collections
233
     *                                                   <p>The collections to merge.</p>
234
     *
235
     *@throws \InvalidArgumentException if any of the given collections are not of the same type
236
     *
237
     * @return $this
238
     *
239
     * @phpstan-param CollectionInterface<TKey,T> ...$collections
240
     * @phpstan-return static<TKey,T>
241
     */
242
    public function merge(CollectionInterface ...$collections): self
243
    {
244
        foreach ($collections as $collection) {
8✔
245
            foreach ($collection as $item) {
8✔
246
                $this->append($item);
8✔
247
            }
248
        }
249

250
        return $this;
8✔
251
    }
252

253
    /**
254
     * Creates an CollectionInterface object.
255
     *
256
     * @param mixed  $data
257
     * @param string $iteratorClass
258
     * @param bool   $checkPropertiesInConstructor
259
     *
260
     * @return static
261
     *                <p>(Immutable) Returns an new instance of the CollectionInterface object.</p>
262
     *
263
     * @template TKeyCreate as TKey
264
     * @template TCreate as T
265
     * @phpstan-param array<TKeyCreate,TCreate> $data
266
     * @phpstan-param  class-string<\Arrayy\ArrayyIterator> $iteratorClass
267
     * @phpstan-return static<TKeyCreate,TCreate>
268
     *
269
     * @psalm-mutation-free
270
     */
271
    public static function create(
272
        $data = [],
273
        string $iteratorClass = ArrayyIterator::class,
274
        bool $checkPropertiesInConstructor = true
275
    ) {
276
        return new static(
224✔
277
            $data,
224✔
278
            $iteratorClass,
196✔
279
            $checkPropertiesInConstructor
196✔
280
        );
112✔
281
    }
282

283
    /**
284
     * @param string $json
285
     *
286
     * @return static
287
     *                <p>(Immutable) Returns an new instance of the CollectionInterface object.</p>
288
     *
289
     * @phpstan-return static<int,T>
290
     *
291
     * @psalm-mutation-free
292
     */
293
    public static function createFromJsonMapper(string $json)
294
    {
295
        // init
296
        $return = static::create();
64✔
297

298
        $jsonObject = \json_decode($json, false);
64✔
299

300
        $mapper = new \Arrayy\Mapper\Json();
64✔
301
        $mapper->undefinedPropertyHandler = static function ($object, $key, $jsonValue) use ($return) {
32✔
302
            if ($return->checkForMissingPropertiesInConstructor) {
8✔
303
                throw new \TypeError('Property mismatch - input: ' . \print_r(['key' => $key, 'jsonValue' => $jsonValue], true) . ' for object: ' . \get_class($object));
8✔
304
            }
305
        };
32✔
306

307
        $type = $return->getType();
64✔
308

309
        if (
310
            \is_string($type)
64✔
311
            &&
312
            \class_exists($type)
64✔
313
        ) {
314
            if (\is_array($jsonObject)) {
32✔
315
                foreach ($jsonObject as $jsonObjectSingle) {
16✔
316
                    $collectionData = $mapper->map($jsonObjectSingle, $type);
16✔
317
                    $return->add($collectionData);
16✔
318
                }
319
            } else {
320
                $collectionData = $mapper->map($jsonObject, $type);
16✔
321
                $return->add($collectionData);
24✔
322
            }
323
        } else {
324
            foreach ($jsonObject as $key => $jsonValue) {
32✔
325
                $return->add($jsonValue, $key);
32✔
326
            }
327
        }
328

329
        /** @phpstan-var static<int,T> */
330
        return $return;
40✔
331
    }
332

333
    /**
334
     * Internal mechanic of set method.
335
     *
336
     * @param int|string|null $key
337
     * @param mixed           $value
338
     * @param bool            $checkProperties
339
     *
340
     * @return bool
341
     */
342
    protected function internalSet(
343
        $key,
344
        &$value,
345
        bool $checkProperties = true
346
    ): bool {
347
        if (
348
            $value instanceof self
840✔
349
            &&
350
            !$value instanceof TypeInterface
840✔
351
        ) {
352
            foreach ($value as $valueTmp) {
×
353
                parent::internalSet(
×
354
                    $key,
×
355
                    $valueTmp,
356
                    $checkProperties
357
                );
358
            }
359

360
            return true;
×
361
        }
362

363
        return parent::internalSet(
840✔
364
            $key,
840✔
365
            $value,
735✔
366
            $checkProperties
735✔
367
        );
420✔
368
    }
369

370
    /**
371
     * @param string|string[]|TypeCheckArray|TypeCheckInterface[]|null $type
372
     *
373
     * @return TypeCheckArray
374
     *
375
     * @phpstan-param null|string|string[]|class-string|class-string[]|TypeCheckArray<array-key,TypeCheckInterface>|array<array-key,TypeCheckInterface>|mixed $type
376
     * @phpstan-return TypeCheckArray<array-key,TypeCheckInterface>
377
     */
378
    protected static function convertIntoTypeCheckArray($type): TypeCheckArray
379
    {
380
        $is_array = false;
896✔
381
        if (
382
            \is_scalar($type)
896✔
383
            ||
384
            $is_array = \is_array($type)
896✔
385
        ) {
386
            $type = TypeCheckArray::create(
848✔
387
                [
424✔
388
                    Arrayy::ARRAYY_HELPER_TYPES_FOR_ALL_PROPERTIES => new TypeCheckSimple($is_array ? $type : (string) $type),
848✔
389
                ]
424✔
390
            );
424✔
391
        }
392

393
        return $type;
896✔
394
    }
395
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc