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