Completed
Push — master ( e240c7...980d95 )
by Lars
01:37
created

AbstractCollection::create()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 3
dl 0
loc 11
ccs 5
cts 5
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   T
26
 * @extends    Arrayy<T>
27
 * @implements CollectionInterface<T>
28
 */
29
abstract class AbstractCollection extends Arrayy implements CollectionInterface
30
{
31
    /**
32
     * @var array
33
     * @psalm-var array<T>
34
     */
35
    protected $array = [];
36
37
    /**
38
     * @var ArrayyRewindableGenerator|null
39
     * @psalm-var \Arrayy\ArrayyRewindableGenerator<T>|null
40
     */
41
    protected $generator;
42
43
    /**
44
     * @var bool
45
     */
46
    protected $checkPropertyTypes = true;
47
48
    /**
49
     * @var bool
50
     */
51
    protected $checkPropertiesMismatch = false;
52
53
    /**
54
     * @var bool
55
     */
56
    protected $checkForMissingPropertiesInConstructor = true;
57
58
    /**
59
     * Constructs a collection object of the specified type, optionally with the
60
     * specified data.
61
     *
62
     * @param mixed  $data
63
     *                                             <p>
64
     *                                             The initial items to store in the collection.
65
     *                                             </p>
66
     * @param string $iteratorClass                optional <p>
67
     *                                             You can overwrite the ArrayyIterator, but mostly you don't
68
     *                                             need this option.
69
     *                                             </p>
70
     * @param bool   $checkPropertiesInConstructor optional <p>
71
     *                                             You need to extend the "Arrayy"-class and you need to set
72
     *                                             the $checkPropertiesMismatchInConstructor class property
73
     *                                             to
74
     *                                             true, otherwise this option didn't not work anyway.
75
     *                                             </p>
76
     *
77
     * @psalm-param array<T> $data
78
     * @psalm-param class-string<\Arrayy\ArrayyIterator> $iteratorClass
79
     */
80 70
    public function __construct(
81
        $data = [],
82
        string $iteratorClass = ArrayyIterator::class,
83
        bool $checkPropertiesInConstructor = true
84
    ) {
85 70
        $type = $this->getType();
86
87 70
        $type = self::convertIntoTypeCheckArray($type);
88
89 70
        $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...
90
91
        // cast into array, if needed
92
        if (
93 70
            !\is_array($data)
94
            &&
95 70
            !($data instanceof \Traversable)
96
            &&
97 70
            !($data instanceof \Closure)
98
        ) {
99 2
            $data = [$data];
100
        }
101
102 70
        parent::__construct(
103 70
            $data,
104 70
            $iteratorClass,
105 70
            $checkPropertiesInConstructor
106
        );
107 58
    }
108
109
    /**
110
     * {@inheritdoc}
111
     */
112 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...
113
    {
114
        if (
115 4
            $value instanceof self
116
            &&
117 4
            !$value instanceof TypeInterface
118
        ) {
119 1
            foreach ($value as $valueTmp) {
120 1
                parent::append($valueTmp, $key);
121
            }
122
123 1
            return $this;
124
        }
125
126 3
        $return = parent::append($value, $key);
127 2
        $this->array = $return->array;
128
129 2
        return $this;
130
    }
131
132
    /**
133
     * {@inheritdoc}
134
     */
135 1
    public function offsetSet($offset, $value)
136
    {
137
        if (
138 1
            $value instanceof self
139
            &&
140 1
            !$value instanceof TypeInterface
141
        ) {
142
            foreach ($value as $valueTmp) {
143
                parent::offsetSet($offset, $valueTmp);
144
            }
145
146
            return;
147
        }
148
149 1
        parent::offsetSet($offset, $value);
150
    }
151
152
    /**
153
     * {@inheritdoc}
154
     */
155 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...
156
    {
157
        if (
158 3
            $value instanceof self
159
            &&
160 3
            !$value instanceof TypeInterface
161
        ) {
162
            foreach ($value as $valueTmp) {
163
                parent::prepend($valueTmp, $key);
164
            }
165
166
            return $this;
167
        }
168
169 3
        $return = parent::prepend($value, $key);
170 1
        $this->array = $return->array;
171
172 1
        return $this;
173
    }
174
175
    /**
176
     * {@inheritdoc}
177
     */
178 1
    public function column(string $keyOrPropertyOrMethod): array
179
    {
180
        // init
181 1
        $temp = [];
182
183 1
        foreach ($this->getGenerator() as $item) {
184 1
            $temp[] = $this->extractValue($item, $keyOrPropertyOrMethod);
185
        }
186
187 1
        return $temp;
188
    }
189
190
    /**
191
     * {@inheritdoc}
192
     */
193 6
    public function getCollection(): array
194
    {
195 6
        return $this->array;
196
    }
197
198
    /**
199
     * {@inheritdoc}
200
     */
201
    abstract public function getType();
202
203
    /**
204
     * Merge current items and items of given collections into a new one.
205
     *
206
     * @param CollectionInterface|static ...$collections The collections to merge.
207
     *
208
     * @throws \InvalidArgumentException if any of the given collections are not of the same type
209
     *
210
     * @return $this
211
     *
212
     * @psalm-param  array<CollectionInterface<T>> ...$collections
213
     * @psalm-return $this<T>
214
     */
215 1
    public function merge(CollectionInterface ...$collections): self
216
    {
217 1
        foreach ($collections as $collection) {
218 1
            if ($collection instanceof Arrayy) {
219 1
                foreach ($collection as $item) {
220 1
                    $this->append($item);
221
                }
222
            }
223
        }
224
225 1
        return $this;
226
    }
227
228
    /**
229
     * Creates an CollectionInterface object.
230
     *
231
     * @param mixed  $data
232
     * @param string $iteratorClass
233
     * @param bool   $checkPropertiesInConstructor
234
     *
235
     * @return static
236
     *                <p>(Immutable) Returns an new instance of the CollectionInterface object.</p>
237
     *
238
     * @psalm-param  array<T> $data
239
     * @psalm-param  class-string<\Arrayy\ArrayyIterator> $iteratorClass
240
     * @psalm-return static<T>
241
     */
242 13
    public static function create(
243
        $data = [],
244
        string $iteratorClass = ArrayyIterator::class,
245
        bool $checkPropertiesInConstructor = true
246
    ) {
247 13
        return new static(
248 13
            $data,
249 13
            $iteratorClass,
250 13
            $checkPropertiesInConstructor
251
        );
252
    }
253
254
    /**
255
     * {@inheritdoc}
256
     */
257 68
    protected function internalSet(
258
        $key,
259
        &$value,
260
        bool $checkProperties = true
261
    ): bool {
262
        if (
263 68
            $value instanceof self
264
            &&
265 68
            !$value instanceof TypeInterface
266
        ) {
267
            foreach ($value as $valueTmp) {
268
                parent::internalSet(
269
                    $key,
270
                    $valueTmp,
271
                    $checkProperties
272
                );
273
            }
274
275
            return true;
276
        }
277
278 68
        return parent::internalSet(
279 68
            $key,
280 68
            $value,
281 68
            $checkProperties
282
        );
283
    }
284
285
    /**
286
     * @param string|string[]|TypeCheckArray|TypeCheckInterface[]|null $type
287
     *
288
     * @return TypeCheckArray
289
     *
290
     * @psalm-param null|string|class-string|string[]|array<class-string>|TypeCheckArray|array<TypeCheckInterface>|mixed $type
291
     */
292 70
    protected static function convertIntoTypeCheckArray($type): TypeCheckArray
293
    {
294 70
        $is_array = false;
295
        if (
296 70
            \is_scalar($type)
297
            ||
298 70
            $is_array = \is_array($type)
299
        ) {
300 70
            $type = TypeCheckArray::create(
301
                [
302 70
                    Arrayy::ARRAYY_HELPER_TYPES_FOR_ALL_PROPERTIES => new TypeCheckSimple($is_array ? $type : (string) $type),
303
                ]
304
            );
305
        }
306
307 70
        return $type;
308
    }
309
}
310