Completed
Pull Request — master (#298)
by
unknown
16:59
created

CalendarConverter::formatDateTimeAsCdbTime()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 9
nc 5
nop 2
1
<?php
2
3
namespace CultuurNet\UDB3\Calendar;
4
5
use CultureFeed_Cdb_Data_Calendar_OpeningTime;
6
use CultureFeed_Cdb_Data_Calendar_Period;
7
use CultureFeed_Cdb_Data_Calendar_PeriodList;
8
use CultureFeed_Cdb_Data_Calendar_Permanent;
9
use CultureFeed_Cdb_Data_Calendar_SchemeDay;
10
use CultureFeed_Cdb_Data_Calendar_Timestamp;
11
use CultureFeed_Cdb_Data_Calendar_TimestampList;
12
use CultureFeed_Cdb_Data_Calendar_Weekscheme;
13
use CultuurNet\UDB3\CalendarInterface;
14
use CultuurNet\UDB3\CalendarType;
15
use DateTimeInterface;
16
use InvalidArgumentException;
17
use League\Period\Period;
18
19
class CalendarConverter implements CalendarConverterInterface
20
{
21
    /**
22
     * @inheritdoc
23
     */
24
    public function toCdbCalendar(CalendarInterface $calendar)
25
    {
26
        $weekScheme = $this->getWeekScheme($calendar);
27
        $calendarType = (string) $calendar->getType();
28
29
        switch ($calendarType) {
30
            case CalendarType::MULTIPLE:
31
                $cdbCalendar = new CultureFeed_Cdb_Data_Calendar_TimestampList();
32
                $index = 1;
33
                foreach ($calendar->getTimestamps() as $timestamp) {
34
                    ($this->countTimestamps($cdbCalendar) - $this->countTimestamps($this->timestampCalendar(
35
                        $timestamp->getStartDate(),
36
                        $timestamp->getEndDate(),
37
                        $cdbCalendar,
38
                        $index
39
                    ))) === -1 ?: $index++ ;
40
                }
41
                break;
42
            case CalendarType::SINGLE:
43
                $cdbCalendar = $this->timestampCalendar(
44
                    $calendar->getStartDate(),
45
                    $calendar->getEndDate(),
46
                    new CultureFeed_Cdb_Data_Calendar_TimestampList(),
47
                    1
48
                );
49
                break;
50
            case CalendarType::PERIODIC:
51
                $cdbCalendar = new CultureFeed_Cdb_Data_Calendar_PeriodList();
52
                $startDate = $calendar->getStartDate()->format('Y-m-d');
53
                $endDate = $calendar->getEndDate()->format('Y-m-d');
54
55
                $period = new CultureFeed_Cdb_Data_Calendar_Period($startDate, $endDate);
56
                if (!empty($weekScheme) && !empty($weekScheme->getDays())) {
57
                    $period->setWeekScheme($weekScheme);
58
                }
59
                $cdbCalendar->add($period);
60
                break;
61
            case CalendarType::PERMANENT:
62
                $cdbCalendar = new CultureFeed_Cdb_Data_Calendar_Permanent();
63
                if (!empty($weekScheme)) {
64
                    $cdbCalendar->setWeekScheme($weekScheme);
65
                }
66
                break;
67
            default:
68
                $cdbCalendar = new CultureFeed_Cdb_Data_Calendar_Permanent();
69
        }
70
71
        return $cdbCalendar;
72
    }
73
74
    /**
75
     * @param CultureFeed_Cdb_Data_Calendar_TimestampList $timestamps
76
     * @return int
77
     */
78
    private function countTimestamps(CultureFeed_Cdb_Data_Calendar_TimestampList $timestamps)
79
    {
80
        $numberOfTimestamps =  iterator_count($timestamps);
81
        $timestamps->rewind();
82
83
        return $numberOfTimestamps;
84
    }
85
86
    /**
87
     * @param \CultuurNet\UDB3\CalendarInterface $itemCalendar
88
     * @return CultureFeed_Cdb_Data_Calendar_Weekscheme|null
89
     * @throws \Exception
90
     */
91
    private function getWeekScheme(CalendarInterface $itemCalendar)
92
    {
93
        // Store opening hours.
94
        $openingHours = $itemCalendar->getOpeningHours();
95
        $weekScheme = null;
96
97
        if (!empty($openingHours)) {
98
            $weekScheme = new CultureFeed_Cdb_Data_Calendar_Weekscheme();
99
100
            // Multiple opening times can happen on same day. Store them in array.
101
            $openingTimesPerDay = array(
102
                'monday' => array(),
103
                'tuesday' => array(),
104
                'wednesday' => array(),
105
                'thursday' => array(),
106
                'friday' => array(),
107
                'saturday' => array(),
108
                'sunday' => array(),
109
            );
110
111
            foreach ($openingHours as $openingHour) {
112
                // In CDB2 every day needs to be a seperate entry.
113
                if (is_array($openingHour)) {
114
                    $openingHour = (object) $openingHour;
115
                }
116
                foreach ($openingHour->getDayOfWeekCollection()->getDaysOfWeek() as $day) {
117
                    $openingTimesPerDay[$day->toNative()][] = new CultureFeed_Cdb_Data_Calendar_OpeningTime(
118
                        $openingHour->getOpens()->toNativeString() . ':00',
119
                        $openingHour->getCloses()->toNativeString() . ':00'
120
                    );
121
                }
122
            }
123
124
            // Create the opening times correctly
125
            foreach ($openingTimesPerDay as $day => $openingTimes) {
126
                // Empty == closed.
127
                if (empty($openingTimes)) {
128
                    $openingInfo = new CultureFeed_Cdb_Data_Calendar_SchemeDay(
129
                        $day,
130
                        CultureFeed_Cdb_Data_Calendar_SchemeDay::SCHEMEDAY_OPEN_TYPE_CLOSED
131
                    );
132
                } else {
133
                    // Add all opening times.
134
                    $openingInfo = new CultureFeed_Cdb_Data_Calendar_SchemeDay(
135
                        $day,
136
                        CultureFeed_Cdb_Data_Calendar_SchemeDay::SCHEMEDAY_OPEN_TYPE_OPEN
137
                    );
138
                    foreach ($openingTimes as $openingTime) {
139
                        $openingInfo->addOpeningTime($openingTime);
140
                    }
141
                }
142
                $weekScheme->setDay($day, $openingInfo);
143
            }
144
        }
145
146
        return $weekScheme;
147
    }
148
149
    /**
150
     * @param DateTimeInterface $startDate
151
     * @param DateTimeInterface $endDate
152
     * @param CultureFeed_Cdb_Data_Calendar_TimestampList $calendar
153
     * @param Integer|null $index
154
     *
155
     * @return CultureFeed_Cdb_Data_Calendar_TimestampList
156
     */
157
    private function timestampCalendar(
158
        DateTimeInterface $startDate,
159
        DateTimeInterface $endDate,
160
        CultureFeed_Cdb_Data_Calendar_TimestampList $calendar,
161
        $index = null
162
    ) {
163
        $startDay = Period::createFromDay($startDate);
164
        $untilEndOfNextDay = $startDay
165
            ->withDuration('2 DAYS')
166
            ->moveEndDate('-1 SECOND');
167
168
        if ($untilEndOfNextDay->contains($endDate)) {
169
            $calendar->add(
170
                new CultureFeed_Cdb_Data_Calendar_Timestamp(
171
                    $startDate->format('Y-m-d'),
172
                    $this->formatDateTimeAsCdbTime($startDate),
173
                    $this->formatDateTimeAsCdbTime($endDate)
174
                )
175
            );
176
        } else if (is_int($index)) {
177
            $period = new Period($startDate, $endDate);
178
179
            $startTimestamp = new CultureFeed_Cdb_Data_Calendar_Timestamp(
180
                $startDate->format('Y-m-d'),
181
                $this->formatDateTimeAsCdbTime($startDate, $index)
182
            );
183
184
            $endTimestamp = new CultureFeed_Cdb_Data_Calendar_Timestamp(
185
                $endDate->format('Y-m-d'),
186
                '00:00:' . str_pad((string) $index, 2, '0', STR_PAD_LEFT),
187
                $this->formatDateTimeAsCdbTime($endDate)
188
            );
189
190
            $days = iterator_to_array($period->getDatePeriod('1 DAY'));
191
            $fillerTimestamps = array_map(
192
                function (DateTimeInterface $dateTime) use ($index) {
193
                    return new CultureFeed_Cdb_Data_Calendar_Timestamp(
194
                        $dateTime->format('Y-m-d'),
195
                        '00:00:' . str_pad((string) $index, 2, '0', STR_PAD_LEFT)
196
                    );
197
                },
198
                array_slice($days, 1, count($days) === 2 ? 2 : -1)
199
            );
200
201
            $calendar = array_reduce(
202
                array_merge([$startTimestamp], $fillerTimestamps, [$endTimestamp]),
203
                function (CultureFeed_Cdb_Data_Calendar_TimestampList $calendar, $timestamp) {
204
                    $calendar->add($timestamp);
205
                    return $calendar;
206
                },
207
                $calendar
208
            );
209
        }
210
211
        return $calendar;
212
    }
213
214
    /**
215
     * @param DateTimeInterface $timestamp
216
     * @param integer|null $index
217
     * @return null|string
218
     */
219
    private function formatDateTimeAsCdbTime(DateTimeInterface $timestamp, $index = null)
220
    {
221
        if (is_int($index) && $index > 59) {
222
            throw new InvalidArgumentException('The CDB time index should not be higher than 59!');
223
        }
224
225
        $time = is_int($index)
226
            ? $timestamp->format('H:i') . ':' . str_pad((string) $index, 2, '0', STR_PAD_LEFT)
227
            : $timestamp->format('H:i:s');
228
229
        if ($time == '00:00:00') {
230
            $time = null;
231
        }
232
233
        return $time;
234
    }
235
}
236