Completed
Push — master ( 51e589...982789 )
by Lars
17:41 queued 16:08
created

AbstractCollection::create()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 3
dl 0
loc 11
ccs 3
cts 3
cp 1
crap 1
rs 9.9
c 0
b 0
f 0
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\ArrayyRewindableGenerator;
14
use Arrayy\Type\TypeInterface;
15
use Arrayy\TypeCheck\TypeCheckArray;
16
use Arrayy\TypeCheck\TypeCheckInterface;
17
use Arrayy\TypeCheck\TypeCheckSimple;
18
19
/**
20
 * This class provides a full implementation of `CollectionInterface`, to
21
 * minimize the effort required to implement this interface.
22
 *
23
 * INFO: this collection thingy is inspired by https://github.com/ramsey/collection/
24
 *
25
 * @template   TKey of array-key
26
 * @template   T
27
 * @extends    Arrayy<TKey,T>
28
 * @implements CollectionInterface<TKey,T>
29
 */
30
abstract class AbstractCollection extends Arrayy implements CollectionInterface
31
{
32
    /**
33
     * @var array
34
     * @psalm-var array<T>
35
     */
36
    protected $array = [];
37
38
    /**
39
     * @var ArrayyRewindableGenerator|null
40
     * @psalm-var \Arrayy\ArrayyRewindableGenerator<TKey,T>|null
41
     */
42
    protected $generator;
43
44
    /**
45
     * @var bool
46
     */
47
    protected $checkPropertyTypes = true;
48
49
    /**
50
     * @var bool
51
     */
52
    protected $checkPropertiesMismatch = false;
53
54
    /**
55
     * @var bool
56
     */
57
    protected $checkForMissingPropertiesInConstructor = true;
58
59
    /**
60
     * Constructs a collection object of the specified type, optionally with the
61
     * specified data.
62
     *
63
     * @param mixed  $data
64
     *                                             <p>
65
     *                                             The initial items to store in the collection.
66
     *                                             </p>
67
     * @param string $iteratorClass                optional <p>
68
     *                                             You can overwrite the ArrayyIterator, but mostly you don't
69
     *                                             need this option.
70
     *                                             </p>
71
     * @param bool   $checkPropertiesInConstructor optional <p>
72
     *                                             You need to extend the "Arrayy"-class and you need to set
73
     *                                             the $checkPropertiesMismatchInConstructor class property
74
     *                                             to
75
     *                                             true, otherwise this option didn't not work anyway.
76
     *                                             </p>
77
     *
78
     * @psalm-param array<TKey,T>|\Arrayy\Arrayy<TKey,T>|\Closure():array<TKey,T>|mixed $data
79
     * @psalm-param class-string<\Arrayy\ArrayyIterator> $iteratorClass
80
     */
81 77
    public function __construct(
82
        $data = [],
83
        string $iteratorClass = ArrayyIterator::class,
84
        bool $checkPropertiesInConstructor = true
85
    ) {
86 77
        $type = $this->getType();
87
88 77
        $type = self::convertIntoTypeCheckArray($type);
89
90 77
        $this->properties = $type;
0 ignored issues
show
Documentation Bug introduced by
It seems like $type of type object<Arrayy\TypeCheck\TypeCheckArray> is incompatible with the declared type array of property $properties.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
91
92
        // cast into array, if needed
93
        if (
94 77
            !\is_array($data)
95
            &&
96 77
            !($data instanceof \Traversable)
97
            &&
98 77
            !($data instanceof \Closure)
99
        ) {
100 1
            $data = [$data];
101
        }
102
103 77
        parent::__construct(
104 77
            $data,
105
            $iteratorClass,
106
            $checkPropertiesInConstructor
107
        );
108 63
    }
109
110
    /**
111
     * Append a (key) + value to the current array.
112
     *
113
     * @param mixed $value
114
     * @param mixed $key
115
     *
116
     * @return $this
117
     *               <p>(Mutable) Return this CollectionInterface object, with the appended values.</p>
118
     *
119
     * @psalm-param T|array<TKey,T>|static<TKey,T> $value
120
     * @psalm-param TKey|null $key
121
     * @psalm-return static<TKey,T>
122
     */
123 4 View Code Duplication
    public function append($value, $key = null): Arrayy
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
124
    {
125
        if (
126 4
            $value instanceof self
127
            &&
128 4
            !$value instanceof TypeInterface
129
        ) {
130 1
            foreach ($value as $valueTmp) {
131 1
                parent::append($valueTmp, $key);
132
            }
133
134 1
            return $this;
135
        }
136
137 3
        $return = parent::append($value, $key);
138 2
        $this->array = $return->array;
139
140 2
        return $this;
141
    }
142
143
    /**
144
     * {@inheritdoc}
145
     */
146 1
    public function offsetSet($offset, $value)
147
    {
148
        if (
149 1
            $value instanceof self
150
            &&
151 1
            !$value instanceof TypeInterface
152
        ) {
153
            foreach ($value as $valueTmp) {
154
                parent::offsetSet($offset, $valueTmp);
155
            }
156
157
            return;
158
        }
159
160 1
        parent::offsetSet($offset, $value);
161
    }
162
163
    /**
164
     * Prepend a (key) + value to the current array.
165
     *
166
     * @param mixed $value
167
     * @param mixed $key
168
     *
169
     * @return $this
170
     *               <p>(Mutable) Return this CollectionInterface object, with the prepended value.</p>
171
     *
172
     * @psalm-param T|array<TKey,T>|static<TKey,T> $value
173
     * @psalm-param TKey|null $key
174
     * @psalm-return static<TKey,T>
175
     */
176 3 View Code Duplication
    public function prepend($value, $key = null): Arrayy
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
177
    {
178
        if (
179 3
            $value instanceof self
180
            &&
181 3
            !$value instanceof TypeInterface
182
        ) {
183
            foreach ($value as $valueTmp) {
184
                parent::prepend($valueTmp, $key);
185
            }
186
187
            return $this;
188
        }
189
190 3
        $return = parent::prepend($value, $key);
191 1
        $this->array = $return->array;
192
193 1
        return $this;
194
    }
195
196
    /**
197
     * {@inheritdoc}
198
     */
199 1
    public function column(string $keyOrPropertyOrMethod): array
200
    {
201
        // init
202 1
        $temp = [];
203
204 1
        foreach ($this->getGenerator() as $item) {
205 1
            $temp[] = $this->extractValue($item, $keyOrPropertyOrMethod);
206
        }
207
208 1
        return $temp;
209
    }
210
211
    /**
212
     * {@inheritdoc}
213
     */
214 6
    public function getCollection(): array
215
    {
216 6
        return $this->array;
217
    }
218
219
    /**
220
     * {@inheritdoc}
221
     */
222
    abstract public function getType();
223
224
    /**
225
     * Merge current items and items of given collections into a new one.
226
     *
227
     * @param CollectionInterface|static ...$collections
228
     *                                                   <p>The collections to merge.</p>
229
     *
230
     *@throws \InvalidArgumentException if any of the given collections are not of the same type
231
     *
232
     * @return $this
233
     *
234
     * @psalm-param CollectionInterface<TKey,T> ...$collections
235
     * @psalm-return static<TKey,T>
236
     */
237 1
    public function merge(CollectionInterface ...$collections): self
238
    {
239 1
        foreach ($collections as $collection) {
240 1
            foreach ($collection as $item) {
241 1
                $this->append($item);
242
            }
243
        }
244
245 1
        return $this;
246
    }
247
248
    /**
249
     * Creates an CollectionInterface object.
250
     *
251
     * @param mixed  $data
252
     * @param string $iteratorClass
253
     * @param bool   $checkPropertiesInConstructor
254
     *
255
     * @return static
256
     *                <p>(Immutable) Returns an new instance of the CollectionInterface object.</p>
257
     *
258
     * @template     TKeyCreate as int|string
259
     * @template     TCreate
260
     * @psalm-param  array<TKeyCreate,TCreate> $data
261
     * @psalm-param  class-string<\Arrayy\ArrayyIterator> $iteratorClass
262
     * @psalm-return static<TKeyCreate,TCreate>
263
     * @psalm-mutation-free
264
     */
265 16
    public static function create(
266
        $data = [],
267
        string $iteratorClass = ArrayyIterator::class,
268
        bool $checkPropertiesInConstructor = true
269
    ) {
270 16
        return new static(
271 16
            $data,
272
            $iteratorClass,
273
            $checkPropertiesInConstructor
274
        );
275
    }
276
277
    /**
278
     * Internal mechanic of set method.
279
     *
280
     * @param int|string|null $key
281
     * @param mixed           $value
282
     * @param bool            $checkProperties
283
     *
284
     * @return bool
285
     */
286 75
    protected function internalSet(
287
        $key,
288
        &$value,
289
        bool $checkProperties = true
290
    ): bool {
291
        if (
292 75
            $value instanceof self
293
            &&
294 75
            !$value instanceof TypeInterface
295
        ) {
296
            foreach ($value as $valueTmp) {
297
                parent::internalSet(
298
                    $key,
299
                    $valueTmp,
300
                    $checkProperties
301
                );
302
            }
303
304
            return true;
305
        }
306
307 75
        return parent::internalSet(
308 75
            $key,
309
            $value,
310
            $checkProperties
311
        );
312
    }
313
314
    /**
315
     * @param string|string[]|TypeCheckArray|TypeCheckInterface[]|null $type
316
     *
317
     * @return TypeCheckArray
318
     *
319
     * @psalm-param null|string|string[]|class-string|class-string[]|TypeCheckArray<array-key,TypeCheckInterface>|array<array-key,TypeCheckInterface>|mixed $type
320
     * @psalm-return TypeCheckArray<array-key,TypeCheckInterface>
321
     */
322 77
    protected static function convertIntoTypeCheckArray($type): TypeCheckArray
323
    {
324 77
        $is_array = false;
325
        if (
326 77
            \is_scalar($type)
327
            ||
328 77
            $is_array = \is_array($type)
329
        ) {
330 77
            $type = TypeCheckArray::create(
331
                [
332 77
                    Arrayy::ARRAYY_HELPER_TYPES_FOR_ALL_PROPERTIES => new TypeCheckSimple($is_array ? $type : (string) $type),
333
                ]
334
            );
335
        }
336
337 77
        return $type;
338
    }
339
}
340