Completed
Push — master ( d91a6c...c4c656 )
by Lars
01:35
created

AbstractCollection::extractValue()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 7.3471

Importance

Changes 0
Metric Value
cc 5
nc 5
nop 2
dl 0
loc 22
ccs 6
cts 11
cp 0.5455
crap 7.3471
rs 9.2568
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
     * {@inheritdoc}
230
     */
231 68
    protected function internalSet(
232
        $key,
233
        &$value,
234
        bool $checkProperties = true
235
    ): bool {
236
        if (
237 68
            $value instanceof self
238
            &&
239 68
            !$value instanceof TypeInterface
240
        ) {
241
            foreach ($value as $valueTmp) {
242
                parent::internalSet(
243
                    $key,
244
                    $valueTmp,
245
                    $checkProperties
246
                );
247
            }
248
249
            return true;
250
        }
251
252 68
        return parent::internalSet(
253 68
            $key,
254 68
            $value,
255 68
            $checkProperties
256
        );
257
    }
258
259
    /**
260
     * @param string|string[]|TypeCheckArray|TypeCheckInterface[]|null $type
261
     *
262
     * @return TypeCheckArray
263
     *
264
     * @psalm-param null|string|class-string|string[]|array<class-string>|TypeCheckArray|array<TypeCheckInterface>|mixed $type
265
     */
266 70
    protected static function convertIntoTypeCheckArray($type): TypeCheckArray
267
    {
268 70
        $is_array = false;
269
        if (
270 70
            \is_scalar($type)
271
            ||
272 70
            $is_array = \is_array($type)
273
        ) {
274 70
            $type = TypeCheckArray::create(
275
                [
276 70
                    Arrayy::ARRAYY_HELPER_TYPES_FOR_ALL_PROPERTIES => new TypeCheckSimple($is_array ? $type : (string) $type),
277
                ]
278
            );
279
        }
280
281 70
        return $type;
282
    }
283
}
284