Completed
Pull Request — master (#296)
by Luc
05:01
created

Calendar::getStartDate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
namespace CultuurNet\UDB3;
4
5
use Broadway\Serializer\SerializableInterface;
6
use CultuurNet\UDB3\Calendar\OpeningHour;
7
use DateTime;
8
use DateTimeInterface;
9
use DateTimeZone;
10
use InvalidArgumentException;
11
12
/**
13
 * Calendar for events and places.
14
 */
15
class Calendar implements CalendarInterface, JsonLdSerializableInterface, SerializableInterface
16
{
17
18
    /**
19
     * @var CalendarType
20
     */
21
    protected $type = null;
22
23
    /**
24
     * @var DateTimeInterface
25
     */
26
    protected $startDate = null;
27
28
    /**
29
     * @var DateTimeInterface
30
     */
31
    protected $endDate = null;
32
33
    /**
34
     * @var Timestamp[]
35
     */
36
    protected $timestamps = array();
37
38
    /**
39
     * @var OpeningHour[]
40
     */
41
    protected $openingHours = array();
42
43
    /**
44
     * @param CalendarType $type
45
     * @param DateTimeInterface|null $startDate
46
     * @param DateTimeInterface|null $endDate
47
     * @param Timestamp[] $timestamps
48
     * @param OpeningHour[] $openingHours
49
     */
50
    public function __construct(
51
        CalendarType $type,
52
        DateTimeInterface $startDate = null,
53
        DateTimeInterface $endDate = null,
54
        array $timestamps = array(),
55
        array $openingHours = array()
56
    ) {
57
        if (($type->is(CalendarType::MULTIPLE()) || $type->is(CalendarType::SINGLE())) && empty($startDate)) {
58
            throw new \UnexpectedValueException('Start date can not be empty for calendar type: ' . $type . '.');
59
        }
60
61
        if ($type->is(CalendarType::PERIODIC()) && (empty($startDate) || empty($endDate))) {
62
            throw new \UnexpectedValueException('A period should have a start- and end-date.');
63
        }
64
65
        $this->type = $type->toNative();
66
        $this->startDate = $startDate;
67
        $this->endDate = $endDate;
68
        $this->timestamps = $timestamps;
69
        $this->openingHours = $openingHours;
70
    }
71
72
    /**
73
     * @inheritdoc
74
     */
75
    public function getType()
76
    {
77
        return CalendarType::fromNative($this->type);
78
    }
79
80
    /**
81
     * {@inheritdoc}
82
     */
83
    public function serialize()
84
    {
85
        $serializedTimestamps = array_map(
86
            function (Timestamp $timestamp) {
87
                return $timestamp->serialize();
88
            },
89
            $this->timestamps
90
        );
91
92
        $serializedOpeningHours = array_map(
93
            function (OpeningHour $openingHour) {
94
                return $openingHour->serialize();
95
            },
96
            $this->openingHours
97
        );
98
99
        $calendar = [
100
          'type' => $this->type,
101
        ];
102
103
        empty($this->startDate) ?: $calendar['startDate'] = $this->startDate->format(DateTime::ATOM);
104
        empty($this->endDate) ?: $calendar['endDate'] = $this->endDate->format(DateTime::ATOM);
105
        empty($serializedTimestamps) ?: $calendar['timestamps'] = $serializedTimestamps;
106
        empty($serializedOpeningHours) ?: $calendar['openingHours'] = $serializedOpeningHours;
107
108
        return $calendar;
109
    }
110
111
    /**
112
     * {@inheritdoc}
113
     */
114
    public static function deserialize(array $data)
115
    {
116
        return new static(
117
            CalendarType::fromNative($data['type']),
118
            !empty($data['startDate']) ? self::deserializeDateTime($data['startDate']) : null,
119
            !empty($data['endDate']) ? self::deserializeDateTime($data['endDate']) : null,
120
            !empty($data['timestamps']) ? array_map(
121
                function ($timestamp) {
122
                    return Timestamp::deserialize($timestamp);
123
                },
124
                $data['timestamps']
125
            ) : [],
126
            !empty($data['openingHours']) ? array_map(
127
                function ($openingHour) {
128
                    return OpeningHour::deserialize($openingHour);
129
                },
130
                $data['openingHours']
131
            ) : []
132
        );
133
    }
134
135
    /**
136
     * This deserialization function takes into account old data that might be missing a timezone.
137
     * It will fall back to creating a DateTime object and assume Brussels.
138
     * If this still fails an error will be thrown.
139
     *
140
     * @param $dateTimeData
141
     * @return DateTime
142
     *
143
     * @throws InvalidArgumentException
144
     */
145
    private static function deserializeDateTime($dateTimeData)
146
    {
147
        $dateTime = DateTime::createFromFormat(DateTime::ATOM, $dateTimeData);
148
149
        if ($dateTime === false) {
150
            $dateTime = DateTime::createFromFormat('Y-m-d\TH:i:s', $dateTimeData, new DateTimeZone('Europe/Brussels'));
151
152
            if (!$dateTime) {
153
                throw new InvalidArgumentException('Invalid date string provided for timestamp, ISO8601 expected!');
154
            }
155
        }
156
157
        return $dateTime;
158
    }
159
160
    /**
161
     * @inheritdoc
162
     */
163
    public function getStartDate()
164
    {
165
        return $this->startDate;
166
    }
167
168
    /**
169
     * @inheritdoc
170
     */
171
    public function getEndDate()
172
    {
173
        return $this->endDate;
174
    }
175
176
    /**
177
     * @inheritdoc
178
     */
179
    public function getOpeningHours()
180
    {
181
        return $this->openingHours;
182
    }
183
184
    /**
185
     * @inheritdoc
186
     */
187
    public function getTimestamps()
188
    {
189
        return $this->timestamps;
190
    }
191
192
    /**
193
     * Return the jsonLD version of a calendar.
194
     */
195
    public function toJsonLd()
196
    {
197
        $jsonLd = [];
198
199
        $jsonLd['calendarType'] = $this->getType()->toNative();
200
        // All calendar types allow startDate (and endDate).
201
        // One timestamp - full day.
202
        // One timestamp - start hour.
203
        // One timestamp - start and end hour.
204
        empty($this->startDate) ?: $jsonLd['startDate'] = $this->getStartDate()->format(DateTime::ATOM);
205
        empty($this->endDate) ?: $jsonLd['endDate'] = $this->getEndDate()->format(DateTime::ATOM);
206
207
208
        $timestamps = $this->getTimestamps();
209
        if (!empty($timestamps)) {
210
            $jsonLd['subEvent'] = array();
211
            foreach ($timestamps as $timestamp) {
212
                $jsonLd['subEvent'][] = array(
213
                  '@type' => 'Event',
214
                  'startDate' => $timestamp->getStartDate()->format(DateTime::ATOM),
215
                  'endDate' => $timestamp->getEndDate()->format(DateTime::ATOM),
216
                );
217
            }
218
        }
219
220
        // Period.
221
        // Period with openingtimes.
222
        // Permanent - "altijd open".
223
        // Permanent - with openingtimes
224
        $openingHours = $this->getOpeningHours();
225
        if (!empty($openingHours)) {
226
            $jsonLd['openingHours'] = array();
227
            foreach ($openingHours as $openingHour) {
228
                $jsonLd['openingHours'][] = $openingHour->serialize();
229
            }
230
        }
231
232
        return $jsonLd;
233
    }
234
}
235