PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 2.4.8
Booking for Appointments and Events Calendar – Amelia v2.4.8
2.4.8 2.4.7 2.4.6 2.4.5 2.4.4 2.4.3 2.4.2 2.4.1 2.4 trunk 1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.15 1.2.16 1.2.17 1.2.18 1.2.19 1.2.2 1.2.20 1.2.21 1.2.22 1.2.23 1.2.24 1.2.25 1.2.26 1.2.27 1.2.28 1.2.29 1.2.3 1.2.30 1.2.31 1.2.32 1.2.33 1.2.34 1.2.35 1.2.36 1.2.37 1.2.38 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 2.0 2.0.1 2.0.2 2.1 2.1.1 2.1.2 2.1.3 2.2 2.2.1 2.3
ameliabooking / vendor / sabre / vobject / lib / Property / ICalendar / DateTime.php
ameliabooking / vendor / sabre / vobject / lib / Property / ICalendar Last commit date
CalAddress.php 7 months ago Date.php 7 months ago DateTime.php 7 months ago Duration.php 7 months ago Period.php 7 months ago Recur.php 7 months ago
DateTime.php
365 lines
1 <?php
2
3 namespace AmeliaVendor\Sabre\VObject\Property\ICalendar;
4
5 use DateTimeInterface;
6 use DateTimeZone;
7 use AmeliaVendor\Sabre\VObject\DateTimeParser;
8 use AmeliaVendor\Sabre\VObject\InvalidDataException;
9 use AmeliaVendor\Sabre\VObject\Property;
10 use AmeliaVendor\Sabre\VObject\TimeZoneUtil;
11
12 /**
13 * DateTime property.
14 *
15 * This object represents DATE-TIME values, as defined here:
16 *
17 * http://tools.ietf.org/html/rfc5545#section-3.3.4
18 *
19 * This particular object has a bit of hackish magic that it may also in some
20 * cases represent a DATE value. This is because it's a common usecase to be
21 * able to change a DATE-TIME into a DATE.
22 *
23 * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
24 * @author Evert Pot (http://evertpot.com/)
25 * @license http://sabre.io/license/ Modified BSD License
26 */
27 class DateTime extends Property
28 {
29 /**
30 * In case this is a multi-value property. This string will be used as a
31 * delimiter.
32 *
33 * @var string|null
34 */
35 public $delimiter = ',';
36
37 /**
38 * Sets a multi-valued property.
39 *
40 * You may also specify DateTime objects here.
41 */
42 public function setParts(array $parts)
43 {
44 if (isset($parts[0]) && $parts[0] instanceof DateTimeInterface) {
45 $this->setDateTimes($parts);
46 } else {
47 parent::setParts($parts);
48 }
49 }
50
51 /**
52 * Updates the current value.
53 *
54 * This may be either a single, or multiple strings in an array.
55 *
56 * Instead of strings, you may also use DateTime here.
57 *
58 * @param string|array|DateTimeInterface $value
59 */
60 public function setValue($value)
61 {
62 if (is_array($value) && isset($value[0]) && $value[0] instanceof DateTimeInterface) {
63 $this->setDateTimes($value);
64 } elseif ($value instanceof DateTimeInterface) {
65 $this->setDateTimes([$value]);
66 } else {
67 parent::setValue($value);
68 }
69 }
70
71 /**
72 * Sets a raw value coming from a mimedir (iCalendar/vCard) file.
73 *
74 * This has been 'unfolded', so only 1 line will be passed. Unescaping is
75 * not yet done, but parameters are not included.
76 *
77 * @param string $val
78 */
79 public function setRawMimeDirValue($val)
80 {
81 $this->setValue(explode($this->delimiter, $val));
82 }
83
84 /**
85 * Returns a raw mime-dir representation of the value.
86 *
87 * @return string
88 */
89 public function getRawMimeDirValue()
90 {
91 return implode($this->delimiter, $this->getParts());
92 }
93
94 /**
95 * Returns true if this is a DATE-TIME value, false if it's a DATE.
96 *
97 * @return bool
98 */
99 public function hasTime()
100 {
101 return 'DATE' !== strtoupper((string) $this['VALUE']);
102 }
103
104 /**
105 * Returns true if this is a floating DATE or DATE-TIME.
106 *
107 * Note that DATE is always floating.
108 */
109 public function isFloating()
110 {
111 return
112 !$this->hasTime() ||
113 (
114 !isset($this['TZID']) &&
115 false === strpos($this->getValue(), 'Z')
116 );
117 }
118
119 /**
120 * Returns a date-time value.
121 *
122 * Note that if this property contained more than 1 date-time, only the
123 * first will be returned. To get an array with multiple values, call
124 * getDateTimes.
125 *
126 * If no timezone information is known, because it's either an all-day
127 * property or floating time, we will use the DateTimeZone argument to
128 * figure out the exact date.
129 *
130 * @param DateTimeZone $timeZone
131 *
132 * @return \DateTimeImmutable
133 */
134 public function getDateTime(?DateTimeZone $timeZone = null)
135 {
136 $dt = $this->getDateTimes($timeZone);
137 if (!$dt) {
138 return;
139 }
140
141 return $dt[0];
142 }
143
144 /**
145 * Returns multiple date-time values.
146 *
147 * If no timezone information is known, because it's either an all-day
148 * property or floating time, we will use the DateTimeZone argument to
149 * figure out the exact date.
150 *
151 * @param DateTimeZone $timeZone
152 *
153 * @return \DateTimeImmutable[]
154 * @return \DateTime[]
155 */
156 public function getDateTimes(?DateTimeZone $timeZone = null)
157 {
158 // Does the property have a TZID?
159 $tzid = $this['TZID'];
160
161 if ($tzid) {
162 $timeZone = TimeZoneUtil::getTimeZone((string) $tzid, $this->root);
163 }
164
165 $dts = [];
166 foreach ($this->getParts() as $part) {
167 $dts[] = DateTimeParser::parse($part, $timeZone);
168 }
169
170 return $dts;
171 }
172
173 /**
174 * Sets the property as a DateTime object.
175 *
176 * @param bool isFloating If set to true, timezones will be ignored
177 */
178 public function setDateTime(DateTimeInterface $dt, $isFloating = false)
179 {
180 $this->setDateTimes([$dt], $isFloating);
181 }
182
183 /**
184 * Sets the property as multiple date-time objects.
185 *
186 * The first value will be used as a reference for the timezones, and all
187 * the other values will be adjusted for that timezone
188 *
189 * @param DateTimeInterface[] $dt
190 * @param bool isFloating If set to true, timezones will be ignored
191 */
192 public function setDateTimes(array $dt, $isFloating = false)
193 {
194 $values = [];
195
196 if ($this->hasTime()) {
197 $tz = null;
198 $isUtc = false;
199
200 foreach ($dt as $d) {
201 if ($isFloating) {
202 $values[] = $d->format('Ymd\\THis');
203 continue;
204 }
205 if (is_null($tz)) {
206 $tz = $d->getTimeZone();
207 $isUtc = in_array($tz->getName(), ['UTC', 'GMT', 'Z', '+00:00']);
208 if (!$isUtc) {
209 $this->offsetSet('TZID', $tz->getName());
210 }
211 } else {
212 $d = $d->setTimeZone($tz);
213 }
214
215 if ($isUtc) {
216 $values[] = $d->format('Ymd\\THis\\Z');
217 } else {
218 $values[] = $d->format('Ymd\\THis');
219 }
220 }
221 if ($isUtc || $isFloating) {
222 $this->offsetUnset('TZID');
223 }
224 } else {
225 foreach ($dt as $d) {
226 $values[] = $d->format('Ymd');
227 }
228 $this->offsetUnset('TZID');
229 }
230
231 $this->value = $values;
232 }
233
234 /**
235 * Returns the type of value.
236 *
237 * This corresponds to the VALUE= parameter. Every property also has a
238 * 'default' valueType.
239 *
240 * @return string
241 */
242 public function getValueType()
243 {
244 return $this->hasTime() ? 'DATE-TIME' : 'DATE';
245 }
246
247 /**
248 * Returns the value, in the format it should be encoded for JSON.
249 *
250 * This method must always return an array.
251 *
252 * @return array
253 */
254 public function getJsonValue()
255 {
256 $dts = $this->getDateTimes();
257 $hasTime = $this->hasTime();
258 $isFloating = $this->isFloating();
259
260 $tz = $dts[0]->getTimeZone();
261 $isUtc = $isFloating ? false : in_array($tz->getName(), ['UTC', 'GMT', 'Z']);
262
263 return array_map(
264 function (DateTimeInterface $dt) use ($hasTime, $isUtc) {
265 if ($hasTime) {
266 return $dt->format('Y-m-d\\TH:i:s').($isUtc ? 'Z' : '');
267 } else {
268 return $dt->format('Y-m-d');
269 }
270 },
271 $dts
272 );
273 }
274
275 /**
276 * Sets the json value, as it would appear in a jCard or jCal object.
277 *
278 * The value must always be an array.
279 */
280 public function setJsonValue(array $value)
281 {
282 // dates and times in jCal have one difference to dates and times in
283 // iCalendar. In jCal date-parts are separated by dashes, and
284 // time-parts are separated by colons. It makes sense to just remove
285 // those.
286 $this->setValue(
287 array_map(
288 function ($item) {
289 return strtr($item, [':' => '', '-' => '']);
290 },
291 $value
292 )
293 );
294 }
295
296 /**
297 * We need to intercept offsetSet, because it may be used to alter the
298 * VALUE from DATE-TIME to DATE or vice-versa.
299 *
300 * @param string $name
301 * @param mixed $value
302 */
303 #[\ReturnTypeWillChange]
304 public function offsetSet($name, $value)
305 {
306 parent::offsetSet($name, $value);
307 if ('VALUE' !== strtoupper($name)) {
308 return;
309 }
310
311 // This will ensure that dates are correctly encoded.
312 $this->setDateTimes($this->getDateTimes());
313 }
314
315 /**
316 * Validates the node for correctness.
317 *
318 * The following options are supported:
319 * Node::REPAIR - May attempt to automatically repair the problem.
320 *
321 * This method returns an array with detected problems.
322 * Every element has the following properties:
323 *
324 * * level - problem level.
325 * * message - A human-readable string describing the issue.
326 * * node - A reference to the problematic node.
327 *
328 * The level means:
329 * 1 - The issue was repaired (only happens if REPAIR was turned on)
330 * 2 - An inconsequential issue
331 * 3 - A severe issue.
332 *
333 * @param int $options
334 *
335 * @return array
336 */
337 public function validate($options = 0)
338 {
339 $messages = parent::validate($options);
340 $valueType = $this->getValueType();
341 $values = $this->getParts();
342 foreach ($values as $value) {
343 try {
344 switch ($valueType) {
345 case 'DATE':
346 DateTimeParser::parseDate($value);
347 break;
348 case 'DATE-TIME':
349 DateTimeParser::parseDateTime($value);
350 break;
351 }
352 } catch (InvalidDataException $e) {
353 $messages[] = [
354 'level' => 3,
355 'message' => 'The supplied value ('.$value.') is not a correct '.$valueType,
356 'node' => $this,
357 ];
358 break;
359 }
360 }
361
362 return $messages;
363 }
364 }
365