Passed
Push — master ( 60a2b8...a4571b )
by Chris
07:43
created

CollectionKernel::getPropertyValue()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 2
crap 1
1
<?php
2
3
namespace WebTheory\Collection\Kernel;
4
5
use ArrayIterator;
6
use Closure;
7
use IteratorAggregate;
8
use Traversable;
9
use WebTheory\Collection\Contracts\ArrayDriverInterface;
10
use WebTheory\Collection\Contracts\CollectionComparatorInterface;
11
use WebTheory\Collection\Contracts\CollectionKernelInterface;
12
use WebTheory\Collection\Contracts\CollectionQueryInterface;
13
use WebTheory\Collection\Contracts\CollectionSorterInterface;
14
use WebTheory\Collection\Contracts\JsonSerializerInterface;
15
use WebTheory\Collection\Contracts\LoopInterface;
16
use WebTheory\Collection\Contracts\OperationProviderInterface;
17
use WebTheory\Collection\Contracts\PropertyResolverInterface;
18
use WebTheory\Collection\Enum\Order;
19
use WebTheory\Collection\Iteration\ForeachLoop;
20
use WebTheory\Collection\Json\BasicJsonSerializer;
21
use WebTheory\Collection\Kernel\Factory\CollectionKernelSubsystemFactory;
22
use WebTheory\Collection\Query\BasicQuery;
23
use WebTheory\Collection\Query\Operation\Operations;
24
use WebTheory\Collection\Sorting\MapBasedSorter;
25
use WebTheory\Collection\Sorting\PropertyBasedSorter;
26
27
class CollectionKernel implements CollectionKernelInterface, IteratorAggregate
28
{
29
    /**
30
     * Array of objects to be operated on.
31
     *
32
     * @var array<int,object>|array<string,object>
33
     */
34
    protected array $items = [];
35
36
    /**
37
     * Function to create a new instance of the interfacing collection.
38
     */
39
    protected Closure $generator;
40
41
    protected ArrayDriverInterface $driver;
42
43
    protected PropertyResolverInterface $propertyResolver;
44
45
    protected CollectionComparatorInterface $aggregateComparator;
46
47
    protected OperationProviderInterface $operationProvider;
48
49
    protected JsonSerializerInterface $jsonSerializer;
50
51 216
    public function __construct(
52
        array $items,
53
        Closure $generator,
54
        ?string $identifier = null,
55
        array $accessors = [],
56
        ?bool $mapToIdentifier = false,
57
        ?JsonSerializerInterface $jsonSerializer = null,
58
        ?OperationProviderInterface $operations = null
59
    ) {
60 216
        $this->generator = $generator;
61
62 216
        $this->jsonSerializer = $jsonSerializer ?? new BasicJsonSerializer();
63 216
        $this->operationProvider = $operations ?? new Operations();
64
65 216
        $subsystems = new CollectionKernelSubsystemFactory(
66
            $identifier,
67
            $accessors,
68
            $mapToIdentifier
0 ignored issues
show
Bug introduced by
It seems like $mapToIdentifier can also be of type null; however, parameter $mapToIdentifier of WebTheory\Collection\Ker...mFactory::__construct() does only seem to accept boolean, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

68
            /** @scrutinizer ignore-type */ $mapToIdentifier
Loading history...
69
        );
70
71 216
        $this->driver = $subsystems->getArrayDriver();
72 216
        $this->propertyResolver = $subsystems->getPropertyResolver();
73 216
        $this->aggregateComparator = $subsystems->getCollectionComparator();
74
75 216
        $this->collect(...$items);
76
    }
77
78 3
    public function __serialize(): array
79
    {
80 3
        return $this->toArray();
81
    }
82
83 216
    public function collect(object ...$items): void
84
    {
85 216
        array_map([$this, 'add'], $items);
86
    }
87
88 216
    public function add(object $item): bool
89
    {
90 216
        return $this->driver->insert($this->items, $item);
91
    }
92
93 9
    public function remove($item): bool
94
    {
95 9
        return $this->driver->remove($this->items, $item);
96
    }
97
98 18
    public function contains($item): bool
99
    {
100 18
        return $this->driver->contains($this->items, $item);
101
    }
102
103 3
    public function first(): object
104
    {
105 3
        return reset($this->items);
106
    }
107
108 3
    public function last(): object
109
    {
110 3
        $last = end($this->items);
111
112 3
        reset($this->items);
113
114 3
        return $last;
115
    }
116
117 6
    public function hasItems(): bool
118
    {
119 6
        return !empty($this->items);
120
    }
121
122
    public function hasWhere(string $property, string $operator, $value): bool
123
    {
124
        return !empty($this->getItemsWhere($property, $operator, $value));
125
    }
126
127 3
    public function firstWhere(string $property, string $operator, $value): ?object
128
    {
129 3
        $items = $this->getItemsWhere($property, $operator, $value);
130
131 3
        return reset($items) ?: null;
132
    }
133
134 30
    public function query(CollectionQueryInterface $query): object
135
    {
136 30
        return $this->spawnFrom(...$this->performQuery($query));
137
    }
138
139 18
    public function where(string $property, string $operator, $value): object
140
    {
141 18
        return $this->query($this->getBasicQuery($property, $operator, $value));
142
    }
143
144 12
    public function filter(callable $callback): object
145
    {
146 12
        return $this->spawnFrom(
147 12
            ...array_values(array_filter($this->items, $callback))
148
        );
149
    }
150
151 6
    public function column(string $property): array
152
    {
153 6
        return $this->map(
154 6
            fn ($item) => $this->getPropertyValue($item, $property)
155
        );
156
    }
157
158 6
    public function matches(array $collection): bool
159
    {
160 6
        return $this->aggregateComparator->matches($this->items, $collection);
161
    }
162
163 12
    public function diff(array $collection): object
164
    {
165 12
        return $this->spawnFrom(
166 12
            ...$this->aggregateComparator->diff($this->items, $collection)
167
        );
168
    }
169
170 15
    public function contrast(array $collection): object
171
    {
172 15
        return $this->spawnFrom(
173 15
            ...$this->aggregateComparator->contrast($this->items, $collection)
174
        );
175
    }
176
177 15
    public function intersect(array $collection): object
178
    {
179 15
        return $this->spawnFrom(
180 15
            ...$this->aggregateComparator->intersect($this->items, $collection)
181
        );
182
    }
183
184 3
    public function merge(array ...$collections): object
185
    {
186 3
        return $this->spawnFrom(
187 3
            ...array_merge(array_values($this->items), ...$collections)
188
        );
189
    }
190
191 42
    public function sortWith(CollectionSorterInterface $sorter, string $order = Order::Asc): object
192
    {
193 42
        return $this->spawnFrom(...$sorter->sort($this->items, $order));
194
    }
195
196 21
    public function sortBy(string $property, string $order = Order::Asc): object
197
    {
198 21
        return $this->sortWith(
199 21
            new PropertyBasedSorter($this->propertyResolver, $property),
200
            $order
201
        );
202
    }
203
204 21
    public function sortMapped(array $map, string $property, string $order = Order::Asc): object
205
    {
206 21
        return $this->sortWith(
207 21
            new MapBasedSorter($this->propertyResolver, $property, $map),
208
            $order
209
        );
210
    }
211
212
    public function sortCustom(callable $callback): object
213
    {
214
        $clone = clone $this;
215
216
        usort($clone->items, $callback);
217
218
        return $this->spawnWith($clone);
219
    }
220
221 9
    public function map(callable $callback): array
222
    {
223 9
        return array_map($callback, $this->items);
224
    }
225
226 3
    public function walk(callable $callback): void
227
    {
228 3
        array_walk($this->items, $callback);
229
    }
230
231 3
    public function loop(LoopInterface $loop, callable $callback): void
232
    {
233 3
        $loop->iterate($this->items, $callback);
234
    }
235
236 3
    public function foreach(callable $callback): void
237
    {
238 3
        $this->loop(new ForeachLoop(), $callback);
239
    }
240
241
    public function values(): array
242
    {
243
        return array_values($this->items);
244
    }
245
246 150
    public function toArray(): array
247
    {
248 150
        return $this->items;
249
    }
250
251 3
    public function toJson(): string
252
    {
253 3
        return $this->jsonSerializer->serialize($this->items);
254
    }
255
256 3
    public function count(): int
257
    {
258 3
        return count($this->items);
259
    }
260
261 3
    public function jsonSerialize(): array
262
    {
263 3
        return $this->items;
264
    }
265
266 3
    public function getIterator(): Traversable
267
    {
268 3
        return new ArrayIterator($this->items);
269
    }
270
271 21
    protected function getBasicQuery(string $property, string $operator, $value): CollectionQueryInterface
272
    {
273 21
        return new BasicQuery(
274 21
            $this->propertyResolver,
275
            $property,
276
            $operator,
277
            $value,
278 21
            $this->operationProvider
279
        );
280
    }
281
282 33
    protected function performQuery(CollectionQueryInterface $query): array
283
    {
284 33
        return $query->query($this->items);
285
    }
286
287 6
    protected function getPropertyValue(object $item, string $property)
288
    {
289 6
        return $this->propertyResolver->resolveProperty($item, $property);
290
    }
291
292 3
    protected function getItemsWhere(string $property, string $operator, $value): array
293
    {
294 3
        return $this->performQuery(
295 3
            $this->getBasicQuery($property, $operator, $value)
296
        );
297
    }
298
299 123
    protected function spawnWith(self $clone): object
300
    {
301 123
        return ($this->generator)($clone);
302
    }
303
304 123
    protected function spawnFrom(object ...$items): object
305
    {
306 123
        $clone = clone $this;
307
308 123
        $clone->items = [];
309 123
        $clone->collect(...$items);
310
311 123
        return $this->spawnWith($clone);
312
    }
313
}
314