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