Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
76 / 76
100.00% covered (success)
100.00%
14 / 14
CRAP
100.00% covered (success)
100.00%
1 / 1
DayList
100.00% covered (success)
100.00%
76 / 76
100.00% covered (success)
100.00%
14 / 14
33
100.00% covered (success)
100.00%
1 / 1
 getArrayCopy
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getDay
100.00% covered (success)
100.00%
20 / 20
100.00% covered (success)
100.00%
1 / 1
8
 getDayByDateTime
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getDayByDay
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasDay
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 withAssociatedDays
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
2
 setStatusByType
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 withAddedDayList
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 setSortByDate
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 setSort
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 hasDayWithAppointments
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 getFirstBookableDay
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 withDaysInDateRange
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
4
 withDaysFromPeriod
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace BO\Zmsentities\Collection;
4
5use BO\Zmsentities\Day;
6
7/**
8 * @extends Base<\BO\Zmsentities\Day>
9 */
10class DayList extends Base implements JsonUnindexed
11{
12    public const string ENTITY_CLASS = '\BO\Zmsentities\Day';
13
14    #[\Override]
15    public function getArrayCopy(): array
16    {
17        return parent::getArrayCopy();
18    }
19
20    /**
21     * ATTENTION: Performance critical, keep highly optimized
22     *
23     * @return ($createDay is true ? Day : Day|null)
24     */
25    public function getDay(string $year, string $month, string $dayNumber, bool $createDay = true): Day|null
26    {
27        $dateHash = Day::getCalculatedDayHash($dayNumber, $month, $year);
28        if ($this->offsetExists($dateHash)) {
29            return $this[$dateHash];
30        }
31        foreach ($this as $key => $day) {
32            if (!$day instanceof Day) {
33                $day = new Day($day);
34                $this[$key] = $day;
35            }
36            if ($day->day == $dayNumber && $day->month == $month && $day->year == $year) {
37                unset($this[$key]);
38                $this[$dateHash] = $day;
39                return $day;
40            }
41        }
42        if ($createDay) {
43            $day  = new \BO\Zmsentities\Day([
44                'year' => $year,
45                'month' => $month,
46                'day' => $dayNumber
47            ]);
48            $this[$dateHash] = $day;
49            return $day;
50        }
51        return null;
52    }
53
54    public function getDayByDateTime(\DateTimeInterface $datetime): \BO\Zmsentities\Day
55    {
56        return $this->getDay($datetime->format('Y'), $datetime->format('m'), $datetime->format('d'));
57    }
58
59    public function getDayByDay(\BO\Zmsentities\Day $day): \BO\Zmsentities\Day
60    {
61        return $this->getDay($day->year, $day->month, $day->day);
62    }
63
64
65    public function hasDay(mixed $year, mixed $month, mixed $dayNumber): bool
66    {
67        $day = $this->getDay($year, $month, $dayNumber, false);
68        return ($day === null) ? false : true;
69    }
70
71    public function withAssociatedDays(\DateTimeInterface $currentDate): self
72    {
73        $dayList = new self();
74        $lastDay = $currentDate->format('t');
75        for ($dayNumber = 1; $dayNumber <= $lastDay; $dayNumber++) {
76            $day = str_pad((string) $dayNumber, 2, '0', STR_PAD_LEFT);
77            $entity = $this->getDay($currentDate->format('Y'), $currentDate->format('m'), $day);
78            $dayList->addEntity($entity);
79        }
80        $dayList->sortByCustomKey('day');
81        return $dayList;
82    }
83
84    public function setStatusByType(mixed $slotType, \DateTimeInterface $dateTime): static
85    {
86        foreach ($this as $day) {
87            $day->getWithStatus($slotType, $dateTime);
88        }
89        return $this;
90    }
91
92    public function withAddedDayList(DayList $dayList): self
93    {
94        $merged = new DayList();
95        foreach ($dayList as $day) {
96            // @codeCoverageIgnoreStart
97            if (!$day instanceof Day) {
98                $day = new Day($day);
99            }
100            // @codeCoverageIgnoreEnd
101            $merged->addEntity($day->withAddedDay($this->getDayByDay($day)));
102        }
103        return $merged;
104    }
105
106    public function setSortByDate(): static
107    {
108        $this->uasort(function ($dayA, $dayB) {
109            return (
110                intval($dayA['year'] . $dayA['month'] . $dayA['day']) -
111                intval($dayB['year'] . $dayB['month'] . $dayB['day'])
112            );
113        });
114        return $this;
115    }
116
117    public function setSort(string $property = 'day'): static
118    {
119        $this->uasort(function ($dayA, $dayB) use ($property) {
120            return strnatcmp($dayA[$property], $dayB[$property]);
121        });
122        return $this;
123    }
124
125    public function hasDayWithAppointments(): bool
126    {
127        foreach ($this as $day) {
128            $day = new Day($day);
129            if ($day->hasAppointments()) {
130                return true;
131            }
132        }
133        return false;
134    }
135
136    public function getFirstBookableDay(): mixed
137    {
138        foreach ($this as $day) {
139            $day = new Day($day);
140            if ($day->isBookable()) {
141                return $day->toDateTime();
142            }
143        }
144        return null;
145    }
146
147    public function withDaysInDateRange(\DateTimeInterface $startDate, \DateTimeInterface $endDate): self
148    {
149        $list = new self();
150        $rangeStart = \BO\Zmsentities\Helper\DateTime::create($startDate)->modify('00:00:00');
151        $rangeEnd = \BO\Zmsentities\Helper\DateTime::create($endDate)->modify('23:59:59');
152        foreach ($this as $day) {
153            if (
154                $day->toDateTime() >= $rangeStart &&
155                $day->toDateTime() <= $rangeEnd
156            ) {
157                $list->addEntity($day);
158            }
159        }
160        return $list;
161    }
162
163    public function withDaysFromPeriod(\DateTimeInterface $startDate, \DateTimeInterface $endDate): self
164    {
165        $list = new self();
166        $startDate = \BO\Zmsentities\Helper\DateTime::create($startDate);
167        do {
168            $day = (new Day())->setDateTime($startDate);
169            $list->addEntity($day);
170            $startDate = $startDate->modify('+1 day');
171        } while ($startDate <= $endDate);
172        return $list;
173    }
174}