Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
42 / 42
100.00% covered (success)
100.00%
11 / 11
CRAP
100.00% covered (success)
100.00%
1 / 1
Day
100.00% covered (success)
100.00%
42 / 42
100.00% covered (success)
100.00%
11 / 11
20
100.00% covered (success)
100.00%
1 / 1
 getDefaults
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 __toString
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setDateTime
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 toDateTime
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 hasAppointmentsByType
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 isBookable
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasAppointments
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 getWithStatus
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
6
 withAddedDay
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 getDayHash
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getCalculatedDayHash
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace BO\Zmsentities;
4
5class Day extends Schema\Entity
6{
7    public const string PRIMARY = 'day';
8
9    public const string FULL = 'full';
10
11    public const string BOOKABLE = 'bookable';
12
13    public const string NOTBOOKABLE = 'notBookable';
14
15    public const string RESTRICTED = 'restricted';
16
17    public const string DETAIL = 'detail';
18
19    public static $schema = "day.json";
20
21    /**
22     * @return (Slot|string)[]
23     *
24     */
25    #[\Override]
26    public function getDefaults()
27    {
28        return [
29            'year' => '',
30            'month' => '',
31            'day' => '',
32            'status' => self::NOTBOOKABLE,
33            'freeAppointments' => new Slot(),
34            'allAppointments' => new Slot()
35        ];
36    }
37
38    //@todo freeAppointments could be an array, should be slot entity
39    public function __toString()
40    {
41        $this->freeAppointments = new Slot($this->freeAppointments);
42        return "Day {$this->status}@{$this->year}-{$this->month}-{$this->day} with " . $this->freeAppointments;
43    }
44
45    public function setDateTime(\DateTimeInterface $dateTime): static
46    {
47        $this['year'] = $dateTime->format('Y');
48        $this['month'] = $dateTime->format('m');
49        $this['day'] = $dateTime->format('d');
50        return $this;
51    }
52
53    public function toDateTime()
54    {
55        $date = Helper\DateTime::createFromFormat('Y-m-d', $this['year'] . '-' . $this['month'] . '-' . $this['day']);
56        return Helper\DateTime::create($date);
57    }
58
59    /**
60     * @return bool TRUE or FALSE if one or more appointments, if no appointments for $slotType were defined, than NULL
61     */
62    public function hasAppointmentsByType($slotType)
63    {
64        $freeAppointmentCount = $this->toProperty()->freeAppointments->{$slotType}->get();
65        $allAppointmentCount = $this->toProperty()->allAppointments->{$slotType}->get();
66        if (null !== $allAppointmentCount && $allAppointmentCount <= 0) {
67            return null;
68        }
69        return (0 < $freeAppointmentCount);
70    }
71
72    public function isBookable(): bool
73    {
74        return ($this->status == self::BOOKABLE);
75    }
76
77    public function hasAppointments(): bool
78    {
79        return ($this->status == self::BOOKABLE || $this->status == self::FULL);
80    }
81
82    /**
83     * Check if day is bookable
84     * The return self or status
85     *
86     * @return \ArrayObject or String
87     */
88    public function getWithStatus($slotType, \DateTimeInterface $now)
89    {
90        $hasAppointments = $this->hasAppointmentsByType($slotType);
91        if ($this->status != self::RESTRICTED && $hasAppointments !== null) {
92            $this->status = ($hasAppointments) ? self::BOOKABLE : self::FULL;
93        } elseif (null === $hasAppointments) {
94            $this->status = self::NOTBOOKABLE;
95        }
96        // if dayend < todays time + half an hour, it is restricted
97        if ($this->toDateTime()->getTimestamp() + 86400 <= $now->getTimestamp() + 1800) {
98            $this->status =  self::RESTRICTED;
99        }
100        return $this;
101    }
102
103    public function withAddedDay(Day $day): static
104    {
105        $merged = clone $this;
106        if (!$merged->freeAppointments instanceof Slot) {
107            $merged->freeAppointments = new Slot($merged->freeAppointments);
108        }
109        $merged->freeAppointments = $merged->freeAppointments->withAddedSlot($day->freeAppointments);
110        return $merged;
111    }
112
113    /**
114     * Returns an unique string hash per day optimized for b-trees
115     */
116    public function getDayHash()
117    {
118        return $this::getCalculatedDayHash($this->day, $this->month, $this->year);
119    }
120
121    public static function getCalculatedDayHash($dayNumber, $month, $year): string
122    {
123        $dateHash = str_pad($dayNumber, 2, '0', STR_PAD_LEFT)
124            . "-"
125            . str_pad($month, 2, '0', STR_PAD_LEFT)
126            . "-$year";
127        return $dateHash;
128    }
129}