Test Failed
Push — master ( 6eea59...bfd094 )
by Chris
31:05
created

CollectionKernel::insert()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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