Passed
Push — master ( a4571b...162929 )
by Chris
07:18
created

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