Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
80.67% covered (warning)
80.67%
96 / 119
81.48% covered (warning)
81.48%
22 / 27
CRAP
0.00% covered (danger)
0.00%
0 / 1
Base
80.67% covered (warning)
80.67%
96 / 119
81.48% covered (warning)
81.48%
22 / 27
82.29
0.00% covered (danger)
0.00%
0 / 1
 getFirst
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getLast
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 sortByName
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 sortByContactName
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 sortByCustomKey
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 sortByCustomStringKey
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 __clone
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 hasEntity
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
4
 getEntity
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
4
 addEntity
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 offsetSet
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
4
 addData
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
4
 addList
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 getIds
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 getIdsCsv
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getCsvForProperty
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 getCsvForPropertyList
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
6
 withValueFor
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 withLessData
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 setJsonCompressLevel
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 getAsArray
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 jsonSerialize
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 __toString
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 getResolveLevel
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setResolveLevel
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 withResolveLevel
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 chunk
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2
3/**
4 * @package Zmsdldb
5 * @copyright BerlinOnline Stadtportal GmbH & Co. KG
6 **/
7
8namespace BO\Zmsentities\Collection;
9
10use BO\Zmsentities\Helper\Sorter;
11use BO\Zmsentities\Schema\Entity;
12
13/**
14 * @SuppressWarnings(NumberOfChildren)
15 * @SuppressWarnings(Public)
16 * @SuppressWarnings(Complexity)
17 *
18 * @template T of Entity
19 * @extends \ArrayObject<int|string, T>
20 */
21class Base extends \ArrayObject implements \JsonSerializable
22{
23    /** @var string */
24    public const string ENTITY_CLASS = '';
25
26    /**
27     * @var Int $resolveLevel indicator on data integrity
28     */
29    protected $resolveLevel = null;
30
31    /**
32     * @return T|null
33     */
34    public function getFirst()
35    {
36        $item = $this->getIterator()->current();
37        return $item;
38    }
39
40    /**
41     * @return Entity|false
42     *
43     */
44    public function getLast()
45    {
46        $copy = $this->getArrayCopy();
47        $item = end($copy);
48        return $item;
49    }
50
51    /**
52     * @return static
53     *
54     */
55    public function sortByName()
56    {
57        $this->uasort(function ($a, $b) {
58            return strcmp(
59                Sorter::toSortableString(ucfirst($a->name ?? '')),
60                Sorter::toSortableString(ucfirst($b->name ?? ''))
61            );
62        });
63        return $this;
64    }
65
66    public function sortByContactName(): static
67    {
68        $this->uasort(function ($a, $b) {
69            return strcmp(
70                Sorter::toSortableString(ucfirst($a->contact['name'] ?? '')),
71                Sorter::toSortableString(ucfirst($b->contact['name'] ?? ''))
72            );
73        });
74        return $this;
75    }
76
77    public function sortByCustomKey(string $key): static
78    {
79        $this->uasort(function ($a, $b) use ($key) {
80            return ($a[$key] - $b[$key]);
81        });
82        return $this;
83    }
84
85    public function sortByCustomStringKey($key): static
86    {
87        $this->uasort(function ($a, $b) use ($key) {
88            return strcmp(
89                Sorter::toSortableString(ucfirst($a[$key] ?? '')),
90                Sorter::toSortableString(ucfirst($b[$key] ?? ''))
91            );
92        });
93        return $this;
94    }
95
96    public function __clone()
97    {
98        foreach ($this as $key => $property) {
99            $this[$key] = clone $property;
100        }
101    }
102
103    public function hasEntity($primary): bool
104    {
105        foreach ($this as $entity) {
106            if (isset($entity->{$entity::PRIMARY}) && $primary == $entity->{$entity::PRIMARY}) {
107                return true;
108            }
109        }
110        return false;
111    }
112
113    /**
114     * @return Entity|null
115     *
116     */
117    public function getEntity(string|int $primary)
118    {
119        foreach ($this as $entity) {
120            if (isset($entity->{$entity::PRIMARY}) && $primary == $entity->{$entity::PRIMARY}) {
121                return $entity;
122            }
123        }
124        return null;
125    }
126
127    /**
128     * @param T $entity
129     *
130     */
131    public function addEntity(\BO\Zmsentities\Schema\Entity $entity): static
132    {
133        $this->offsetSet(null, $entity);
134        return $this;
135    }
136
137    #[\Override]
138    public function offsetSet(mixed $index, mixed $value): void
139    {
140        $className = $this::ENTITY_CLASS;
141        if (is_a($value, $className)) {
142            parent::offsetSet($index, $value);
143        } elseif (is_array($value)) {
144            parent::offsetSet($index, new $className($value));
145        } else {
146            $given = is_object($value) ? $value::class : gettype($value);
147            throw new \Exception('Invalid entity ' . $given . ' for collection ' . __CLASS__);
148        }
149    }
150
151    public function addData($mergeData): static
152    {
153        foreach ($mergeData as $item) {
154            if ($item instanceof Entity) {
155                if (null === $item->getResolveLevel()) {
156                    $item->setResolveLevel($this->getResolveLevel());
157                }
158                $this->addEntity($item);
159            } else {
160                $className = $this::ENTITY_CLASS;
161                $entity = new $className($item);
162                $entity->setResolveLevel($this->getResolveLevel());
163                $this->addEntity($entity);
164            }
165        }
166        return $this;
167    }
168
169    public function addList(Base $list): static
170    {
171        foreach ($list as $item) {
172            $this->addEntity($item);
173        }
174        return $this;
175    }
176
177    /**
178     * @return array
179     *
180     */
181    public function getIds()
182    {
183        $list = [];
184        foreach ($this as $entity) {
185            $list[] = $entity->id;
186        }
187        return $list;
188    }
189
190    public function getIdsCsv(): string
191    {
192        return implode(',', $this->getIds());
193    }
194
195    public function getCsvForProperty($propertyName, $csvSeperator = ','): string
196    {
197        $list = [];
198        foreach ($this as $entry) {
199            if ($entry->hasProperty($propertyName)) {
200                $list[] = $entry->getProperty($propertyName);
201            }
202        }
203        return implode($csvSeperator, $list);
204    }
205
206    public function getCsvForPropertyList(array $propertyList, $propertySeperator = '', $csvSeperator = ','): string
207    {
208        $list = [];
209        foreach ($this as $entry) {
210            $propertyConcat = '';
211            foreach ($propertyList as $propertyName) {
212                if ($entry->hasProperty($propertyName)) {
213                    if ($propertyConcat) {
214                        $propertyConcat .= $propertySeperator;
215                    }
216                    $propertyConcat .= $entry->getProperty($propertyName);
217                }
218            }
219            if ($propertyConcat) {
220                $list[] = $propertyConcat;
221            }
222        }
223        return implode($csvSeperator, $list);
224    }
225
226    /**
227     * Change a parameter on all entries
228     *
229     */
230    public function withValueFor($param, $newValue): static
231    {
232        $list = new static();
233        foreach ($this as $entry) {
234            $list[] = $entry->withProperty($param, $newValue);
235        }
236        return $list;
237    }
238
239    /**
240     * Reduce items data of dereferenced entities to a required minimum
241     *
242     * @return static
243     *
244     */
245    public function withLessData(array $keepArray = [])
246    {
247        $list = new static();
248        foreach ($this as $key => $item) {
249            $list[$key] = $item->withLessData($keepArray);
250        }
251        return $list;
252    }
253
254    public function setJsonCompressLevel($jsonCompressLevel): void
255    {
256        foreach ($this as $item) {
257            $item->setJsonCompressLevel($jsonCompressLevel);
258        }
259    }
260
261    /**
262     * @return T[]
263     *
264     */
265    public function getAsArray(): array
266    {
267        $array = [];
268        foreach ($this as $item) {
269            $array[] = $item;
270        }
271
272        return $array;
273    }
274
275    #[\Override]
276    public function jsonSerialize(): mixed
277    {
278        return $this->getArrayCopy();
279    }
280
281    public function __toString()
282    {
283        $list = [];
284        foreach ($this as $item) {
285            $list[] = $item->__toString();
286        }
287        return "[" . implode(',', $list) . "]";
288    }
289
290    /**
291     * @return Int
292     */
293    public function getResolveLevel()
294    {
295        return $this->resolveLevel;
296    }
297
298    /**
299     * @param Int $resolveLevel
300     * @return self
301     */
302    public function setResolveLevel($resolveLevel)
303    {
304        $this->resolveLevel = $resolveLevel;
305        return $this;
306    }
307
308    /**
309     * @param Int $resolveLevel
310     * @return self
311     */
312    public function withResolveLevel($resolveLevel)
313    {
314        $collection = new static();
315        foreach ($this as $entity) {
316            $reduced = $entity->withResolveLevel($resolveLevel);
317            if (null !== $reduced) {
318                $collection[] = $reduced;
319            }
320        }
321        return $collection;
322    }
323
324    /**
325     * @return static[]
326     *
327     */
328    public function chunk($length): array
329    {
330        $chunks = [new static()];
331        $id = 0;
332        foreach ($this as $entry) {
333            if (! isset($chunks[floor($id / $length)])) {
334                $chunks[floor($id / $length)] = new static();
335            }
336
337            $chunks[floor($id / $length)][] = $entry;
338
339            $id++;
340        }
341
342        return $chunks;
343    }
344}