Completed
Push — developer ( d751a3...e1a3df )
by Błażej
164:44 queued 111:37
created
libraries/SabreDAV/VObject/Component/Available.php 1 patch
Indentation   +107 added lines, -107 removed lines patch added patch discarded remove patch
@@ -16,111 +16,111 @@
 block discarded – undo
16 16
  */
17 17
 class Available extends VObject\Component {
18 18
 
19
-    /**
20
-     * Returns the 'effective start' and 'effective end' of this VAVAILABILITY
21
-     * component.
22
-     *
23
-     * We use the DTSTART and DTEND or DURATION to determine this.
24
-     *
25
-     * The returned value is an array containing DateTimeImmutable instances.
26
-     * If either the start or end is 'unbounded' its value will be null
27
-     * instead.
28
-     *
29
-     * @return array
30
-     */
31
-    public function getEffectiveStartEnd() {
32
-
33
-        $effectiveStart = $this->DTSTART->getDateTime();
34
-        if (isset($this->DTEND)) {
35
-            $effectiveEnd = $this->DTEND->getDateTime();
36
-        } else {
37
-            $effectiveEnd = $effectiveStart->add(VObject\DateTimeParser::parseDuration($this->DURATION));
38
-        }
39
-
40
-        return [$effectiveStart, $effectiveEnd];
41
-
42
-    }
43
-
44
-    /**
45
-     * A simple list of validation rules.
46
-     *
47
-     * This is simply a list of properties, and how many times they either
48
-     * must or must not appear.
49
-     *
50
-     * Possible values per property:
51
-     *   * 0 - Must not appear.
52
-     *   * 1 - Must appear exactly once.
53
-     *   * + - Must appear at least once.
54
-     *   * * - Can appear any number of times.
55
-     *   * ? - May appear, but not more than once.
56
-     *
57
-     * @var array
58
-     */
59
-    public function getValidationRules() {
60
-
61
-        return [
62
-            'UID'     => 1,
63
-            'DTSTART' => 1,
64
-            'DTSTAMP' => 1,
65
-
66
-            'DTEND'    => '?',
67
-            'DURATION' => '?',
68
-
69
-            'CREATED'       => '?',
70
-            'DESCRIPTION'   => '?',
71
-            'LAST-MODIFIED' => '?',
72
-            'RECURRENCE-ID' => '?',
73
-            'RRULE'         => '?',
74
-            'SUMMARY'       => '?',
75
-
76
-            'CATEGORIES' => '*',
77
-            'COMMENT'    => '*',
78
-            'CONTACT'    => '*',
79
-            'EXDATE'     => '*',
80
-            'RDATE'      => '*',
81
-
82
-            'AVAILABLE' => '*',
83
-        ];
84
-
85
-    }
86
-
87
-    /**
88
-     * Validates the node for correctness.
89
-     *
90
-     * The following options are supported:
91
-     *   Node::REPAIR - May attempt to automatically repair the problem.
92
-     *   Node::PROFILE_CARDDAV - Validate the vCard for CardDAV purposes.
93
-     *   Node::PROFILE_CALDAV - Validate the iCalendar for CalDAV purposes.
94
-     *
95
-     * This method returns an array with detected problems.
96
-     * Every element has the following properties:
97
-     *
98
-     *  * level - problem level.
99
-     *  * message - A human-readable string describing the issue.
100
-     *  * node - A reference to the problematic node.
101
-     *
102
-     * The level means:
103
-     *   1 - The issue was repaired (only happens if REPAIR was turned on).
104
-     *   2 - A warning.
105
-     *   3 - An error.
106
-     *
107
-     * @param int $options
108
-     *
109
-     * @return array
110
-     */
111
-    public function validate($options = 0) {
112
-
113
-        $result = parent::validate($options);
114
-
115
-        if (isset($this->DTEND) && isset($this->DURATION)) {
116
-            $result[] = [
117
-                'level'   => 3,
118
-                'message' => 'DTEND and DURATION cannot both be present',
119
-                'node'    => $this
120
-            ];
121
-        }
122
-
123
-        return $result;
124
-
125
-    }
19
+	/**
20
+	 * Returns the 'effective start' and 'effective end' of this VAVAILABILITY
21
+	 * component.
22
+	 *
23
+	 * We use the DTSTART and DTEND or DURATION to determine this.
24
+	 *
25
+	 * The returned value is an array containing DateTimeImmutable instances.
26
+	 * If either the start or end is 'unbounded' its value will be null
27
+	 * instead.
28
+	 *
29
+	 * @return array
30
+	 */
31
+	public function getEffectiveStartEnd() {
32
+
33
+		$effectiveStart = $this->DTSTART->getDateTime();
34
+		if (isset($this->DTEND)) {
35
+			$effectiveEnd = $this->DTEND->getDateTime();
36
+		} else {
37
+			$effectiveEnd = $effectiveStart->add(VObject\DateTimeParser::parseDuration($this->DURATION));
38
+		}
39
+
40
+		return [$effectiveStart, $effectiveEnd];
41
+
42
+	}
43
+
44
+	/**
45
+	 * A simple list of validation rules.
46
+	 *
47
+	 * This is simply a list of properties, and how many times they either
48
+	 * must or must not appear.
49
+	 *
50
+	 * Possible values per property:
51
+	 *   * 0 - Must not appear.
52
+	 *   * 1 - Must appear exactly once.
53
+	 *   * + - Must appear at least once.
54
+	 *   * * - Can appear any number of times.
55
+	 *   * ? - May appear, but not more than once.
56
+	 *
57
+	 * @var array
58
+	 */
59
+	public function getValidationRules() {
60
+
61
+		return [
62
+			'UID'     => 1,
63
+			'DTSTART' => 1,
64
+			'DTSTAMP' => 1,
65
+
66
+			'DTEND'    => '?',
67
+			'DURATION' => '?',
68
+
69
+			'CREATED'       => '?',
70
+			'DESCRIPTION'   => '?',
71
+			'LAST-MODIFIED' => '?',
72
+			'RECURRENCE-ID' => '?',
73
+			'RRULE'         => '?',
74
+			'SUMMARY'       => '?',
75
+
76
+			'CATEGORIES' => '*',
77
+			'COMMENT'    => '*',
78
+			'CONTACT'    => '*',
79
+			'EXDATE'     => '*',
80
+			'RDATE'      => '*',
81
+
82
+			'AVAILABLE' => '*',
83
+		];
84
+
85
+	}
86
+
87
+	/**
88
+	 * Validates the node for correctness.
89
+	 *
90
+	 * The following options are supported:
91
+	 *   Node::REPAIR - May attempt to automatically repair the problem.
92
+	 *   Node::PROFILE_CARDDAV - Validate the vCard for CardDAV purposes.
93
+	 *   Node::PROFILE_CALDAV - Validate the iCalendar for CalDAV purposes.
94
+	 *
95
+	 * This method returns an array with detected problems.
96
+	 * Every element has the following properties:
97
+	 *
98
+	 *  * level - problem level.
99
+	 *  * message - A human-readable string describing the issue.
100
+	 *  * node - A reference to the problematic node.
101
+	 *
102
+	 * The level means:
103
+	 *   1 - The issue was repaired (only happens if REPAIR was turned on).
104
+	 *   2 - A warning.
105
+	 *   3 - An error.
106
+	 *
107
+	 * @param int $options
108
+	 *
109
+	 * @return array
110
+	 */
111
+	public function validate($options = 0) {
112
+
113
+		$result = parent::validate($options);
114
+
115
+		if (isset($this->DTEND) && isset($this->DURATION)) {
116
+			$result[] = [
117
+				'level'   => 3,
118
+				'message' => 'DTEND and DURATION cannot both be present',
119
+				'node'    => $this
120
+			];
121
+		}
122
+
123
+		return $result;
124
+
125
+	}
126 126
 }
Please login to merge, or discard this patch.
libraries/SabreDAV/VObject/Component/VCard.php 1 patch
Indentation   +520 added lines, -520 removed lines patch added patch discarded remove patch
@@ -17,537 +17,537 @@
 block discarded – undo
17 17
  */
18 18
 class VCard extends VObject\Document {
19 19
 
20
-    /**
21
-     * The default name for this component.
22
-     *
23
-     * This should be 'VCALENDAR' or 'VCARD'.
24
-     *
25
-     * @var string
26
-     */
27
-    static $defaultName = 'VCARD';
28
-
29
-    /**
30
-     * Caching the version number.
31
-     *
32
-     * @var int
33
-     */
34
-    private $version = null;
35
-
36
-    /**
37
-     * This is a list of components, and which classes they should map to.
38
-     *
39
-     * @var array
40
-     */
41
-    static $componentMap = [
42
-        'VCARD' => 'Sabre\\VObject\\Component\\VCard',
43
-    ];
44
-
45
-    /**
46
-     * List of value-types, and which classes they map to.
47
-     *
48
-     * @var array
49
-     */
50
-    static $valueMap = [
51
-        'BINARY'           => 'Sabre\\VObject\\Property\\Binary',
52
-        'BOOLEAN'          => 'Sabre\\VObject\\Property\\Boolean',
53
-        'CONTENT-ID'       => 'Sabre\\VObject\\Property\\FlatText',   // vCard 2.1 only
54
-        'DATE'             => 'Sabre\\VObject\\Property\\VCard\\Date',
55
-        'DATE-TIME'        => 'Sabre\\VObject\\Property\\VCard\\DateTime',
56
-        'DATE-AND-OR-TIME' => 'Sabre\\VObject\\Property\\VCard\\DateAndOrTime', // vCard only
57
-        'FLOAT'            => 'Sabre\\VObject\\Property\\FloatValue',
58
-        'INTEGER'          => 'Sabre\\VObject\\Property\\IntegerValue',
59
-        'LANGUAGE-TAG'     => 'Sabre\\VObject\\Property\\VCard\\LanguageTag',
60
-        'TIMESTAMP'        => 'Sabre\\VObject\\Property\\VCard\\TimeStamp',
61
-        'TEXT'             => 'Sabre\\VObject\\Property\\Text',
62
-        'TIME'             => 'Sabre\\VObject\\Property\\Time',
63
-        'UNKNOWN'          => 'Sabre\\VObject\\Property\\Unknown', // jCard / jCal-only.
64
-        'URI'              => 'Sabre\\VObject\\Property\\Uri',
65
-        'URL'              => 'Sabre\\VObject\\Property\\Uri', // vCard 2.1 only
66
-        'UTC-OFFSET'       => 'Sabre\\VObject\\Property\\UtcOffset',
67
-    ];
68
-
69
-    /**
70
-     * List of properties, and which classes they map to.
71
-     *
72
-     * @var array
73
-     */
74
-    static $propertyMap = [
75
-
76
-        // vCard 2.1 properties and up
77
-        'N'       => 'Sabre\\VObject\\Property\\Text',
78
-        'FN'      => 'Sabre\\VObject\\Property\\FlatText',
79
-        'PHOTO'   => 'Sabre\\VObject\\Property\\Binary',
80
-        'BDAY'    => 'Sabre\\VObject\\Property\\VCard\\DateAndOrTime',
81
-        'ADR'     => 'Sabre\\VObject\\Property\\Text',
82
-        'LABEL'   => 'Sabre\\VObject\\Property\\FlatText', // Removed in vCard 4.0
83
-        'TEL'     => 'Sabre\\VObject\\Property\\FlatText',
84
-        'EMAIL'   => 'Sabre\\VObject\\Property\\FlatText',
85
-        'MAILER'  => 'Sabre\\VObject\\Property\\FlatText', // Removed in vCard 4.0
86
-        'GEO'     => 'Sabre\\VObject\\Property\\FlatText',
87
-        'TITLE'   => 'Sabre\\VObject\\Property\\FlatText',
88
-        'ROLE'    => 'Sabre\\VObject\\Property\\FlatText',
89
-        'LOGO'    => 'Sabre\\VObject\\Property\\Binary',
90
-        // 'AGENT'   => 'Sabre\\VObject\\Property\\',      // Todo: is an embedded vCard. Probably rare, so
91
-                                 // not supported at the moment
92
-        'ORG'     => 'Sabre\\VObject\\Property\\Text',
93
-        'NOTE'    => 'Sabre\\VObject\\Property\\FlatText',
94
-        'REV'     => 'Sabre\\VObject\\Property\\VCard\\TimeStamp',
95
-        'SOUND'   => 'Sabre\\VObject\\Property\\FlatText',
96
-        'URL'     => 'Sabre\\VObject\\Property\\Uri',
97
-        'UID'     => 'Sabre\\VObject\\Property\\FlatText',
98
-        'VERSION' => 'Sabre\\VObject\\Property\\FlatText',
99
-        'KEY'     => 'Sabre\\VObject\\Property\\FlatText',
100
-        'TZ'      => 'Sabre\\VObject\\Property\\Text',
101
-
102
-        // vCard 3.0 properties
103
-        'CATEGORIES'  => 'Sabre\\VObject\\Property\\Text',
104
-        'SORT-STRING' => 'Sabre\\VObject\\Property\\FlatText',
105
-        'PRODID'      => 'Sabre\\VObject\\Property\\FlatText',
106
-        'NICKNAME'    => 'Sabre\\VObject\\Property\\Text',
107
-        'CLASS'       => 'Sabre\\VObject\\Property\\FlatText', // Removed in vCard 4.0
108
-
109
-        // rfc2739 properties
110
-        'FBURL'        => 'Sabre\\VObject\\Property\\Uri',
111
-        'CAPURI'       => 'Sabre\\VObject\\Property\\Uri',
112
-        'CALURI'       => 'Sabre\\VObject\\Property\\Uri',
113
-        'CALADRURI'    => 'Sabre\\VObject\\Property\\Uri',
114
-
115
-        // rfc4770 properties
116
-        'IMPP'         => 'Sabre\\VObject\\Property\\Uri',
117
-
118
-        // vCard 4.0 properties
119
-        'SOURCE'       => 'Sabre\\VObject\\Property\\Uri',
120
-        'XML'          => 'Sabre\\VObject\\Property\\FlatText',
121
-        'ANNIVERSARY'  => 'Sabre\\VObject\\Property\\VCard\\DateAndOrTime',
122
-        'CLIENTPIDMAP' => 'Sabre\\VObject\\Property\\Text',
123
-        'LANG'         => 'Sabre\\VObject\\Property\\VCard\\LanguageTag',
124
-        'GENDER'       => 'Sabre\\VObject\\Property\\Text',
125
-        'KIND'         => 'Sabre\\VObject\\Property\\FlatText',
126
-        'MEMBER'       => 'Sabre\\VObject\\Property\\Uri',
127
-        'RELATED'      => 'Sabre\\VObject\\Property\\Uri',
128
-
129
-        // rfc6474 properties
130
-        'BIRTHPLACE'    => 'Sabre\\VObject\\Property\\FlatText',
131
-        'DEATHPLACE'    => 'Sabre\\VObject\\Property\\FlatText',
132
-        'DEATHDATE'     => 'Sabre\\VObject\\Property\\VCard\\DateAndOrTime',
133
-
134
-        // rfc6715 properties
135
-        'EXPERTISE'     => 'Sabre\\VObject\\Property\\FlatText',
136
-        'HOBBY'         => 'Sabre\\VObject\\Property\\FlatText',
137
-        'INTEREST'      => 'Sabre\\VObject\\Property\\FlatText',
138
-        'ORG-DIRECTORY' => 'Sabre\\VObject\\Property\\FlatText',
139
-
140
-    ];
141
-
142
-    /**
143
-     * Returns the current document type.
144
-     *
145
-     * @return int
146
-     */
147
-    public function getDocumentType() {
148
-
149
-        if (!$this->version) {
150
-
151
-            $version = (string)$this->VERSION;
152
-
153
-            switch ($version) {
154
-                case '2.1' :
155
-                    $this->version = self::VCARD21;
156
-                    break;
157
-                case '3.0' :
158
-                    $this->version = self::VCARD30;
159
-                    break;
160
-                case '4.0' :
161
-                    $this->version = self::VCARD40;
162
-                    break;
163
-                default :
164
-                    // We don't want to cache the version if it's unknown,
165
-                    // because we might get a version property in a bit.
166
-                    return self::UNKNOWN;
167
-            }
168
-        }
169
-
170
-        return $this->version;
171
-
172
-    }
173
-
174
-    /**
175
-     * Converts the document to a different vcard version.
176
-     *
177
-     * Use one of the VCARD constants for the target. This method will return
178
-     * a copy of the vcard in the new version.
179
-     *
180
-     * At the moment the only supported conversion is from 3.0 to 4.0.
181
-     *
182
-     * If input and output version are identical, a clone is returned.
183
-     *
184
-     * @param int $target
185
-     *
186
-     * @return VCard
187
-     */
188
-    public function convert($target) {
189
-
190
-        $converter = new VObject\VCardConverter();
191
-        return $converter->convert($this, $target);
192
-
193
-    }
194
-
195
-    /**
196
-     * VCards with version 2.1, 3.0 and 4.0 are found.
197
-     *
198
-     * If the VCARD doesn't know its version, 2.1 is assumed.
199
-     */
200
-    const DEFAULT_VERSION = self::VCARD21;
201
-
202
-    /**
203
-     * Validates the node for correctness.
204
-     *
205
-     * The following options are supported:
206
-     *   Node::REPAIR - May attempt to automatically repair the problem.
207
-     *
208
-     * This method returns an array with detected problems.
209
-     * Every element has the following properties:
210
-     *
211
-     *  * level - problem level.
212
-     *  * message - A human-readable string describing the issue.
213
-     *  * node - A reference to the problematic node.
214
-     *
215
-     * The level means:
216
-     *   1 - The issue was repaired (only happens if REPAIR was turned on)
217
-     *   2 - An inconsequential issue
218
-     *   3 - A severe issue.
219
-     *
220
-     * @param int $options
221
-     *
222
-     * @return array
223
-     */
224
-    public function validate($options = 0) {
225
-
226
-        $warnings = [];
227
-
228
-        $versionMap = [
229
-            self::VCARD21 => '2.1',
230
-            self::VCARD30 => '3.0',
231
-            self::VCARD40 => '4.0',
232
-        ];
233
-
234
-        $version = $this->select('VERSION');
235
-        if (count($version) === 1) {
236
-            $version = (string)$this->VERSION;
237
-            if ($version !== '2.1' && $version !== '3.0' && $version !== '4.0') {
238
-                $warnings[] = [
239
-                    'level'   => 3,
240
-                    'message' => 'Only vcard version 4.0 (RFC6350), version 3.0 (RFC2426) or version 2.1 (icm-vcard-2.1) are supported.',
241
-                    'node'    => $this,
242
-                ];
243
-                if ($options & self::REPAIR) {
244
-                    $this->VERSION = $versionMap[self::DEFAULT_VERSION];
245
-                }
246
-            }
247
-            if ($version === '2.1' && ($options & self::PROFILE_CARDDAV)) {
248
-                $warnings[] = [
249
-                    'level'   => 3,
250
-                    'message' => 'CardDAV servers are not allowed to accept vCard 2.1.',
251
-                    'node'    => $this,
252
-                ];
253
-            }
254
-
255
-        }
256
-        $uid = $this->select('UID');
257
-        if (count($uid) === 0) {
258
-            if ($options & self::PROFILE_CARDDAV) {
259
-                // Required for CardDAV
260
-                $warningLevel = 3;
261
-                $message = 'vCards on CardDAV servers MUST have a UID property.';
262
-            } else {
263
-                // Not required for regular vcards
264
-                $warningLevel = 2;
265
-                $message = 'Adding a UID to a vCard property is recommended.';
266
-            }
267
-            if ($options & self::REPAIR) {
268
-                $this->UID = VObject\UUIDUtil::getUUID();
269
-                $warningLevel = 1;
270
-            }
271
-            $warnings[] = [
272
-                'level'   => $warningLevel,
273
-                'message' => $message,
274
-                'node'    => $this,
275
-            ];
276
-        }
277
-
278
-        $fn = $this->select('FN');
279
-        if (count($fn) !== 1) {
280
-
281
-            $repaired = false;
282
-            if (($options & self::REPAIR) && count($fn) === 0) {
283
-                // We're going to try to see if we can use the contents of the
284
-                // N property.
285
-                if (isset($this->N)) {
286
-                    $value = explode(';', (string)$this->N);
287
-                    if (isset($value[1]) && $value[1]) {
288
-                        $this->FN = $value[1] . ' ' . $value[0];
289
-                    } else {
290
-                        $this->FN = $value[0];
291
-                    }
292
-                    $repaired = true;
293
-
294
-                // Otherwise, the ORG property may work
295
-                } elseif (isset($this->ORG)) {
296
-                    $this->FN = (string)$this->ORG;
297
-                    $repaired = true;
298
-                }
299
-
300
-            }
301
-            $warnings[] = [
302
-                'level'   => $repaired ? 1 : 3,
303
-                'message' => 'The FN property must appear in the VCARD component exactly 1 time',
304
-                'node'    => $this,
305
-            ];
306
-        }
307
-
308
-        return array_merge(
309
-            parent::validate($options),
310
-            $warnings
311
-        );
312
-
313
-    }
314
-
315
-    /**
316
-     * A simple list of validation rules.
317
-     *
318
-     * This is simply a list of properties, and how many times they either
319
-     * must or must not appear.
320
-     *
321
-     * Possible values per property:
322
-     *   * 0 - Must not appear.
323
-     *   * 1 - Must appear exactly once.
324
-     *   * + - Must appear at least once.
325
-     *   * * - Can appear any number of times.
326
-     *   * ? - May appear, but not more than once.
327
-     *
328
-     * @var array
329
-     */
330
-    public function getValidationRules() {
331
-
332
-        return [
333
-            'ADR'          => '*',
334
-            'ANNIVERSARY'  => '?',
335
-            'BDAY'         => '?',
336
-            'CALADRURI'    => '*',
337
-            'CALURI'       => '*',
338
-            'CATEGORIES'   => '*',
339
-            'CLIENTPIDMAP' => '*',
340
-            'EMAIL'        => '*',
341
-            'FBURL'        => '*',
342
-            'IMPP'         => '*',
343
-            'GENDER'       => '?',
344
-            'GEO'          => '*',
345
-            'KEY'          => '*',
346
-            'KIND'         => '?',
347
-            'LANG'         => '*',
348
-            'LOGO'         => '*',
349
-            'MEMBER'       => '*',
350
-            'N'            => '?',
351
-            'NICKNAME'     => '*',
352
-            'NOTE'         => '*',
353
-            'ORG'          => '*',
354
-            'PHOTO'        => '*',
355
-            'PRODID'       => '?',
356
-            'RELATED'      => '*',
357
-            'REV'          => '?',
358
-            'ROLE'         => '*',
359
-            'SOUND'        => '*',
360
-            'SOURCE'       => '*',
361
-            'TEL'          => '*',
362
-            'TITLE'        => '*',
363
-            'TZ'           => '*',
364
-            'URL'          => '*',
365
-            'VERSION'      => '1',
366
-            'XML'          => '*',
367
-
368
-            // FN is commented out, because it's already handled by the
369
-            // validate function, which may also try to repair it.
370
-            // 'FN'           => '+',
371
-            'UID'          => '?',
372
-        ];
373
-
374
-    }
375
-
376
-    /**
377
-     * Returns a preferred field.
378
-     *
379
-     * VCards can indicate wether a field such as ADR, TEL or EMAIL is
380
-     * preferred by specifying TYPE=PREF (vcard 2.1, 3) or PREF=x (vcard 4, x
381
-     * being a number between 1 and 100).
382
-     *
383
-     * If neither of those parameters are specified, the first is returned, if
384
-     * a field with that name does not exist, null is returned.
385
-     *
386
-     * @param string $fieldName
387
-     *
388
-     * @return VObject\Property|null
389
-     */
390
-    public function preferred($propertyName) {
391
-
392
-        $preferred = null;
393
-        $lastPref = 101;
394
-        foreach ($this->select($propertyName) as $field) {
395
-
396
-            $pref = 101;
397
-            if (isset($field['TYPE']) && $field['TYPE']->has('PREF')) {
398
-                $pref = 1;
399
-            } elseif (isset($field['PREF'])) {
400
-                $pref = $field['PREF']->getValue();
401
-            }
402
-
403
-            if ($pref < $lastPref || is_null($preferred)) {
404
-                $preferred = $field;
405
-                $lastPref = $pref;
406
-            }
407
-
408
-        }
409
-        return $preferred;
410
-
411
-    }
412
-
413
-    /**
414
-     * Returns a property with a specific TYPE value (ADR, TEL, or EMAIL).
415
-     *
416
-     * This function will return null if the property does not exist. If there are
417
-     * multiple properties with the same TYPE value, only one will be returned.
418
-     *
419
-     * @param string $propertyName
420
-     * @param string $type
421
-     *
422
-     * @return VObject\Property|null
423
-     */
424
-    public function getByType($propertyName, $type) {
425
-        foreach ($this->select($propertyName) as $field) {
426
-            if (isset($field['TYPE']) && $field['TYPE']->has($type)) {
427
-                return $field;
428
-            }
429
-        }
430
-    }
431
-
432
-    /**
433
-     * This method should return a list of default property values.
434
-     *
435
-     * @return array
436
-     */
437
-    protected function getDefaults() {
438
-
439
-        return [
440
-            'VERSION' => '4.0',
441
-            'PRODID'  => '-//Sabre//Sabre VObject ' . VObject\Version::VERSION . '//EN',
442
-            'UID'     => 'sabre-vobject-' . VObject\UUIDUtil::getUUID(),
443
-        ];
444
-
445
-    }
446
-
447
-    /**
448
-     * This method returns an array, with the representation as it should be
449
-     * encoded in json. This is used to create jCard or jCal documents.
450
-     *
451
-     * @return array
452
-     */
453
-    public function jsonSerialize() {
454
-
455
-        // A vcard does not have sub-components, so we're overriding this
456
-        // method to remove that array element.
457
-        $properties = [];
458
-
459
-        foreach ($this->children() as $child) {
460
-            $properties[] = $child->jsonSerialize();
461
-        }
462
-
463
-        return [
464
-            strtolower($this->name),
465
-            $properties,
466
-        ];
467
-
468
-    }
469
-
470
-    /**
471
-     * This method serializes the data into XML. This is used to create xCard or
472
-     * xCal documents.
473
-     *
474
-     * @param Xml\Writer $writer  XML writer.
475
-     *
476
-     * @return void
477
-     */
478
-    public function xmlSerialize(Xml\Writer $writer) {
479
-
480
-        $propertiesByGroup = [];
481
-
482
-        foreach ($this->children() as $property) {
483
-
484
-            $group = $property->group;
485
-
486
-            if (!isset($propertiesByGroup[$group])) {
487
-                $propertiesByGroup[$group] = [];
488
-            }
489
-
490
-            $propertiesByGroup[$group][] = $property;
491
-
492
-        }
493
-
494
-        $writer->startElement(strtolower($this->name));
495
-
496
-        foreach ($propertiesByGroup as $group => $properties) {
497
-
498
-            if (!empty($group)) {
499
-
500
-                $writer->startElement('group');
501
-                $writer->writeAttribute('name', strtolower($group));
20
+	/**
21
+	 * The default name for this component.
22
+	 *
23
+	 * This should be 'VCALENDAR' or 'VCARD'.
24
+	 *
25
+	 * @var string
26
+	 */
27
+	static $defaultName = 'VCARD';
28
+
29
+	/**
30
+	 * Caching the version number.
31
+	 *
32
+	 * @var int
33
+	 */
34
+	private $version = null;
35
+
36
+	/**
37
+	 * This is a list of components, and which classes they should map to.
38
+	 *
39
+	 * @var array
40
+	 */
41
+	static $componentMap = [
42
+		'VCARD' => 'Sabre\\VObject\\Component\\VCard',
43
+	];
44
+
45
+	/**
46
+	 * List of value-types, and which classes they map to.
47
+	 *
48
+	 * @var array
49
+	 */
50
+	static $valueMap = [
51
+		'BINARY'           => 'Sabre\\VObject\\Property\\Binary',
52
+		'BOOLEAN'          => 'Sabre\\VObject\\Property\\Boolean',
53
+		'CONTENT-ID'       => 'Sabre\\VObject\\Property\\FlatText',   // vCard 2.1 only
54
+		'DATE'             => 'Sabre\\VObject\\Property\\VCard\\Date',
55
+		'DATE-TIME'        => 'Sabre\\VObject\\Property\\VCard\\DateTime',
56
+		'DATE-AND-OR-TIME' => 'Sabre\\VObject\\Property\\VCard\\DateAndOrTime', // vCard only
57
+		'FLOAT'            => 'Sabre\\VObject\\Property\\FloatValue',
58
+		'INTEGER'          => 'Sabre\\VObject\\Property\\IntegerValue',
59
+		'LANGUAGE-TAG'     => 'Sabre\\VObject\\Property\\VCard\\LanguageTag',
60
+		'TIMESTAMP'        => 'Sabre\\VObject\\Property\\VCard\\TimeStamp',
61
+		'TEXT'             => 'Sabre\\VObject\\Property\\Text',
62
+		'TIME'             => 'Sabre\\VObject\\Property\\Time',
63
+		'UNKNOWN'          => 'Sabre\\VObject\\Property\\Unknown', // jCard / jCal-only.
64
+		'URI'              => 'Sabre\\VObject\\Property\\Uri',
65
+		'URL'              => 'Sabre\\VObject\\Property\\Uri', // vCard 2.1 only
66
+		'UTC-OFFSET'       => 'Sabre\\VObject\\Property\\UtcOffset',
67
+	];
68
+
69
+	/**
70
+	 * List of properties, and which classes they map to.
71
+	 *
72
+	 * @var array
73
+	 */
74
+	static $propertyMap = [
75
+
76
+		// vCard 2.1 properties and up
77
+		'N'       => 'Sabre\\VObject\\Property\\Text',
78
+		'FN'      => 'Sabre\\VObject\\Property\\FlatText',
79
+		'PHOTO'   => 'Sabre\\VObject\\Property\\Binary',
80
+		'BDAY'    => 'Sabre\\VObject\\Property\\VCard\\DateAndOrTime',
81
+		'ADR'     => 'Sabre\\VObject\\Property\\Text',
82
+		'LABEL'   => 'Sabre\\VObject\\Property\\FlatText', // Removed in vCard 4.0
83
+		'TEL'     => 'Sabre\\VObject\\Property\\FlatText',
84
+		'EMAIL'   => 'Sabre\\VObject\\Property\\FlatText',
85
+		'MAILER'  => 'Sabre\\VObject\\Property\\FlatText', // Removed in vCard 4.0
86
+		'GEO'     => 'Sabre\\VObject\\Property\\FlatText',
87
+		'TITLE'   => 'Sabre\\VObject\\Property\\FlatText',
88
+		'ROLE'    => 'Sabre\\VObject\\Property\\FlatText',
89
+		'LOGO'    => 'Sabre\\VObject\\Property\\Binary',
90
+		// 'AGENT'   => 'Sabre\\VObject\\Property\\',      // Todo: is an embedded vCard. Probably rare, so
91
+								 // not supported at the moment
92
+		'ORG'     => 'Sabre\\VObject\\Property\\Text',
93
+		'NOTE'    => 'Sabre\\VObject\\Property\\FlatText',
94
+		'REV'     => 'Sabre\\VObject\\Property\\VCard\\TimeStamp',
95
+		'SOUND'   => 'Sabre\\VObject\\Property\\FlatText',
96
+		'URL'     => 'Sabre\\VObject\\Property\\Uri',
97
+		'UID'     => 'Sabre\\VObject\\Property\\FlatText',
98
+		'VERSION' => 'Sabre\\VObject\\Property\\FlatText',
99
+		'KEY'     => 'Sabre\\VObject\\Property\\FlatText',
100
+		'TZ'      => 'Sabre\\VObject\\Property\\Text',
101
+
102
+		// vCard 3.0 properties
103
+		'CATEGORIES'  => 'Sabre\\VObject\\Property\\Text',
104
+		'SORT-STRING' => 'Sabre\\VObject\\Property\\FlatText',
105
+		'PRODID'      => 'Sabre\\VObject\\Property\\FlatText',
106
+		'NICKNAME'    => 'Sabre\\VObject\\Property\\Text',
107
+		'CLASS'       => 'Sabre\\VObject\\Property\\FlatText', // Removed in vCard 4.0
108
+
109
+		// rfc2739 properties
110
+		'FBURL'        => 'Sabre\\VObject\\Property\\Uri',
111
+		'CAPURI'       => 'Sabre\\VObject\\Property\\Uri',
112
+		'CALURI'       => 'Sabre\\VObject\\Property\\Uri',
113
+		'CALADRURI'    => 'Sabre\\VObject\\Property\\Uri',
114
+
115
+		// rfc4770 properties
116
+		'IMPP'         => 'Sabre\\VObject\\Property\\Uri',
117
+
118
+		// vCard 4.0 properties
119
+		'SOURCE'       => 'Sabre\\VObject\\Property\\Uri',
120
+		'XML'          => 'Sabre\\VObject\\Property\\FlatText',
121
+		'ANNIVERSARY'  => 'Sabre\\VObject\\Property\\VCard\\DateAndOrTime',
122
+		'CLIENTPIDMAP' => 'Sabre\\VObject\\Property\\Text',
123
+		'LANG'         => 'Sabre\\VObject\\Property\\VCard\\LanguageTag',
124
+		'GENDER'       => 'Sabre\\VObject\\Property\\Text',
125
+		'KIND'         => 'Sabre\\VObject\\Property\\FlatText',
126
+		'MEMBER'       => 'Sabre\\VObject\\Property\\Uri',
127
+		'RELATED'      => 'Sabre\\VObject\\Property\\Uri',
128
+
129
+		// rfc6474 properties
130
+		'BIRTHPLACE'    => 'Sabre\\VObject\\Property\\FlatText',
131
+		'DEATHPLACE'    => 'Sabre\\VObject\\Property\\FlatText',
132
+		'DEATHDATE'     => 'Sabre\\VObject\\Property\\VCard\\DateAndOrTime',
133
+
134
+		// rfc6715 properties
135
+		'EXPERTISE'     => 'Sabre\\VObject\\Property\\FlatText',
136
+		'HOBBY'         => 'Sabre\\VObject\\Property\\FlatText',
137
+		'INTEREST'      => 'Sabre\\VObject\\Property\\FlatText',
138
+		'ORG-DIRECTORY' => 'Sabre\\VObject\\Property\\FlatText',
139
+
140
+	];
141
+
142
+	/**
143
+	 * Returns the current document type.
144
+	 *
145
+	 * @return int
146
+	 */
147
+	public function getDocumentType() {
148
+
149
+		if (!$this->version) {
150
+
151
+			$version = (string)$this->VERSION;
152
+
153
+			switch ($version) {
154
+				case '2.1' :
155
+					$this->version = self::VCARD21;
156
+					break;
157
+				case '3.0' :
158
+					$this->version = self::VCARD30;
159
+					break;
160
+				case '4.0' :
161
+					$this->version = self::VCARD40;
162
+					break;
163
+				default :
164
+					// We don't want to cache the version if it's unknown,
165
+					// because we might get a version property in a bit.
166
+					return self::UNKNOWN;
167
+			}
168
+		}
169
+
170
+		return $this->version;
171
+
172
+	}
173
+
174
+	/**
175
+	 * Converts the document to a different vcard version.
176
+	 *
177
+	 * Use one of the VCARD constants for the target. This method will return
178
+	 * a copy of the vcard in the new version.
179
+	 *
180
+	 * At the moment the only supported conversion is from 3.0 to 4.0.
181
+	 *
182
+	 * If input and output version are identical, a clone is returned.
183
+	 *
184
+	 * @param int $target
185
+	 *
186
+	 * @return VCard
187
+	 */
188
+	public function convert($target) {
189
+
190
+		$converter = new VObject\VCardConverter();
191
+		return $converter->convert($this, $target);
192
+
193
+	}
194
+
195
+	/**
196
+	 * VCards with version 2.1, 3.0 and 4.0 are found.
197
+	 *
198
+	 * If the VCARD doesn't know its version, 2.1 is assumed.
199
+	 */
200
+	const DEFAULT_VERSION = self::VCARD21;
201
+
202
+	/**
203
+	 * Validates the node for correctness.
204
+	 *
205
+	 * The following options are supported:
206
+	 *   Node::REPAIR - May attempt to automatically repair the problem.
207
+	 *
208
+	 * This method returns an array with detected problems.
209
+	 * Every element has the following properties:
210
+	 *
211
+	 *  * level - problem level.
212
+	 *  * message - A human-readable string describing the issue.
213
+	 *  * node - A reference to the problematic node.
214
+	 *
215
+	 * The level means:
216
+	 *   1 - The issue was repaired (only happens if REPAIR was turned on)
217
+	 *   2 - An inconsequential issue
218
+	 *   3 - A severe issue.
219
+	 *
220
+	 * @param int $options
221
+	 *
222
+	 * @return array
223
+	 */
224
+	public function validate($options = 0) {
225
+
226
+		$warnings = [];
227
+
228
+		$versionMap = [
229
+			self::VCARD21 => '2.1',
230
+			self::VCARD30 => '3.0',
231
+			self::VCARD40 => '4.0',
232
+		];
233
+
234
+		$version = $this->select('VERSION');
235
+		if (count($version) === 1) {
236
+			$version = (string)$this->VERSION;
237
+			if ($version !== '2.1' && $version !== '3.0' && $version !== '4.0') {
238
+				$warnings[] = [
239
+					'level'   => 3,
240
+					'message' => 'Only vcard version 4.0 (RFC6350), version 3.0 (RFC2426) or version 2.1 (icm-vcard-2.1) are supported.',
241
+					'node'    => $this,
242
+				];
243
+				if ($options & self::REPAIR) {
244
+					$this->VERSION = $versionMap[self::DEFAULT_VERSION];
245
+				}
246
+			}
247
+			if ($version === '2.1' && ($options & self::PROFILE_CARDDAV)) {
248
+				$warnings[] = [
249
+					'level'   => 3,
250
+					'message' => 'CardDAV servers are not allowed to accept vCard 2.1.',
251
+					'node'    => $this,
252
+				];
253
+			}
254
+
255
+		}
256
+		$uid = $this->select('UID');
257
+		if (count($uid) === 0) {
258
+			if ($options & self::PROFILE_CARDDAV) {
259
+				// Required for CardDAV
260
+				$warningLevel = 3;
261
+				$message = 'vCards on CardDAV servers MUST have a UID property.';
262
+			} else {
263
+				// Not required for regular vcards
264
+				$warningLevel = 2;
265
+				$message = 'Adding a UID to a vCard property is recommended.';
266
+			}
267
+			if ($options & self::REPAIR) {
268
+				$this->UID = VObject\UUIDUtil::getUUID();
269
+				$warningLevel = 1;
270
+			}
271
+			$warnings[] = [
272
+				'level'   => $warningLevel,
273
+				'message' => $message,
274
+				'node'    => $this,
275
+			];
276
+		}
277
+
278
+		$fn = $this->select('FN');
279
+		if (count($fn) !== 1) {
280
+
281
+			$repaired = false;
282
+			if (($options & self::REPAIR) && count($fn) === 0) {
283
+				// We're going to try to see if we can use the contents of the
284
+				// N property.
285
+				if (isset($this->N)) {
286
+					$value = explode(';', (string)$this->N);
287
+					if (isset($value[1]) && $value[1]) {
288
+						$this->FN = $value[1] . ' ' . $value[0];
289
+					} else {
290
+						$this->FN = $value[0];
291
+					}
292
+					$repaired = true;
293
+
294
+				// Otherwise, the ORG property may work
295
+				} elseif (isset($this->ORG)) {
296
+					$this->FN = (string)$this->ORG;
297
+					$repaired = true;
298
+				}
299
+
300
+			}
301
+			$warnings[] = [
302
+				'level'   => $repaired ? 1 : 3,
303
+				'message' => 'The FN property must appear in the VCARD component exactly 1 time',
304
+				'node'    => $this,
305
+			];
306
+		}
307
+
308
+		return array_merge(
309
+			parent::validate($options),
310
+			$warnings
311
+		);
312
+
313
+	}
314
+
315
+	/**
316
+	 * A simple list of validation rules.
317
+	 *
318
+	 * This is simply a list of properties, and how many times they either
319
+	 * must or must not appear.
320
+	 *
321
+	 * Possible values per property:
322
+	 *   * 0 - Must not appear.
323
+	 *   * 1 - Must appear exactly once.
324
+	 *   * + - Must appear at least once.
325
+	 *   * * - Can appear any number of times.
326
+	 *   * ? - May appear, but not more than once.
327
+	 *
328
+	 * @var array
329
+	 */
330
+	public function getValidationRules() {
331
+
332
+		return [
333
+			'ADR'          => '*',
334
+			'ANNIVERSARY'  => '?',
335
+			'BDAY'         => '?',
336
+			'CALADRURI'    => '*',
337
+			'CALURI'       => '*',
338
+			'CATEGORIES'   => '*',
339
+			'CLIENTPIDMAP' => '*',
340
+			'EMAIL'        => '*',
341
+			'FBURL'        => '*',
342
+			'IMPP'         => '*',
343
+			'GENDER'       => '?',
344
+			'GEO'          => '*',
345
+			'KEY'          => '*',
346
+			'KIND'         => '?',
347
+			'LANG'         => '*',
348
+			'LOGO'         => '*',
349
+			'MEMBER'       => '*',
350
+			'N'            => '?',
351
+			'NICKNAME'     => '*',
352
+			'NOTE'         => '*',
353
+			'ORG'          => '*',
354
+			'PHOTO'        => '*',
355
+			'PRODID'       => '?',
356
+			'RELATED'      => '*',
357
+			'REV'          => '?',
358
+			'ROLE'         => '*',
359
+			'SOUND'        => '*',
360
+			'SOURCE'       => '*',
361
+			'TEL'          => '*',
362
+			'TITLE'        => '*',
363
+			'TZ'           => '*',
364
+			'URL'          => '*',
365
+			'VERSION'      => '1',
366
+			'XML'          => '*',
367
+
368
+			// FN is commented out, because it's already handled by the
369
+			// validate function, which may also try to repair it.
370
+			// 'FN'           => '+',
371
+			'UID'          => '?',
372
+		];
373
+
374
+	}
375
+
376
+	/**
377
+	 * Returns a preferred field.
378
+	 *
379
+	 * VCards can indicate wether a field such as ADR, TEL or EMAIL is
380
+	 * preferred by specifying TYPE=PREF (vcard 2.1, 3) or PREF=x (vcard 4, x
381
+	 * being a number between 1 and 100).
382
+	 *
383
+	 * If neither of those parameters are specified, the first is returned, if
384
+	 * a field with that name does not exist, null is returned.
385
+	 *
386
+	 * @param string $fieldName
387
+	 *
388
+	 * @return VObject\Property|null
389
+	 */
390
+	public function preferred($propertyName) {
391
+
392
+		$preferred = null;
393
+		$lastPref = 101;
394
+		foreach ($this->select($propertyName) as $field) {
395
+
396
+			$pref = 101;
397
+			if (isset($field['TYPE']) && $field['TYPE']->has('PREF')) {
398
+				$pref = 1;
399
+			} elseif (isset($field['PREF'])) {
400
+				$pref = $field['PREF']->getValue();
401
+			}
402
+
403
+			if ($pref < $lastPref || is_null($preferred)) {
404
+				$preferred = $field;
405
+				$lastPref = $pref;
406
+			}
407
+
408
+		}
409
+		return $preferred;
410
+
411
+	}
412
+
413
+	/**
414
+	 * Returns a property with a specific TYPE value (ADR, TEL, or EMAIL).
415
+	 *
416
+	 * This function will return null if the property does not exist. If there are
417
+	 * multiple properties with the same TYPE value, only one will be returned.
418
+	 *
419
+	 * @param string $propertyName
420
+	 * @param string $type
421
+	 *
422
+	 * @return VObject\Property|null
423
+	 */
424
+	public function getByType($propertyName, $type) {
425
+		foreach ($this->select($propertyName) as $field) {
426
+			if (isset($field['TYPE']) && $field['TYPE']->has($type)) {
427
+				return $field;
428
+			}
429
+		}
430
+	}
431
+
432
+	/**
433
+	 * This method should return a list of default property values.
434
+	 *
435
+	 * @return array
436
+	 */
437
+	protected function getDefaults() {
438
+
439
+		return [
440
+			'VERSION' => '4.0',
441
+			'PRODID'  => '-//Sabre//Sabre VObject ' . VObject\Version::VERSION . '//EN',
442
+			'UID'     => 'sabre-vobject-' . VObject\UUIDUtil::getUUID(),
443
+		];
444
+
445
+	}
446
+
447
+	/**
448
+	 * This method returns an array, with the representation as it should be
449
+	 * encoded in json. This is used to create jCard or jCal documents.
450
+	 *
451
+	 * @return array
452
+	 */
453
+	public function jsonSerialize() {
454
+
455
+		// A vcard does not have sub-components, so we're overriding this
456
+		// method to remove that array element.
457
+		$properties = [];
458
+
459
+		foreach ($this->children() as $child) {
460
+			$properties[] = $child->jsonSerialize();
461
+		}
462
+
463
+		return [
464
+			strtolower($this->name),
465
+			$properties,
466
+		];
467
+
468
+	}
469
+
470
+	/**
471
+	 * This method serializes the data into XML. This is used to create xCard or
472
+	 * xCal documents.
473
+	 *
474
+	 * @param Xml\Writer $writer  XML writer.
475
+	 *
476
+	 * @return void
477
+	 */
478
+	public function xmlSerialize(Xml\Writer $writer) {
479
+
480
+		$propertiesByGroup = [];
481
+
482
+		foreach ($this->children() as $property) {
483
+
484
+			$group = $property->group;
485
+
486
+			if (!isset($propertiesByGroup[$group])) {
487
+				$propertiesByGroup[$group] = [];
488
+			}
489
+
490
+			$propertiesByGroup[$group][] = $property;
491
+
492
+		}
493
+
494
+		$writer->startElement(strtolower($this->name));
495
+
496
+		foreach ($propertiesByGroup as $group => $properties) {
497
+
498
+			if (!empty($group)) {
499
+
500
+				$writer->startElement('group');
501
+				$writer->writeAttribute('name', strtolower($group));
502 502
 
503
-            }
504
-
505
-            foreach ($properties as $property) {
506
-                switch ($property->name) {
503
+			}
504
+
505
+			foreach ($properties as $property) {
506
+				switch ($property->name) {
507 507
 
508
-                    case 'VERSION':
509
-                        continue;
508
+					case 'VERSION':
509
+						continue;
510 510
 
511
-                    case 'XML':
512
-                        $value = $property->getParts();
513
-                        $fragment = new Xml\Element\XmlFragment($value[0]);
514
-                        $writer->write($fragment);
515
-                        break;
516
-
517
-                    default:
518
-                        $property->xmlSerialize($writer);
519
-                        break;
511
+					case 'XML':
512
+						$value = $property->getParts();
513
+						$fragment = new Xml\Element\XmlFragment($value[0]);
514
+						$writer->write($fragment);
515
+						break;
516
+
517
+					default:
518
+						$property->xmlSerialize($writer);
519
+						break;
520 520
 
521
-                }
522
-            }
521
+				}
522
+			}
523 523
 
524
-            if (!empty($group)) {
525
-                $writer->endElement();
526
-            }
524
+			if (!empty($group)) {
525
+				$writer->endElement();
526
+			}
527 527
 
528
-        }
528
+		}
529 529
 
530
-        $writer->endElement();
530
+		$writer->endElement();
531 531
 
532
-    }
532
+	}
533 533
 
534
-    /**
535
-     * Returns the default class for a property name.
536
-     *
537
-     * @param string $propertyName
538
-     *
539
-     * @return string
540
-     */
541
-    public function getClassNameForPropertyName($propertyName) {
534
+	/**
535
+	 * Returns the default class for a property name.
536
+	 *
537
+	 * @param string $propertyName
538
+	 *
539
+	 * @return string
540
+	 */
541
+	public function getClassNameForPropertyName($propertyName) {
542 542
 
543
-        $className = parent::getClassNameForPropertyName($propertyName);
543
+		$className = parent::getClassNameForPropertyName($propertyName);
544 544
 
545
-        // In vCard 4, BINARY no longer exists, and we need URI instead.
546
-        if ($className == 'Sabre\\VObject\\Property\\Binary' && $this->getDocumentType() === self::VCARD40) {
547
-            return 'Sabre\\VObject\\Property\\Uri';
548
-        }
549
-        return $className;
545
+		// In vCard 4, BINARY no longer exists, and we need URI instead.
546
+		if ($className == 'Sabre\\VObject\\Property\\Binary' && $this->getDocumentType() === self::VCARD40) {
547
+			return 'Sabre\\VObject\\Property\\Uri';
548
+		}
549
+		return $className;
550 550
 
551
-    }
551
+	}
552 552
 
553 553
 }
Please login to merge, or discard this patch.
libraries/SabreDAV/VObject/Component/VEvent.php 1 patch
Indentation   +131 added lines, -131 removed lines patch added patch discarded remove patch
@@ -18,136 +18,136 @@
 block discarded – undo
18 18
  */
19 19
 class VEvent extends VObject\Component {
20 20
 
21
-    /**
22
-     * Returns true or false depending on if the event falls in the specified
23
-     * time-range. This is used for filtering purposes.
24
-     *
25
-     * The rules used to determine if an event falls within the specified
26
-     * time-range is based on the CalDAV specification.
27
-     *
28
-     * @param DateTimeInterface $start
29
-     * @param DateTimeInterface $end
30
-     *
31
-     * @return bool
32
-     */
33
-    public function isInTimeRange(DateTimeInterface $start, DateTimeInterface $end) {
34
-
35
-        if ($this->RRULE) {
36
-
37
-            try {
38
-
39
-                $it = new EventIterator($this, null, $start->getTimezone());
40
-
41
-            } catch (NoInstancesException $e) {
42
-
43
-                // If we've catched this exception, there are no instances
44
-                // for the event that fall into the specified time-range.
45
-                return false;
46
-
47
-            }
48
-
49
-            $it->fastForward($start);
50
-
51
-            // We fast-forwarded to a spot where the end-time of the
52
-            // recurrence instance exceeded the start of the requested
53
-            // time-range.
54
-            //
55
-            // If the starttime of the recurrence did not exceed the
56
-            // end of the time range as well, we have a match.
57
-            return ($it->getDTStart() < $end && $it->getDTEnd() > $start);
58
-
59
-        }
60
-
61
-        $effectiveStart = $this->DTSTART->getDateTime($start->getTimezone());
62
-        if (isset($this->DTEND)) {
63
-
64
-            // The DTEND property is considered non inclusive. So for a 3 day
65
-            // event in july, dtstart and dtend would have to be July 1st and
66
-            // July 4th respectively.
67
-            //
68
-            // See:
69
-            // http://tools.ietf.org/html/rfc5545#page-54
70
-            $effectiveEnd = $this->DTEND->getDateTime($end->getTimezone());
71
-
72
-        } elseif (isset($this->DURATION)) {
73
-            $effectiveEnd = $effectiveStart->add(VObject\DateTimeParser::parseDuration($this->DURATION));
74
-        } elseif (!$this->DTSTART->hasTime()) {
75
-            $effectiveEnd = $effectiveStart->modify('+1 day');
76
-        } else {
77
-            $effectiveEnd = $effectiveStart;
78
-        }
79
-        return (
80
-            ($start < $effectiveEnd) && ($end > $effectiveStart)
81
-        );
82
-
83
-    }
84
-
85
-    /**
86
-     * This method should return a list of default property values.
87
-     *
88
-     * @return array
89
-     */
90
-    protected function getDefaults() {
91
-
92
-        return [
93
-            'UID'     => 'sabre-vobject-' . VObject\UUIDUtil::getUUID(),
94
-            'DTSTAMP' => date('Ymd\\THis\\Z'),
95
-        ];
96
-
97
-    }
98
-
99
-    /**
100
-     * A simple list of validation rules.
101
-     *
102
-     * This is simply a list of properties, and how many times they either
103
-     * must or must not appear.
104
-     *
105
-     * Possible values per property:
106
-     *   * 0 - Must not appear.
107
-     *   * 1 - Must appear exactly once.
108
-     *   * + - Must appear at least once.
109
-     *   * * - Can appear any number of times.
110
-     *   * ? - May appear, but not more than once.
111
-     *
112
-     * @var array
113
-     */
114
-    public function getValidationRules() {
115
-
116
-        $hasMethod = isset($this->parent->METHOD);
117
-        return [
118
-            'UID'           => 1,
119
-            'DTSTAMP'       => 1,
120
-            'DTSTART'       => $hasMethod ? '?' : '1',
121
-            'CLASS'         => '?',
122
-            'CREATED'       => '?',
123
-            'DESCRIPTION'   => '?',
124
-            'GEO'           => '?',
125
-            'LAST-MODIFIED' => '?',
126
-            'LOCATION'      => '?',
127
-            'ORGANIZER'     => '?',
128
-            'PRIORITY'      => '?',
129
-            'SEQUENCE'      => '?',
130
-            'STATUS'        => '?',
131
-            'SUMMARY'       => '?',
132
-            'TRANSP'        => '?',
133
-            'URL'           => '?',
134
-            'RECURRENCE-ID' => '?',
135
-            'RRULE'         => '?',
136
-            'DTEND'         => '?',
137
-            'DURATION'      => '?',
138
-
139
-            'ATTACH'         => '*',
140
-            'ATTENDEE'       => '*',
141
-            'CATEGORIES'     => '*',
142
-            'COMMENT'        => '*',
143
-            'CONTACT'        => '*',
144
-            'EXDATE'         => '*',
145
-            'REQUEST-STATUS' => '*',
146
-            'RELATED-TO'     => '*',
147
-            'RESOURCES'      => '*',
148
-            'RDATE'          => '*',
149
-        ];
150
-
151
-    }
21
+	/**
22
+	 * Returns true or false depending on if the event falls in the specified
23
+	 * time-range. This is used for filtering purposes.
24
+	 *
25
+	 * The rules used to determine if an event falls within the specified
26
+	 * time-range is based on the CalDAV specification.
27
+	 *
28
+	 * @param DateTimeInterface $start
29
+	 * @param DateTimeInterface $end
30
+	 *
31
+	 * @return bool
32
+	 */
33
+	public function isInTimeRange(DateTimeInterface $start, DateTimeInterface $end) {
34
+
35
+		if ($this->RRULE) {
36
+
37
+			try {
38
+
39
+				$it = new EventIterator($this, null, $start->getTimezone());
40
+
41
+			} catch (NoInstancesException $e) {
42
+
43
+				// If we've catched this exception, there are no instances
44
+				// for the event that fall into the specified time-range.
45
+				return false;
46
+
47
+			}
48
+
49
+			$it->fastForward($start);
50
+
51
+			// We fast-forwarded to a spot where the end-time of the
52
+			// recurrence instance exceeded the start of the requested
53
+			// time-range.
54
+			//
55
+			// If the starttime of the recurrence did not exceed the
56
+			// end of the time range as well, we have a match.
57
+			return ($it->getDTStart() < $end && $it->getDTEnd() > $start);
58
+
59
+		}
60
+
61
+		$effectiveStart = $this->DTSTART->getDateTime($start->getTimezone());
62
+		if (isset($this->DTEND)) {
63
+
64
+			// The DTEND property is considered non inclusive. So for a 3 day
65
+			// event in july, dtstart and dtend would have to be July 1st and
66
+			// July 4th respectively.
67
+			//
68
+			// See:
69
+			// http://tools.ietf.org/html/rfc5545#page-54
70
+			$effectiveEnd = $this->DTEND->getDateTime($end->getTimezone());
71
+
72
+		} elseif (isset($this->DURATION)) {
73
+			$effectiveEnd = $effectiveStart->add(VObject\DateTimeParser::parseDuration($this->DURATION));
74
+		} elseif (!$this->DTSTART->hasTime()) {
75
+			$effectiveEnd = $effectiveStart->modify('+1 day');
76
+		} else {
77
+			$effectiveEnd = $effectiveStart;
78
+		}
79
+		return (
80
+			($start < $effectiveEnd) && ($end > $effectiveStart)
81
+		);
82
+
83
+	}
84
+
85
+	/**
86
+	 * This method should return a list of default property values.
87
+	 *
88
+	 * @return array
89
+	 */
90
+	protected function getDefaults() {
91
+
92
+		return [
93
+			'UID'     => 'sabre-vobject-' . VObject\UUIDUtil::getUUID(),
94
+			'DTSTAMP' => date('Ymd\\THis\\Z'),
95
+		];
96
+
97
+	}
98
+
99
+	/**
100
+	 * A simple list of validation rules.
101
+	 *
102
+	 * This is simply a list of properties, and how many times they either
103
+	 * must or must not appear.
104
+	 *
105
+	 * Possible values per property:
106
+	 *   * 0 - Must not appear.
107
+	 *   * 1 - Must appear exactly once.
108
+	 *   * + - Must appear at least once.
109
+	 *   * * - Can appear any number of times.
110
+	 *   * ? - May appear, but not more than once.
111
+	 *
112
+	 * @var array
113
+	 */
114
+	public function getValidationRules() {
115
+
116
+		$hasMethod = isset($this->parent->METHOD);
117
+		return [
118
+			'UID'           => 1,
119
+			'DTSTAMP'       => 1,
120
+			'DTSTART'       => $hasMethod ? '?' : '1',
121
+			'CLASS'         => '?',
122
+			'CREATED'       => '?',
123
+			'DESCRIPTION'   => '?',
124
+			'GEO'           => '?',
125
+			'LAST-MODIFIED' => '?',
126
+			'LOCATION'      => '?',
127
+			'ORGANIZER'     => '?',
128
+			'PRIORITY'      => '?',
129
+			'SEQUENCE'      => '?',
130
+			'STATUS'        => '?',
131
+			'SUMMARY'       => '?',
132
+			'TRANSP'        => '?',
133
+			'URL'           => '?',
134
+			'RECURRENCE-ID' => '?',
135
+			'RRULE'         => '?',
136
+			'DTEND'         => '?',
137
+			'DURATION'      => '?',
138
+
139
+			'ATTACH'         => '*',
140
+			'ATTENDEE'       => '*',
141
+			'CATEGORIES'     => '*',
142
+			'COMMENT'        => '*',
143
+			'CONTACT'        => '*',
144
+			'EXDATE'         => '*',
145
+			'REQUEST-STATUS' => '*',
146
+			'RELATED-TO'     => '*',
147
+			'RESOURCES'      => '*',
148
+			'RDATE'          => '*',
149
+		];
150
+
151
+	}
152 152
 
153 153
 }
Please login to merge, or discard this patch.
libraries/SabreDAV/VObject/Component/VTimeZone.php 1 patch
Indentation   +40 added lines, -40 removed lines patch added patch discarded remove patch
@@ -16,52 +16,52 @@
 block discarded – undo
16 16
  */
17 17
 class VTimeZone extends VObject\Component {
18 18
 
19
-    /**
20
-     * Returns the PHP DateTimeZone for this VTIMEZONE component.
21
-     *
22
-     * If we can't accurately determine the timezone, this method will return
23
-     * UTC.
24
-     *
25
-     * @return \DateTimeZone
26
-     */
27
-    public function getTimeZone() {
19
+	/**
20
+	 * Returns the PHP DateTimeZone for this VTIMEZONE component.
21
+	 *
22
+	 * If we can't accurately determine the timezone, this method will return
23
+	 * UTC.
24
+	 *
25
+	 * @return \DateTimeZone
26
+	 */
27
+	public function getTimeZone() {
28 28
 
29
-        return VObject\TimeZoneUtil::getTimeZone((string)$this->TZID, $this->root);
29
+		return VObject\TimeZoneUtil::getTimeZone((string)$this->TZID, $this->root);
30 30
 
31
-    }
31
+	}
32 32
 
33
-    /**
34
-     * A simple list of validation rules.
35
-     *
36
-     * This is simply a list of properties, and how many times they either
37
-     * must or must not appear.
38
-     *
39
-     * Possible values per property:
40
-     *   * 0 - Must not appear.
41
-     *   * 1 - Must appear exactly once.
42
-     *   * + - Must appear at least once.
43
-     *   * * - Can appear any number of times.
44
-     *   * ? - May appear, but not more than once.
45
-     *
46
-     * @var array
47
-     */
48
-    public function getValidationRules() {
33
+	/**
34
+	 * A simple list of validation rules.
35
+	 *
36
+	 * This is simply a list of properties, and how many times they either
37
+	 * must or must not appear.
38
+	 *
39
+	 * Possible values per property:
40
+	 *   * 0 - Must not appear.
41
+	 *   * 1 - Must appear exactly once.
42
+	 *   * + - Must appear at least once.
43
+	 *   * * - Can appear any number of times.
44
+	 *   * ? - May appear, but not more than once.
45
+	 *
46
+	 * @var array
47
+	 */
48
+	public function getValidationRules() {
49 49
 
50
-        return [
51
-            'TZID' => 1,
50
+		return [
51
+			'TZID' => 1,
52 52
 
53
-            'LAST-MODIFIED' => '?',
54
-            'TZURL'         => '?',
53
+			'LAST-MODIFIED' => '?',
54
+			'TZURL'         => '?',
55 55
 
56
-            // At least 1 STANDARD or DAYLIGHT must appear, or more. But both
57
-            // cannot appear in the same VTIMEZONE.
58
-            //
59
-            // The validator is not specific yet to pick this up, so these
60
-            // rules are too loose.
61
-            'STANDARD' => '*',
62
-            'DAYLIGHT' => '*',
63
-        ];
56
+			// At least 1 STANDARD or DAYLIGHT must appear, or more. But both
57
+			// cannot appear in the same VTIMEZONE.
58
+			//
59
+			// The validator is not specific yet to pick this up, so these
60
+			// rules are too loose.
61
+			'STANDARD' => '*',
62
+			'DAYLIGHT' => '*',
63
+		];
64 64
 
65
-    }
65
+	}
66 66
 
67 67
 }
Please login to merge, or discard this patch.
libraries/SabreDAV/VObject/Component/VCalendar.php 1 patch
Indentation   +534 added lines, -534 removed lines patch added patch discarded remove patch
@@ -22,540 +22,540 @@
 block discarded – undo
22 22
  */
23 23
 class VCalendar extends VObject\Document {
24 24
 
25
-    /**
26
-     * The default name for this component.
27
-     *
28
-     * This should be 'VCALENDAR' or 'VCARD'.
29
-     *
30
-     * @var string
31
-     */
32
-    static $defaultName = 'VCALENDAR';
33
-
34
-    /**
35
-     * This is a list of components, and which classes they should map to.
36
-     *
37
-     * @var array
38
-     */
39
-    static $componentMap = [
40
-        'VCALENDAR'     => 'Sabre\\VObject\\Component\\VCalendar',
41
-        'VALARM'        => 'Sabre\\VObject\\Component\\VAlarm',
42
-        'VEVENT'        => 'Sabre\\VObject\\Component\\VEvent',
43
-        'VFREEBUSY'     => 'Sabre\\VObject\\Component\\VFreeBusy',
44
-        'VAVAILABILITY' => 'Sabre\\VObject\\Component\\VAvailability',
45
-        'AVAILABLE'     => 'Sabre\\VObject\\Component\\Available',
46
-        'VJOURNAL'      => 'Sabre\\VObject\\Component\\VJournal',
47
-        'VTIMEZONE'     => 'Sabre\\VObject\\Component\\VTimeZone',
48
-        'VTODO'         => 'Sabre\\VObject\\Component\\VTodo',
49
-    ];
50
-
51
-    /**
52
-     * List of value-types, and which classes they map to.
53
-     *
54
-     * @var array
55
-     */
56
-    static $valueMap = [
57
-        'BINARY'           => 'Sabre\\VObject\\Property\\Binary',
58
-        'BOOLEAN'          => 'Sabre\\VObject\\Property\\Boolean',
59
-        'CAL-ADDRESS'      => 'Sabre\\VObject\\Property\\ICalendar\\CalAddress',
60
-        'DATE'             => 'Sabre\\VObject\\Property\\ICalendar\\Date',
61
-        'DATE-TIME'        => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
62
-        'DURATION'         => 'Sabre\\VObject\\Property\\ICalendar\\Duration',
63
-        'FLOAT'            => 'Sabre\\VObject\\Property\\FloatValue',
64
-        'INTEGER'          => 'Sabre\\VObject\\Property\\IntegerValue',
65
-        'PERIOD'           => 'Sabre\\VObject\\Property\\ICalendar\\Period',
66
-        'RECUR'            => 'Sabre\\VObject\\Property\\ICalendar\\Recur',
67
-        'TEXT'             => 'Sabre\\VObject\\Property\\Text',
68
-        'TIME'             => 'Sabre\\VObject\\Property\\Time',
69
-        'UNKNOWN'          => 'Sabre\\VObject\\Property\\Unknown', // jCard / jCal-only.
70
-        'URI'              => 'Sabre\\VObject\\Property\\Uri',
71
-        'UTC-OFFSET'       => 'Sabre\\VObject\\Property\\UtcOffset',
72
-    ];
73
-
74
-    /**
75
-     * List of properties, and which classes they map to.
76
-     *
77
-     * @var array
78
-     */
79
-    static $propertyMap = [
80
-        // Calendar properties
81
-        'CALSCALE'      => 'Sabre\\VObject\\Property\\FlatText',
82
-        'METHOD'        => 'Sabre\\VObject\\Property\\FlatText',
83
-        'PRODID'        => 'Sabre\\VObject\\Property\\FlatText',
84
-        'VERSION'       => 'Sabre\\VObject\\Property\\FlatText',
85
-
86
-        // Component properties
87
-        'ATTACH'            => 'Sabre\\VObject\\Property\\Uri',
88
-        'CATEGORIES'        => 'Sabre\\VObject\\Property\\Text',
89
-        'CLASS'             => 'Sabre\\VObject\\Property\\FlatText',
90
-        'COMMENT'           => 'Sabre\\VObject\\Property\\FlatText',
91
-        'DESCRIPTION'       => 'Sabre\\VObject\\Property\\FlatText',
92
-        'GEO'               => 'Sabre\\VObject\\Property\\FloatValue',
93
-        'LOCATION'          => 'Sabre\\VObject\\Property\\FlatText',
94
-        'PERCENT-COMPLETE'  => 'Sabre\\VObject\\Property\\IntegerValue',
95
-        'PRIORITY'          => 'Sabre\\VObject\\Property\\IntegerValue',
96
-        'RESOURCES'         => 'Sabre\\VObject\\Property\\Text',
97
-        'STATUS'            => 'Sabre\\VObject\\Property\\FlatText',
98
-        'SUMMARY'           => 'Sabre\\VObject\\Property\\FlatText',
99
-
100
-        // Date and Time Component Properties
101
-        'COMPLETED'     => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
102
-        'DTEND'         => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
103
-        'DUE'           => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
104
-        'DTSTART'       => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
105
-        'DURATION'      => 'Sabre\\VObject\\Property\\ICalendar\\Duration',
106
-        'FREEBUSY'      => 'Sabre\\VObject\\Property\\ICalendar\\Period',
107
-        'TRANSP'        => 'Sabre\\VObject\\Property\\FlatText',
108
-
109
-        // Time Zone Component Properties
110
-        'TZID'          => 'Sabre\\VObject\\Property\\FlatText',
111
-        'TZNAME'        => 'Sabre\\VObject\\Property\\FlatText',
112
-        'TZOFFSETFROM'  => 'Sabre\\VObject\\Property\\UtcOffset',
113
-        'TZOFFSETTO'    => 'Sabre\\VObject\\Property\\UtcOffset',
114
-        'TZURL'         => 'Sabre\\VObject\\Property\\Uri',
115
-
116
-        // Relationship Component Properties
117
-        'ATTENDEE'      => 'Sabre\\VObject\\Property\\ICalendar\\CalAddress',
118
-        'CONTACT'       => 'Sabre\\VObject\\Property\\FlatText',
119
-        'ORGANIZER'     => 'Sabre\\VObject\\Property\\ICalendar\\CalAddress',
120
-        'RECURRENCE-ID' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
121
-        'RELATED-TO'    => 'Sabre\\VObject\\Property\\FlatText',
122
-        'URL'           => 'Sabre\\VObject\\Property\\Uri',
123
-        'UID'           => 'Sabre\\VObject\\Property\\FlatText',
124
-
125
-        // Recurrence Component Properties
126
-        'EXDATE'        => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
127
-        'RDATE'         => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
128
-        'RRULE'         => 'Sabre\\VObject\\Property\\ICalendar\\Recur',
129
-        'EXRULE'        => 'Sabre\\VObject\\Property\\ICalendar\\Recur', // Deprecated since rfc5545
130
-
131
-        // Alarm Component Properties
132
-        'ACTION'        => 'Sabre\\VObject\\Property\\FlatText',
133
-        'REPEAT'        => 'Sabre\\VObject\\Property\\IntegerValue',
134
-        'TRIGGER'       => 'Sabre\\VObject\\Property\\ICalendar\\Duration',
135
-
136
-        // Change Management Component Properties
137
-        'CREATED'       => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
138
-        'DTSTAMP'       => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
139
-        'LAST-MODIFIED' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
140
-        'SEQUENCE'      => 'Sabre\\VObject\\Property\\IntegerValue',
141
-
142
-        // Request Status
143
-        'REQUEST-STATUS' => 'Sabre\\VObject\\Property\\Text',
144
-
145
-        // Additions from draft-daboo-valarm-extensions-04
146
-        'ALARM-AGENT'    => 'Sabre\\VObject\\Property\\Text',
147
-        'ACKNOWLEDGED'   => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
148
-        'PROXIMITY'      => 'Sabre\\VObject\\Property\\Text',
149
-        'DEFAULT-ALARM'  => 'Sabre\\VObject\\Property\\Boolean',
150
-
151
-        // Additions from draft-daboo-calendar-availability-05
152
-        'BUSYTYPE'       => 'Sabre\\VObject\\Property\\Text',
153
-
154
-    ];
155
-
156
-    /**
157
-     * Returns the current document type.
158
-     *
159
-     * @return int
160
-     */
161
-    public function getDocumentType() {
162
-
163
-        return self::ICALENDAR20;
164
-
165
-    }
166
-
167
-    /**
168
-     * Returns a list of all 'base components'. For instance, if an Event has
169
-     * a recurrence rule, and one instance is overridden, the overridden event
170
-     * will have the same UID, but will be excluded from this list.
171
-     *
172
-     * VTIMEZONE components will always be excluded.
173
-     *
174
-     * @param string $componentName filter by component name
175
-     *
176
-     * @return VObject\Component[]
177
-     */
178
-    public function getBaseComponents($componentName = null) {
179
-
180
-        $isBaseComponent = function($component) {
181
-
182
-            if (!$component instanceof VObject\Component) {
183
-                return false;
184
-            }
185
-            if ($component->name === 'VTIMEZONE') {
186
-                return false;
187
-            }
188
-            if (isset($component->{'RECURRENCE-ID'})) {
189
-                return false;
190
-            }
191
-            return true;
192
-
193
-        };
194
-
195
-        if ($componentName) {
196
-            // Early exit
197
-            return array_filter(
198
-                $this->select($componentName),
199
-                $isBaseComponent
200
-            );
201
-        }
202
-
203
-        $components = [];
204
-        foreach ($this->children as $childGroup) {
205
-
206
-            foreach ($childGroup as $child) {
207
-
208
-                if (!$child instanceof Component) {
209
-                    // If one child is not a component, they all are so we skip
210
-                    // the entire group.
211
-                    continue 2;
212
-                }
213
-                if ($isBaseComponent($child)) {
214
-                    $components[] = $child;
215
-                }
216
-
217
-            }
218
-
219
-        }
220
-        return $components;
221
-
222
-    }
223
-
224
-    /**
225
-     * Returns the first component that is not a VTIMEZONE, and does not have
226
-     * an RECURRENCE-ID.
227
-     *
228
-     * If there is no such component, null will be returned.
229
-     *
230
-     * @param string $componentName filter by component name
231
-     *
232
-     * @return VObject\Component|null
233
-     */
234
-    public function getBaseComponent($componentName = null) {
235
-
236
-        $isBaseComponent = function($component) {
237
-
238
-            if (!$component instanceof VObject\Component) {
239
-                return false;
240
-            }
241
-            if ($component->name === 'VTIMEZONE') {
242
-                return false;
243
-            }
244
-            if (isset($component->{'RECURRENCE-ID'})) {
245
-                return false;
246
-            }
247
-            return true;
248
-
249
-        };
250
-
251
-        if ($componentName) {
252
-            foreach ($this->select($componentName) as $child) {
253
-                if ($isBaseComponent($child)) {
254
-                    return $child;
255
-                }
256
-            }
257
-            return null;
258
-        }
259
-
260
-        // Searching all components
261
-        foreach ($this->children as $childGroup) {
262
-            foreach ($childGroup as $child) {
263
-                if ($isBaseComponent($child)) {
264
-                    return $child;
265
-                }
266
-            }
267
-
268
-        }
269
-        return null;
270
-
271
-    }
272
-
273
-    /**
274
-     * Expand all events in this VCalendar object and return a new VCalendar
275
-     * with the expanded events.
276
-     *
277
-     * If this calendar object, has events with recurrence rules, this method
278
-     * can be used to expand the event into multiple sub-events.
279
-     *
280
-     * Each event will be stripped from it's recurrence information, and only
281
-     * the instances of the event in the specified timerange will be left
282
-     * alone.
283
-     *
284
-     * In addition, this method will cause timezone information to be stripped,
285
-     * and normalized to UTC.
286
-     *
287
-     * @param DateTimeInterface $start
288
-     * @param DateTimeInterface $end
289
-     * @param DateTimeZone $timeZone reference timezone for floating dates and
290
-     *                     times.
291
-     * @return VCalendar
292
-     */
293
-    public function expand(DateTimeInterface $start, DateTimeInterface $end, DateTimeZone $timeZone = null) {
294
-
295
-        $newChildren = [];
296
-        $recurringEvents = [];
297
-
298
-        if (!$timeZone) {
299
-            $timeZone = new DateTimeZone('UTC');
300
-        }
301
-
302
-        $stripTimezones = function(Component $component) use ($timeZone, &$stripTimezones) {
303
-
304
-            foreach ($component->children() as $componentChild) {
305
-                if ($componentChild instanceof Property\ICalendar\DateTime && $componentChild->hasTime()) {
306
-
307
-                    $dt = $componentChild->getDateTimes($timeZone);
308
-                    // We only need to update the first timezone, because
309
-                    // setDateTimes will match all other timezones to the
310
-                    // first.
311
-                    $dt[0] = $dt[0]->setTimeZone(new DateTimeZone('UTC'));
312
-                    $componentChild->setDateTimes($dt);
313
-                } elseif ($componentChild instanceof Component) {
314
-                    $stripTimezones($componentChild);
315
-                }
316
-
317
-            }
318
-            return $component;
319
-
320
-        };
321
-
322
-        foreach ($this->children() as $child) {
323
-
324
-            if ($child instanceof Property && $child->name !== 'PRODID') {
325
-                // We explictly want to ignore PRODID, because we want to
326
-                // overwrite it with our own.
327
-                $newChildren[] = clone $child;
328
-            } elseif ($child instanceof Component && $child->name !== 'VTIMEZONE') {
329
-
330
-                // We're also stripping all VTIMEZONE objects because we're
331
-                // converting everything to UTC.
332
-                if ($child->name === 'VEVENT' && (isset($child->{'RECURRENCE-ID'}) || isset($child->RRULE) || isset($child->RDATE))) {
333
-                    // Handle these a bit later.
334
-                    $uid = (string)$child->UID;
335
-                    if (!$uid) {
336
-                        throw new InvalidDataException('Every VEVENT object must have a UID property');
337
-                    }
338
-                    if (isset($recurringEvents[$uid])) {
339
-                        $recurringEvents[$uid][] = clone $child;
340
-                    } else {
341
-                        $recurringEvents[$uid] = [clone $child];
342
-                    }
343
-                } elseif ($child->name === 'VEVENT' && $child->isInTimeRange($start, $end)) {
344
-                    $newChildren[] = $stripTimezones(clone $child);
345
-                }
346
-
347
-            }
348
-
349
-        }
350
-
351
-        foreach ($recurringEvents as $events) {
352
-
353
-            try {
354
-                $it = new EventIterator($events, $timeZone);
355
-
356
-            } catch (NoInstancesException $e) {
357
-                // This event is recurring, but it doesn't have a single
358
-                // instance. We are skipping this event from the output
359
-                // entirely.
360
-                continue;
361
-            }
362
-            $it->fastForward($start);
363
-
364
-            while ($it->valid() && $it->getDTStart() < $end) {
365
-
366
-                if ($it->getDTEnd() > $start) {
367
-
368
-                    $newChildren[] = $stripTimezones($it->getEventObject());
369
-
370
-                }
371
-                $it->next();
372
-
373
-            }
374
-
375
-        }
376
-
377
-        return new self($newChildren);
378
-
379
-    }
380
-
381
-    /**
382
-     * This method should return a list of default property values.
383
-     *
384
-     * @return array
385
-     */
386
-    protected function getDefaults() {
387
-
388
-        return [
389
-            'VERSION'  => '2.0',
390
-            'PRODID'   => '-//Sabre//Sabre VObject ' . VObject\Version::VERSION . '//EN',
391
-            'CALSCALE' => 'GREGORIAN',
392
-        ];
393
-
394
-    }
395
-
396
-    /**
397
-     * A simple list of validation rules.
398
-     *
399
-     * This is simply a list of properties, and how many times they either
400
-     * must or must not appear.
401
-     *
402
-     * Possible values per property:
403
-     *   * 0 - Must not appear.
404
-     *   * 1 - Must appear exactly once.
405
-     *   * + - Must appear at least once.
406
-     *   * * - Can appear any number of times.
407
-     *   * ? - May appear, but not more than once.
408
-     *
409
-     * @var array
410
-     */
411
-    public function getValidationRules() {
412
-
413
-        return [
414
-            'PRODID'  => 1,
415
-            'VERSION' => 1,
416
-
417
-            'CALSCALE' => '?',
418
-            'METHOD'   => '?',
419
-        ];
420
-
421
-    }
422
-
423
-    /**
424
-     * Validates the node for correctness.
425
-     *
426
-     * The following options are supported:
427
-     *   Node::REPAIR - May attempt to automatically repair the problem.
428
-     *   Node::PROFILE_CARDDAV - Validate the vCard for CardDAV purposes.
429
-     *   Node::PROFILE_CALDAV - Validate the iCalendar for CalDAV purposes.
430
-     *
431
-     * This method returns an array with detected problems.
432
-     * Every element has the following properties:
433
-     *
434
-     *  * level - problem level.
435
-     *  * message - A human-readable string describing the issue.
436
-     *  * node - A reference to the problematic node.
437
-     *
438
-     * The level means:
439
-     *   1 - The issue was repaired (only happens if REPAIR was turned on).
440
-     *   2 - A warning.
441
-     *   3 - An error.
442
-     *
443
-     * @param int $options
444
-     *
445
-     * @return array
446
-     */
447
-    public function validate($options = 0) {
448
-
449
-        $warnings = parent::validate($options);
450
-
451
-        if ($ver = $this->VERSION) {
452
-            if ((string)$ver !== '2.0') {
453
-                $warnings[] = [
454
-                    'level'   => 3,
455
-                    'message' => 'Only iCalendar version 2.0 as defined in rfc5545 is supported.',
456
-                    'node'    => $this,
457
-                ];
458
-            }
459
-
460
-        }
461
-
462
-        $uidList = [];
463
-        $componentsFound = 0;
464
-        $componentTypes = [];
465
-
466
-        foreach ($this->children() as $child) {
467
-            if ($child instanceof Component) {
468
-                $componentsFound++;
469
-
470
-                if (!in_array($child->name, ['VEVENT', 'VTODO', 'VJOURNAL'])) {
471
-                    continue;
472
-                }
473
-                $componentTypes[] = $child->name;
474
-
475
-                $uid = (string)$child->UID;
476
-                $isMaster = isset($child->{'RECURRENCE-ID'}) ? 0 : 1;
477
-                if (isset($uidList[$uid])) {
478
-                    $uidList[$uid]['count']++;
479
-                    if ($isMaster && $uidList[$uid]['hasMaster']) {
480
-                        $warnings[] = [
481
-                            'level'   => 3,
482
-                            'message' => 'More than one master object was found for the object with UID ' . $uid,
483
-                            'node'    => $this,
484
-                        ];
485
-                    }
486
-                    $uidList[$uid]['hasMaster'] += $isMaster;
487
-                } else {
488
-                    $uidList[$uid] = [
489
-                        'count'     => 1,
490
-                        'hasMaster' => $isMaster,
491
-                    ];
492
-                }
493
-
494
-            }
495
-        }
496
-
497
-        if ($componentsFound === 0) {
498
-            $warnings[] = [
499
-                'level'   => 3,
500
-                'message' => 'An iCalendar object must have at least 1 component.',
501
-                'node'    => $this,
502
-            ];
503
-        }
504
-
505
-        if ($options & self::PROFILE_CALDAV) {
506
-            if (count($uidList) > 1) {
507
-                $warnings[] = [
508
-                    'level'   => 3,
509
-                    'message' => 'A calendar object on a CalDAV server may only have components with the same UID.',
510
-                    'node'    => $this,
511
-                ];
512
-            }
513
-            if (count($componentTypes) === 0) {
514
-                $warnings[] = [
515
-                    'level'   => 3,
516
-                    'message' => 'A calendar object on a CalDAV server must have at least 1 component (VTODO, VEVENT, VJOURNAL).',
517
-                    'node'    => $this,
518
-                ];
519
-            }
520
-            if (count(array_unique($componentTypes)) > 1) {
521
-                $warnings[] = [
522
-                    'level'   => 3,
523
-                    'message' => 'A calendar object on a CalDAV server may only have 1 type of component (VEVENT, VTODO or VJOURNAL).',
524
-                    'node'    => $this,
525
-                ];
526
-            }
527
-
528
-            if (isset($this->METHOD)) {
529
-                $warnings[] = [
530
-                    'level'   => 3,
531
-                    'message' => 'A calendar object on a CalDAV server MUST NOT have a METHOD property.',
532
-                    'node'    => $this,
533
-                ];
534
-            }
535
-        }
536
-
537
-        return $warnings;
538
-
539
-    }
540
-
541
-    /**
542
-     * Returns all components with a specific UID value.
543
-     *
544
-     * @return array
545
-     */
546
-    public function getByUID($uid) {
547
-
548
-        return array_filter($this->getComponents(), function($item) use ($uid) {
549
-
550
-            if (!$itemUid = $item->select('UID')) {
551
-                return false;
552
-            }
553
-            $itemUid = current($itemUid)->getValue();
554
-            return $uid === $itemUid;
555
-
556
-        });
557
-
558
-    }
25
+	/**
26
+	 * The default name for this component.
27
+	 *
28
+	 * This should be 'VCALENDAR' or 'VCARD'.
29
+	 *
30
+	 * @var string
31
+	 */
32
+	static $defaultName = 'VCALENDAR';
33
+
34
+	/**
35
+	 * This is a list of components, and which classes they should map to.
36
+	 *
37
+	 * @var array
38
+	 */
39
+	static $componentMap = [
40
+		'VCALENDAR'     => 'Sabre\\VObject\\Component\\VCalendar',
41
+		'VALARM'        => 'Sabre\\VObject\\Component\\VAlarm',
42
+		'VEVENT'        => 'Sabre\\VObject\\Component\\VEvent',
43
+		'VFREEBUSY'     => 'Sabre\\VObject\\Component\\VFreeBusy',
44
+		'VAVAILABILITY' => 'Sabre\\VObject\\Component\\VAvailability',
45
+		'AVAILABLE'     => 'Sabre\\VObject\\Component\\Available',
46
+		'VJOURNAL'      => 'Sabre\\VObject\\Component\\VJournal',
47
+		'VTIMEZONE'     => 'Sabre\\VObject\\Component\\VTimeZone',
48
+		'VTODO'         => 'Sabre\\VObject\\Component\\VTodo',
49
+	];
50
+
51
+	/**
52
+	 * List of value-types, and which classes they map to.
53
+	 *
54
+	 * @var array
55
+	 */
56
+	static $valueMap = [
57
+		'BINARY'           => 'Sabre\\VObject\\Property\\Binary',
58
+		'BOOLEAN'          => 'Sabre\\VObject\\Property\\Boolean',
59
+		'CAL-ADDRESS'      => 'Sabre\\VObject\\Property\\ICalendar\\CalAddress',
60
+		'DATE'             => 'Sabre\\VObject\\Property\\ICalendar\\Date',
61
+		'DATE-TIME'        => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
62
+		'DURATION'         => 'Sabre\\VObject\\Property\\ICalendar\\Duration',
63
+		'FLOAT'            => 'Sabre\\VObject\\Property\\FloatValue',
64
+		'INTEGER'          => 'Sabre\\VObject\\Property\\IntegerValue',
65
+		'PERIOD'           => 'Sabre\\VObject\\Property\\ICalendar\\Period',
66
+		'RECUR'            => 'Sabre\\VObject\\Property\\ICalendar\\Recur',
67
+		'TEXT'             => 'Sabre\\VObject\\Property\\Text',
68
+		'TIME'             => 'Sabre\\VObject\\Property\\Time',
69
+		'UNKNOWN'          => 'Sabre\\VObject\\Property\\Unknown', // jCard / jCal-only.
70
+		'URI'              => 'Sabre\\VObject\\Property\\Uri',
71
+		'UTC-OFFSET'       => 'Sabre\\VObject\\Property\\UtcOffset',
72
+	];
73
+
74
+	/**
75
+	 * List of properties, and which classes they map to.
76
+	 *
77
+	 * @var array
78
+	 */
79
+	static $propertyMap = [
80
+		// Calendar properties
81
+		'CALSCALE'      => 'Sabre\\VObject\\Property\\FlatText',
82
+		'METHOD'        => 'Sabre\\VObject\\Property\\FlatText',
83
+		'PRODID'        => 'Sabre\\VObject\\Property\\FlatText',
84
+		'VERSION'       => 'Sabre\\VObject\\Property\\FlatText',
85
+
86
+		// Component properties
87
+		'ATTACH'            => 'Sabre\\VObject\\Property\\Uri',
88
+		'CATEGORIES'        => 'Sabre\\VObject\\Property\\Text',
89
+		'CLASS'             => 'Sabre\\VObject\\Property\\FlatText',
90
+		'COMMENT'           => 'Sabre\\VObject\\Property\\FlatText',
91
+		'DESCRIPTION'       => 'Sabre\\VObject\\Property\\FlatText',
92
+		'GEO'               => 'Sabre\\VObject\\Property\\FloatValue',
93
+		'LOCATION'          => 'Sabre\\VObject\\Property\\FlatText',
94
+		'PERCENT-COMPLETE'  => 'Sabre\\VObject\\Property\\IntegerValue',
95
+		'PRIORITY'          => 'Sabre\\VObject\\Property\\IntegerValue',
96
+		'RESOURCES'         => 'Sabre\\VObject\\Property\\Text',
97
+		'STATUS'            => 'Sabre\\VObject\\Property\\FlatText',
98
+		'SUMMARY'           => 'Sabre\\VObject\\Property\\FlatText',
99
+
100
+		// Date and Time Component Properties
101
+		'COMPLETED'     => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
102
+		'DTEND'         => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
103
+		'DUE'           => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
104
+		'DTSTART'       => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
105
+		'DURATION'      => 'Sabre\\VObject\\Property\\ICalendar\\Duration',
106
+		'FREEBUSY'      => 'Sabre\\VObject\\Property\\ICalendar\\Period',
107
+		'TRANSP'        => 'Sabre\\VObject\\Property\\FlatText',
108
+
109
+		// Time Zone Component Properties
110
+		'TZID'          => 'Sabre\\VObject\\Property\\FlatText',
111
+		'TZNAME'        => 'Sabre\\VObject\\Property\\FlatText',
112
+		'TZOFFSETFROM'  => 'Sabre\\VObject\\Property\\UtcOffset',
113
+		'TZOFFSETTO'    => 'Sabre\\VObject\\Property\\UtcOffset',
114
+		'TZURL'         => 'Sabre\\VObject\\Property\\Uri',
115
+
116
+		// Relationship Component Properties
117
+		'ATTENDEE'      => 'Sabre\\VObject\\Property\\ICalendar\\CalAddress',
118
+		'CONTACT'       => 'Sabre\\VObject\\Property\\FlatText',
119
+		'ORGANIZER'     => 'Sabre\\VObject\\Property\\ICalendar\\CalAddress',
120
+		'RECURRENCE-ID' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
121
+		'RELATED-TO'    => 'Sabre\\VObject\\Property\\FlatText',
122
+		'URL'           => 'Sabre\\VObject\\Property\\Uri',
123
+		'UID'           => 'Sabre\\VObject\\Property\\FlatText',
124
+
125
+		// Recurrence Component Properties
126
+		'EXDATE'        => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
127
+		'RDATE'         => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
128
+		'RRULE'         => 'Sabre\\VObject\\Property\\ICalendar\\Recur',
129
+		'EXRULE'        => 'Sabre\\VObject\\Property\\ICalendar\\Recur', // Deprecated since rfc5545
130
+
131
+		// Alarm Component Properties
132
+		'ACTION'        => 'Sabre\\VObject\\Property\\FlatText',
133
+		'REPEAT'        => 'Sabre\\VObject\\Property\\IntegerValue',
134
+		'TRIGGER'       => 'Sabre\\VObject\\Property\\ICalendar\\Duration',
135
+
136
+		// Change Management Component Properties
137
+		'CREATED'       => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
138
+		'DTSTAMP'       => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
139
+		'LAST-MODIFIED' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
140
+		'SEQUENCE'      => 'Sabre\\VObject\\Property\\IntegerValue',
141
+
142
+		// Request Status
143
+		'REQUEST-STATUS' => 'Sabre\\VObject\\Property\\Text',
144
+
145
+		// Additions from draft-daboo-valarm-extensions-04
146
+		'ALARM-AGENT'    => 'Sabre\\VObject\\Property\\Text',
147
+		'ACKNOWLEDGED'   => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
148
+		'PROXIMITY'      => 'Sabre\\VObject\\Property\\Text',
149
+		'DEFAULT-ALARM'  => 'Sabre\\VObject\\Property\\Boolean',
150
+
151
+		// Additions from draft-daboo-calendar-availability-05
152
+		'BUSYTYPE'       => 'Sabre\\VObject\\Property\\Text',
153
+
154
+	];
155
+
156
+	/**
157
+	 * Returns the current document type.
158
+	 *
159
+	 * @return int
160
+	 */
161
+	public function getDocumentType() {
162
+
163
+		return self::ICALENDAR20;
164
+
165
+	}
166
+
167
+	/**
168
+	 * Returns a list of all 'base components'. For instance, if an Event has
169
+	 * a recurrence rule, and one instance is overridden, the overridden event
170
+	 * will have the same UID, but will be excluded from this list.
171
+	 *
172
+	 * VTIMEZONE components will always be excluded.
173
+	 *
174
+	 * @param string $componentName filter by component name
175
+	 *
176
+	 * @return VObject\Component[]
177
+	 */
178
+	public function getBaseComponents($componentName = null) {
179
+
180
+		$isBaseComponent = function($component) {
181
+
182
+			if (!$component instanceof VObject\Component) {
183
+				return false;
184
+			}
185
+			if ($component->name === 'VTIMEZONE') {
186
+				return false;
187
+			}
188
+			if (isset($component->{'RECURRENCE-ID'})) {
189
+				return false;
190
+			}
191
+			return true;
192
+
193
+		};
194
+
195
+		if ($componentName) {
196
+			// Early exit
197
+			return array_filter(
198
+				$this->select($componentName),
199
+				$isBaseComponent
200
+			);
201
+		}
202
+
203
+		$components = [];
204
+		foreach ($this->children as $childGroup) {
205
+
206
+			foreach ($childGroup as $child) {
207
+
208
+				if (!$child instanceof Component) {
209
+					// If one child is not a component, they all are so we skip
210
+					// the entire group.
211
+					continue 2;
212
+				}
213
+				if ($isBaseComponent($child)) {
214
+					$components[] = $child;
215
+				}
216
+
217
+			}
218
+
219
+		}
220
+		return $components;
221
+
222
+	}
223
+
224
+	/**
225
+	 * Returns the first component that is not a VTIMEZONE, and does not have
226
+	 * an RECURRENCE-ID.
227
+	 *
228
+	 * If there is no such component, null will be returned.
229
+	 *
230
+	 * @param string $componentName filter by component name
231
+	 *
232
+	 * @return VObject\Component|null
233
+	 */
234
+	public function getBaseComponent($componentName = null) {
235
+
236
+		$isBaseComponent = function($component) {
237
+
238
+			if (!$component instanceof VObject\Component) {
239
+				return false;
240
+			}
241
+			if ($component->name === 'VTIMEZONE') {
242
+				return false;
243
+			}
244
+			if (isset($component->{'RECURRENCE-ID'})) {
245
+				return false;
246
+			}
247
+			return true;
248
+
249
+		};
250
+
251
+		if ($componentName) {
252
+			foreach ($this->select($componentName) as $child) {
253
+				if ($isBaseComponent($child)) {
254
+					return $child;
255
+				}
256
+			}
257
+			return null;
258
+		}
259
+
260
+		// Searching all components
261
+		foreach ($this->children as $childGroup) {
262
+			foreach ($childGroup as $child) {
263
+				if ($isBaseComponent($child)) {
264
+					return $child;
265
+				}
266
+			}
267
+
268
+		}
269
+		return null;
270
+
271
+	}
272
+
273
+	/**
274
+	 * Expand all events in this VCalendar object and return a new VCalendar
275
+	 * with the expanded events.
276
+	 *
277
+	 * If this calendar object, has events with recurrence rules, this method
278
+	 * can be used to expand the event into multiple sub-events.
279
+	 *
280
+	 * Each event will be stripped from it's recurrence information, and only
281
+	 * the instances of the event in the specified timerange will be left
282
+	 * alone.
283
+	 *
284
+	 * In addition, this method will cause timezone information to be stripped,
285
+	 * and normalized to UTC.
286
+	 *
287
+	 * @param DateTimeInterface $start
288
+	 * @param DateTimeInterface $end
289
+	 * @param DateTimeZone $timeZone reference timezone for floating dates and
290
+	 *                     times.
291
+	 * @return VCalendar
292
+	 */
293
+	public function expand(DateTimeInterface $start, DateTimeInterface $end, DateTimeZone $timeZone = null) {
294
+
295
+		$newChildren = [];
296
+		$recurringEvents = [];
297
+
298
+		if (!$timeZone) {
299
+			$timeZone = new DateTimeZone('UTC');
300
+		}
301
+
302
+		$stripTimezones = function(Component $component) use ($timeZone, &$stripTimezones) {
303
+
304
+			foreach ($component->children() as $componentChild) {
305
+				if ($componentChild instanceof Property\ICalendar\DateTime && $componentChild->hasTime()) {
306
+
307
+					$dt = $componentChild->getDateTimes($timeZone);
308
+					// We only need to update the first timezone, because
309
+					// setDateTimes will match all other timezones to the
310
+					// first.
311
+					$dt[0] = $dt[0]->setTimeZone(new DateTimeZone('UTC'));
312
+					$componentChild->setDateTimes($dt);
313
+				} elseif ($componentChild instanceof Component) {
314
+					$stripTimezones($componentChild);
315
+				}
316
+
317
+			}
318
+			return $component;
319
+
320
+		};
321
+
322
+		foreach ($this->children() as $child) {
323
+
324
+			if ($child instanceof Property && $child->name !== 'PRODID') {
325
+				// We explictly want to ignore PRODID, because we want to
326
+				// overwrite it with our own.
327
+				$newChildren[] = clone $child;
328
+			} elseif ($child instanceof Component && $child->name !== 'VTIMEZONE') {
329
+
330
+				// We're also stripping all VTIMEZONE objects because we're
331
+				// converting everything to UTC.
332
+				if ($child->name === 'VEVENT' && (isset($child->{'RECURRENCE-ID'}) || isset($child->RRULE) || isset($child->RDATE))) {
333
+					// Handle these a bit later.
334
+					$uid = (string)$child->UID;
335
+					if (!$uid) {
336
+						throw new InvalidDataException('Every VEVENT object must have a UID property');
337
+					}
338
+					if (isset($recurringEvents[$uid])) {
339
+						$recurringEvents[$uid][] = clone $child;
340
+					} else {
341
+						$recurringEvents[$uid] = [clone $child];
342
+					}
343
+				} elseif ($child->name === 'VEVENT' && $child->isInTimeRange($start, $end)) {
344
+					$newChildren[] = $stripTimezones(clone $child);
345
+				}
346
+
347
+			}
348
+
349
+		}
350
+
351
+		foreach ($recurringEvents as $events) {
352
+
353
+			try {
354
+				$it = new EventIterator($events, $timeZone);
355
+
356
+			} catch (NoInstancesException $e) {
357
+				// This event is recurring, but it doesn't have a single
358
+				// instance. We are skipping this event from the output
359
+				// entirely.
360
+				continue;
361
+			}
362
+			$it->fastForward($start);
363
+
364
+			while ($it->valid() && $it->getDTStart() < $end) {
365
+
366
+				if ($it->getDTEnd() > $start) {
367
+
368
+					$newChildren[] = $stripTimezones($it->getEventObject());
369
+
370
+				}
371
+				$it->next();
372
+
373
+			}
374
+
375
+		}
376
+
377
+		return new self($newChildren);
378
+
379
+	}
380
+
381
+	/**
382
+	 * This method should return a list of default property values.
383
+	 *
384
+	 * @return array
385
+	 */
386
+	protected function getDefaults() {
387
+
388
+		return [
389
+			'VERSION'  => '2.0',
390
+			'PRODID'   => '-//Sabre//Sabre VObject ' . VObject\Version::VERSION . '//EN',
391
+			'CALSCALE' => 'GREGORIAN',
392
+		];
393
+
394
+	}
395
+
396
+	/**
397
+	 * A simple list of validation rules.
398
+	 *
399
+	 * This is simply a list of properties, and how many times they either
400
+	 * must or must not appear.
401
+	 *
402
+	 * Possible values per property:
403
+	 *   * 0 - Must not appear.
404
+	 *   * 1 - Must appear exactly once.
405
+	 *   * + - Must appear at least once.
406
+	 *   * * - Can appear any number of times.
407
+	 *   * ? - May appear, but not more than once.
408
+	 *
409
+	 * @var array
410
+	 */
411
+	public function getValidationRules() {
412
+
413
+		return [
414
+			'PRODID'  => 1,
415
+			'VERSION' => 1,
416
+
417
+			'CALSCALE' => '?',
418
+			'METHOD'   => '?',
419
+		];
420
+
421
+	}
422
+
423
+	/**
424
+	 * Validates the node for correctness.
425
+	 *
426
+	 * The following options are supported:
427
+	 *   Node::REPAIR - May attempt to automatically repair the problem.
428
+	 *   Node::PROFILE_CARDDAV - Validate the vCard for CardDAV purposes.
429
+	 *   Node::PROFILE_CALDAV - Validate the iCalendar for CalDAV purposes.
430
+	 *
431
+	 * This method returns an array with detected problems.
432
+	 * Every element has the following properties:
433
+	 *
434
+	 *  * level - problem level.
435
+	 *  * message - A human-readable string describing the issue.
436
+	 *  * node - A reference to the problematic node.
437
+	 *
438
+	 * The level means:
439
+	 *   1 - The issue was repaired (only happens if REPAIR was turned on).
440
+	 *   2 - A warning.
441
+	 *   3 - An error.
442
+	 *
443
+	 * @param int $options
444
+	 *
445
+	 * @return array
446
+	 */
447
+	public function validate($options = 0) {
448
+
449
+		$warnings = parent::validate($options);
450
+
451
+		if ($ver = $this->VERSION) {
452
+			if ((string)$ver !== '2.0') {
453
+				$warnings[] = [
454
+					'level'   => 3,
455
+					'message' => 'Only iCalendar version 2.0 as defined in rfc5545 is supported.',
456
+					'node'    => $this,
457
+				];
458
+			}
459
+
460
+		}
461
+
462
+		$uidList = [];
463
+		$componentsFound = 0;
464
+		$componentTypes = [];
465
+
466
+		foreach ($this->children() as $child) {
467
+			if ($child instanceof Component) {
468
+				$componentsFound++;
469
+
470
+				if (!in_array($child->name, ['VEVENT', 'VTODO', 'VJOURNAL'])) {
471
+					continue;
472
+				}
473
+				$componentTypes[] = $child->name;
474
+
475
+				$uid = (string)$child->UID;
476
+				$isMaster = isset($child->{'RECURRENCE-ID'}) ? 0 : 1;
477
+				if (isset($uidList[$uid])) {
478
+					$uidList[$uid]['count']++;
479
+					if ($isMaster && $uidList[$uid]['hasMaster']) {
480
+						$warnings[] = [
481
+							'level'   => 3,
482
+							'message' => 'More than one master object was found for the object with UID ' . $uid,
483
+							'node'    => $this,
484
+						];
485
+					}
486
+					$uidList[$uid]['hasMaster'] += $isMaster;
487
+				} else {
488
+					$uidList[$uid] = [
489
+						'count'     => 1,
490
+						'hasMaster' => $isMaster,
491
+					];
492
+				}
493
+
494
+			}
495
+		}
496
+
497
+		if ($componentsFound === 0) {
498
+			$warnings[] = [
499
+				'level'   => 3,
500
+				'message' => 'An iCalendar object must have at least 1 component.',
501
+				'node'    => $this,
502
+			];
503
+		}
504
+
505
+		if ($options & self::PROFILE_CALDAV) {
506
+			if (count($uidList) > 1) {
507
+				$warnings[] = [
508
+					'level'   => 3,
509
+					'message' => 'A calendar object on a CalDAV server may only have components with the same UID.',
510
+					'node'    => $this,
511
+				];
512
+			}
513
+			if (count($componentTypes) === 0) {
514
+				$warnings[] = [
515
+					'level'   => 3,
516
+					'message' => 'A calendar object on a CalDAV server must have at least 1 component (VTODO, VEVENT, VJOURNAL).',
517
+					'node'    => $this,
518
+				];
519
+			}
520
+			if (count(array_unique($componentTypes)) > 1) {
521
+				$warnings[] = [
522
+					'level'   => 3,
523
+					'message' => 'A calendar object on a CalDAV server may only have 1 type of component (VEVENT, VTODO or VJOURNAL).',
524
+					'node'    => $this,
525
+				];
526
+			}
527
+
528
+			if (isset($this->METHOD)) {
529
+				$warnings[] = [
530
+					'level'   => 3,
531
+					'message' => 'A calendar object on a CalDAV server MUST NOT have a METHOD property.',
532
+					'node'    => $this,
533
+				];
534
+			}
535
+		}
536
+
537
+		return $warnings;
538
+
539
+	}
540
+
541
+	/**
542
+	 * Returns all components with a specific UID value.
543
+	 *
544
+	 * @return array
545
+	 */
546
+	public function getByUID($uid) {
547
+
548
+		return array_filter($this->getComponents(), function($item) use ($uid) {
549
+
550
+			if (!$itemUid = $item->select('UID')) {
551
+				return false;
552
+			}
553
+			$itemUid = current($itemUid)->getValue();
554
+			return $uid === $itemUid;
555
+
556
+		});
557
+
558
+	}
559 559
 
560 560
 
561 561
 }
Please login to merge, or discard this patch.
libraries/SabreDAV/VObject/Component/VAvailability.php 1 patch
Indentation   +136 added lines, -136 removed lines patch added patch discarded remove patch
@@ -17,140 +17,140 @@
 block discarded – undo
17 17
  */
18 18
 class VAvailability extends VObject\Component {
19 19
 
20
-    /**
21
-     * Returns true or false depending on if the event falls in the specified
22
-     * time-range. This is used for filtering purposes.
23
-     *
24
-     * The rules used to determine if an event falls within the specified
25
-     * time-range is based on:
26
-     *
27
-     * https://tools.ietf.org/html/draft-daboo-calendar-availability-05#section-3.1
28
-     *
29
-     * @param DateTimeInterface $start
30
-     * @param DateTimeInterface $end
31
-     *
32
-     * @return bool
33
-     */
34
-    public function isInTimeRange(DateTimeInterface $start, DateTimeInterface $end) {
35
-
36
-        list($effectiveStart, $effectiveEnd) = $this->getEffectiveStartEnd();
37
-        return (
38
-            (is_null($effectiveStart) || $start < $effectiveEnd) &&
39
-            (is_null($effectiveEnd) || $end > $effectiveStart)
40
-        );
41
-
42
-    }
43
-
44
-    /**
45
-     * Returns the 'effective start' and 'effective end' of this VAVAILABILITY
46
-     * component.
47
-     *
48
-     * We use the DTSTART and DTEND or DURATION to determine this.
49
-     *
50
-     * The returned value is an array containing DateTimeImmutable instances.
51
-     * If either the start or end is 'unbounded' its value will be null
52
-     * instead.
53
-     *
54
-     * @return array
55
-     */
56
-    public function getEffectiveStartEnd() {
57
-
58
-        $effectiveStart = null;
59
-        $effectiveEnd = null;
60
-
61
-        if (isset($this->DTSTART)) {
62
-            $effectiveStart = $this->DTSTART->getDateTime();
63
-        }
64
-        if (isset($this->DTEND)) {
65
-            $effectiveEnd = $this->DTEND->getDateTime();
66
-        } elseif ($effectiveStart && isset($this->DURATION)) {
67
-            $effectiveEnd = $effectiveStart->add(VObject\DateTimeParser::parseDuration($this->DURATION));
68
-        }
69
-
70
-        return [$effectiveStart, $effectiveEnd];
71
-
72
-    }
73
-
74
-
75
-    /**
76
-     * A simple list of validation rules.
77
-     *
78
-     * This is simply a list of properties, and how many times they either
79
-     * must or must not appear.
80
-     *
81
-     * Possible values per property:
82
-     *   * 0 - Must not appear.
83
-     *   * 1 - Must appear exactly once.
84
-     *   * + - Must appear at least once.
85
-     *   * * - Can appear any number of times.
86
-     *   * ? - May appear, but not more than once.
87
-     *
88
-     * @var array
89
-     */
90
-    public function getValidationRules() {
91
-
92
-        return [
93
-            'UID'     => 1,
94
-            'DTSTAMP' => 1,
95
-
96
-            'BUSYTYPE'      => '?',
97
-            'CLASS'         => '?',
98
-            'CREATED'       => '?',
99
-            'DESCRIPTION'   => '?',
100
-            'DTSTART'       => '?',
101
-            'LAST-MODIFIED' => '?',
102
-            'ORGANIZER'     => '?',
103
-            'PRIORITY'      => '?',
104
-            'SEQUENCE'      => '?',
105
-            'SUMMARY'       => '?',
106
-            'URL'           => '?',
107
-            'DTEND'         => '?',
108
-            'DURATION'      => '?',
109
-
110
-            'CATEGORIES' => '*',
111
-            'COMMENT'    => '*',
112
-            'CONTACT'    => '*',
113
-        ];
114
-
115
-    }
116
-
117
-    /**
118
-     * Validates the node for correctness.
119
-     *
120
-     * The following options are supported:
121
-     *   Node::REPAIR - May attempt to automatically repair the problem.
122
-     *   Node::PROFILE_CARDDAV - Validate the vCard for CardDAV purposes.
123
-     *   Node::PROFILE_CALDAV - Validate the iCalendar for CalDAV purposes.
124
-     *
125
-     * This method returns an array with detected problems.
126
-     * Every element has the following properties:
127
-     *
128
-     *  * level - problem level.
129
-     *  * message - A human-readable string describing the issue.
130
-     *  * node - A reference to the problematic node.
131
-     *
132
-     * The level means:
133
-     *   1 - The issue was repaired (only happens if REPAIR was turned on).
134
-     *   2 - A warning.
135
-     *   3 - An error.
136
-     *
137
-     * @param int $options
138
-     *
139
-     * @return array
140
-     */
141
-    public function validate($options = 0) {
142
-
143
-        $result = parent::validate($options);
144
-
145
-        if (isset($this->DTEND) && isset($this->DURATION)) {
146
-            $result[] = [
147
-                'level'   => 3,
148
-                'message' => 'DTEND and DURATION cannot both be present',
149
-                'node'    => $this
150
-            ];
151
-        }
152
-
153
-        return $result;
154
-
155
-    }
20
+	/**
21
+	 * Returns true or false depending on if the event falls in the specified
22
+	 * time-range. This is used for filtering purposes.
23
+	 *
24
+	 * The rules used to determine if an event falls within the specified
25
+	 * time-range is based on:
26
+	 *
27
+	 * https://tools.ietf.org/html/draft-daboo-calendar-availability-05#section-3.1
28
+	 *
29
+	 * @param DateTimeInterface $start
30
+	 * @param DateTimeInterface $end
31
+	 *
32
+	 * @return bool
33
+	 */
34
+	public function isInTimeRange(DateTimeInterface $start, DateTimeInterface $end) {
35
+
36
+		list($effectiveStart, $effectiveEnd) = $this->getEffectiveStartEnd();
37
+		return (
38
+			(is_null($effectiveStart) || $start < $effectiveEnd) &&
39
+			(is_null($effectiveEnd) || $end > $effectiveStart)
40
+		);
41
+
42
+	}
43
+
44
+	/**
45
+	 * Returns the 'effective start' and 'effective end' of this VAVAILABILITY
46
+	 * component.
47
+	 *
48
+	 * We use the DTSTART and DTEND or DURATION to determine this.
49
+	 *
50
+	 * The returned value is an array containing DateTimeImmutable instances.
51
+	 * If either the start or end is 'unbounded' its value will be null
52
+	 * instead.
53
+	 *
54
+	 * @return array
55
+	 */
56
+	public function getEffectiveStartEnd() {
57
+
58
+		$effectiveStart = null;
59
+		$effectiveEnd = null;
60
+
61
+		if (isset($this->DTSTART)) {
62
+			$effectiveStart = $this->DTSTART->getDateTime();
63
+		}
64
+		if (isset($this->DTEND)) {
65
+			$effectiveEnd = $this->DTEND->getDateTime();
66
+		} elseif ($effectiveStart && isset($this->DURATION)) {
67
+			$effectiveEnd = $effectiveStart->add(VObject\DateTimeParser::parseDuration($this->DURATION));
68
+		}
69
+
70
+		return [$effectiveStart, $effectiveEnd];
71
+
72
+	}
73
+
74
+
75
+	/**
76
+	 * A simple list of validation rules.
77
+	 *
78
+	 * This is simply a list of properties, and how many times they either
79
+	 * must or must not appear.
80
+	 *
81
+	 * Possible values per property:
82
+	 *   * 0 - Must not appear.
83
+	 *   * 1 - Must appear exactly once.
84
+	 *   * + - Must appear at least once.
85
+	 *   * * - Can appear any number of times.
86
+	 *   * ? - May appear, but not more than once.
87
+	 *
88
+	 * @var array
89
+	 */
90
+	public function getValidationRules() {
91
+
92
+		return [
93
+			'UID'     => 1,
94
+			'DTSTAMP' => 1,
95
+
96
+			'BUSYTYPE'      => '?',
97
+			'CLASS'         => '?',
98
+			'CREATED'       => '?',
99
+			'DESCRIPTION'   => '?',
100
+			'DTSTART'       => '?',
101
+			'LAST-MODIFIED' => '?',
102
+			'ORGANIZER'     => '?',
103
+			'PRIORITY'      => '?',
104
+			'SEQUENCE'      => '?',
105
+			'SUMMARY'       => '?',
106
+			'URL'           => '?',
107
+			'DTEND'         => '?',
108
+			'DURATION'      => '?',
109
+
110
+			'CATEGORIES' => '*',
111
+			'COMMENT'    => '*',
112
+			'CONTACT'    => '*',
113
+		];
114
+
115
+	}
116
+
117
+	/**
118
+	 * Validates the node for correctness.
119
+	 *
120
+	 * The following options are supported:
121
+	 *   Node::REPAIR - May attempt to automatically repair the problem.
122
+	 *   Node::PROFILE_CARDDAV - Validate the vCard for CardDAV purposes.
123
+	 *   Node::PROFILE_CALDAV - Validate the iCalendar for CalDAV purposes.
124
+	 *
125
+	 * This method returns an array with detected problems.
126
+	 * Every element has the following properties:
127
+	 *
128
+	 *  * level - problem level.
129
+	 *  * message - A human-readable string describing the issue.
130
+	 *  * node - A reference to the problematic node.
131
+	 *
132
+	 * The level means:
133
+	 *   1 - The issue was repaired (only happens if REPAIR was turned on).
134
+	 *   2 - A warning.
135
+	 *   3 - An error.
136
+	 *
137
+	 * @param int $options
138
+	 *
139
+	 * @return array
140
+	 */
141
+	public function validate($options = 0) {
142
+
143
+		$result = parent::validate($options);
144
+
145
+		if (isset($this->DTEND) && isset($this->DURATION)) {
146
+			$result[] = [
147
+				'level'   => 3,
148
+				'message' => 'DTEND and DURATION cannot both be present',
149
+				'node'    => $this
150
+			];
151
+		}
152
+
153
+		return $result;
154
+
155
+	}
156 156
 }
Please login to merge, or discard this patch.
libraries/SabreDAV/VObject/Component/VJournal.php 1 patch
Indentation   +88 added lines, -88 removed lines patch added patch discarded remove patch
@@ -16,92 +16,92 @@
 block discarded – undo
16 16
  */
17 17
 class VJournal extends VObject\Component {
18 18
 
19
-    /**
20
-     * Returns true or false depending on if the event falls in the specified
21
-     * time-range. This is used for filtering purposes.
22
-     *
23
-     * The rules used to determine if an event falls within the specified
24
-     * time-range is based on the CalDAV specification.
25
-     *
26
-     * @param DateTimeInterface $start
27
-     * @param DateTimeInterface $end
28
-     *
29
-     * @return bool
30
-     */
31
-    public function isInTimeRange(DateTimeInterface $start, DateTimeInterface $end) {
32
-
33
-        $dtstart = isset($this->DTSTART) ? $this->DTSTART->getDateTime() : null;
34
-        if ($dtstart) {
35
-            $effectiveEnd = $dtstart;
36
-            if (!$this->DTSTART->hasTime()) {
37
-                $effectiveEnd = $effectiveEnd->modify('+1 day');
38
-            }
39
-
40
-            return ($start <= $effectiveEnd && $end > $dtstart);
41
-
42
-        }
43
-        return false;
44
-
45
-    }
46
-
47
-    /**
48
-     * A simple list of validation rules.
49
-     *
50
-     * This is simply a list of properties, and how many times they either
51
-     * must or must not appear.
52
-     *
53
-     * Possible values per property:
54
-     *   * 0 - Must not appear.
55
-     *   * 1 - Must appear exactly once.
56
-     *   * + - Must appear at least once.
57
-     *   * * - Can appear any number of times.
58
-     *   * ? - May appear, but not more than once.
59
-     *
60
-     * @var array
61
-     */
62
-    public function getValidationRules() {
63
-
64
-        return [
65
-            'UID'     => 1,
66
-            'DTSTAMP' => 1,
67
-
68
-            'CLASS'         => '?',
69
-            'CREATED'       => '?',
70
-            'DTSTART'       => '?',
71
-            'LAST-MODIFIED' => '?',
72
-            'ORGANIZER'     => '?',
73
-            'RECURRENCE-ID' => '?',
74
-            'SEQUENCE'      => '?',
75
-            'STATUS'        => '?',
76
-            'SUMMARY'       => '?',
77
-            'URL'           => '?',
78
-
79
-            'RRULE' => '?',
80
-
81
-            'ATTACH'      => '*',
82
-            'ATTENDEE'    => '*',
83
-            'CATEGORIES'  => '*',
84
-            'COMMENT'     => '*',
85
-            'CONTACT'     => '*',
86
-            'DESCRIPTION' => '*',
87
-            'EXDATE'      => '*',
88
-            'RELATED-TO'  => '*',
89
-            'RDATE'       => '*',
90
-        ];
91
-
92
-    }
93
-
94
-    /**
95
-     * This method should return a list of default property values.
96
-     *
97
-     * @return array
98
-     */
99
-    protected function getDefaults() {
100
-
101
-        return [
102
-            'UID'     => 'sabre-vobject-' . VObject\UUIDUtil::getUUID(),
103
-            'DTSTAMP' => date('Ymd\\THis\\Z'),
104
-        ];
105
-
106
-    }
19
+	/**
20
+	 * Returns true or false depending on if the event falls in the specified
21
+	 * time-range. This is used for filtering purposes.
22
+	 *
23
+	 * The rules used to determine if an event falls within the specified
24
+	 * time-range is based on the CalDAV specification.
25
+	 *
26
+	 * @param DateTimeInterface $start
27
+	 * @param DateTimeInterface $end
28
+	 *
29
+	 * @return bool
30
+	 */
31
+	public function isInTimeRange(DateTimeInterface $start, DateTimeInterface $end) {
32
+
33
+		$dtstart = isset($this->DTSTART) ? $this->DTSTART->getDateTime() : null;
34
+		if ($dtstart) {
35
+			$effectiveEnd = $dtstart;
36
+			if (!$this->DTSTART->hasTime()) {
37
+				$effectiveEnd = $effectiveEnd->modify('+1 day');
38
+			}
39
+
40
+			return ($start <= $effectiveEnd && $end > $dtstart);
41
+
42
+		}
43
+		return false;
44
+
45
+	}
46
+
47
+	/**
48
+	 * A simple list of validation rules.
49
+	 *
50
+	 * This is simply a list of properties, and how many times they either
51
+	 * must or must not appear.
52
+	 *
53
+	 * Possible values per property:
54
+	 *   * 0 - Must not appear.
55
+	 *   * 1 - Must appear exactly once.
56
+	 *   * + - Must appear at least once.
57
+	 *   * * - Can appear any number of times.
58
+	 *   * ? - May appear, but not more than once.
59
+	 *
60
+	 * @var array
61
+	 */
62
+	public function getValidationRules() {
63
+
64
+		return [
65
+			'UID'     => 1,
66
+			'DTSTAMP' => 1,
67
+
68
+			'CLASS'         => '?',
69
+			'CREATED'       => '?',
70
+			'DTSTART'       => '?',
71
+			'LAST-MODIFIED' => '?',
72
+			'ORGANIZER'     => '?',
73
+			'RECURRENCE-ID' => '?',
74
+			'SEQUENCE'      => '?',
75
+			'STATUS'        => '?',
76
+			'SUMMARY'       => '?',
77
+			'URL'           => '?',
78
+
79
+			'RRULE' => '?',
80
+
81
+			'ATTACH'      => '*',
82
+			'ATTENDEE'    => '*',
83
+			'CATEGORIES'  => '*',
84
+			'COMMENT'     => '*',
85
+			'CONTACT'     => '*',
86
+			'DESCRIPTION' => '*',
87
+			'EXDATE'      => '*',
88
+			'RELATED-TO'  => '*',
89
+			'RDATE'       => '*',
90
+		];
91
+
92
+	}
93
+
94
+	/**
95
+	 * This method should return a list of default property values.
96
+	 *
97
+	 * @return array
98
+	 */
99
+	protected function getDefaults() {
100
+
101
+		return [
102
+			'UID'     => 'sabre-vobject-' . VObject\UUIDUtil::getUUID(),
103
+			'DTSTAMP' => date('Ymd\\THis\\Z'),
104
+		];
105
+
106
+	}
107 107
 }
Please login to merge, or discard this patch.
libraries/SabreDAV/VObject/Component/VTodo.php 1 patch
Indentation   +173 added lines, -173 removed lines patch added patch discarded remove patch
@@ -16,178 +16,178 @@
 block discarded – undo
16 16
  */
17 17
 class VTodo extends VObject\Component {
18 18
 
19
-    /**
20
-     * Returns true or false depending on if the event falls in the specified
21
-     * time-range. This is used for filtering purposes.
22
-     *
23
-     * The rules used to determine if an event falls within the specified
24
-     * time-range is based on the CalDAV specification.
25
-     *
26
-     * @param DateTimeInterface $start
27
-     * @param DateTimeInterface $end
28
-     *
29
-     * @return bool
30
-     */
31
-    public function isInTimeRange(DateTimeInterface $start, DateTimeInterface $end) {
32
-
33
-        $dtstart = isset($this->DTSTART) ? $this->DTSTART->getDateTime() : null;
34
-        $duration = isset($this->DURATION) ? VObject\DateTimeParser::parseDuration($this->DURATION) : null;
35
-        $due = isset($this->DUE) ? $this->DUE->getDateTime() : null;
36
-        $completed = isset($this->COMPLETED) ? $this->COMPLETED->getDateTime() : null;
37
-        $created = isset($this->CREATED) ? $this->CREATED->getDateTime() : null;
38
-
39
-        if ($dtstart) {
40
-            if ($duration) {
41
-                $effectiveEnd = $dtstart->add($duration);
42
-                return $start <= $effectiveEnd && $end > $dtstart;
43
-            } elseif ($due) {
44
-                return
45
-                    ($start < $due || $start <= $dtstart) &&
46
-                    ($end > $dtstart || $end >= $due);
47
-            } else {
48
-                return $start <= $dtstart && $end > $dtstart;
49
-            }
50
-        }
51
-        if ($due) {
52
-            return ($start < $due && $end >= $due);
53
-        }
54
-        if ($completed && $created) {
55
-            return
56
-                ($start <= $created || $start <= $completed) &&
57
-                ($end >= $created || $end >= $completed);
58
-        }
59
-        if ($completed) {
60
-            return ($start <= $completed && $end >= $completed);
61
-        }
62
-        if ($created) {
63
-            return ($end > $created);
64
-        }
65
-        return true;
66
-
67
-    }
68
-
69
-    /**
70
-     * A simple list of validation rules.
71
-     *
72
-     * This is simply a list of properties, and how many times they either
73
-     * must or must not appear.
74
-     *
75
-     * Possible values per property:
76
-     *   * 0 - Must not appear.
77
-     *   * 1 - Must appear exactly once.
78
-     *   * + - Must appear at least once.
79
-     *   * * - Can appear any number of times.
80
-     *   * ? - May appear, but not more than once.
81
-     *
82
-     * @var array
83
-     */
84
-    public function getValidationRules() {
85
-
86
-        return [
87
-            'UID'     => 1,
88
-            'DTSTAMP' => 1,
89
-
90
-            'CLASS'         => '?',
91
-            'COMPLETED'     => '?',
92
-            'CREATED'       => '?',
93
-            'DESCRIPTION'   => '?',
94
-            'DTSTART'       => '?',
95
-            'GEO'           => '?',
96
-            'LAST-MODIFIED' => '?',
97
-            'LOCATION'      => '?',
98
-            'ORGANIZER'     => '?',
99
-            'PERCENT'       => '?',
100
-            'PRIORITY'      => '?',
101
-            'RECURRENCE-ID' => '?',
102
-            'SEQUENCE'      => '?',
103
-            'STATUS'        => '?',
104
-            'SUMMARY'       => '?',
105
-            'URL'           => '?',
106
-
107
-            'RRULE'    => '?',
108
-            'DUE'      => '?',
109
-            'DURATION' => '?',
110
-
111
-            'ATTACH'         => '*',
112
-            'ATTENDEE'       => '*',
113
-            'CATEGORIES'     => '*',
114
-            'COMMENT'        => '*',
115
-            'CONTACT'        => '*',
116
-            'EXDATE'         => '*',
117
-            'REQUEST-STATUS' => '*',
118
-            'RELATED-TO'     => '*',
119
-            'RESOURCES'      => '*',
120
-            'RDATE'          => '*',
121
-        ];
122
-
123
-    }
124
-
125
-    /**
126
-     * Validates the node for correctness.
127
-     *
128
-     * The following options are supported:
129
-     *   Node::REPAIR - May attempt to automatically repair the problem.
130
-     *
131
-     * This method returns an array with detected problems.
132
-     * Every element has the following properties:
133
-     *
134
-     *  * level - problem level.
135
-     *  * message - A human-readable string describing the issue.
136
-     *  * node - A reference to the problematic node.
137
-     *
138
-     * The level means:
139
-     *   1 - The issue was repaired (only happens if REPAIR was turned on)
140
-     *   2 - An inconsequential issue
141
-     *   3 - A severe issue.
142
-     *
143
-     * @param int $options
144
-     *
145
-     * @return array
146
-     */
147
-    public function validate($options = 0) {
148
-
149
-        $result = parent::validate($options);
150
-        if (isset($this->DUE) && isset($this->DTSTART)) {
151
-
152
-            $due = $this->DUE;
153
-            $dtStart = $this->DTSTART;
154
-
155
-            if ($due->getValueType() !== $dtStart->getValueType()) {
156
-
157
-                $result[] = [
158
-                    'level'   => 3,
159
-                    'message' => 'The value type (DATE or DATE-TIME) must be identical for DUE and DTSTART',
160
-                    'node'    => $due,
161
-                ];
162
-
163
-            } elseif ($due->getDateTime() < $dtStart->getDateTime()) {
164
-
165
-                $result[] = [
166
-                    'level'   => 3,
167
-                    'message' => 'DUE must occur after DTSTART',
168
-                    'node'    => $due,
169
-                ];
170
-
171
-            }
172
-
173
-        }
174
-
175
-        return $result;
176
-
177
-    }
178
-
179
-    /**
180
-     * This method should return a list of default property values.
181
-     *
182
-     * @return array
183
-     */
184
-    protected function getDefaults() {
185
-
186
-        return [
187
-            'UID'     => 'sabre-vobject-' . VObject\UUIDUtil::getUUID(),
188
-            'DTSTAMP' => date('Ymd\\THis\\Z'),
189
-        ];
190
-
191
-    }
19
+	/**
20
+	 * Returns true or false depending on if the event falls in the specified
21
+	 * time-range. This is used for filtering purposes.
22
+	 *
23
+	 * The rules used to determine if an event falls within the specified
24
+	 * time-range is based on the CalDAV specification.
25
+	 *
26
+	 * @param DateTimeInterface $start
27
+	 * @param DateTimeInterface $end
28
+	 *
29
+	 * @return bool
30
+	 */
31
+	public function isInTimeRange(DateTimeInterface $start, DateTimeInterface $end) {
32
+
33
+		$dtstart = isset($this->DTSTART) ? $this->DTSTART->getDateTime() : null;
34
+		$duration = isset($this->DURATION) ? VObject\DateTimeParser::parseDuration($this->DURATION) : null;
35
+		$due = isset($this->DUE) ? $this->DUE->getDateTime() : null;
36
+		$completed = isset($this->COMPLETED) ? $this->COMPLETED->getDateTime() : null;
37
+		$created = isset($this->CREATED) ? $this->CREATED->getDateTime() : null;
38
+
39
+		if ($dtstart) {
40
+			if ($duration) {
41
+				$effectiveEnd = $dtstart->add($duration);
42
+				return $start <= $effectiveEnd && $end > $dtstart;
43
+			} elseif ($due) {
44
+				return
45
+					($start < $due || $start <= $dtstart) &&
46
+					($end > $dtstart || $end >= $due);
47
+			} else {
48
+				return $start <= $dtstart && $end > $dtstart;
49
+			}
50
+		}
51
+		if ($due) {
52
+			return ($start < $due && $end >= $due);
53
+		}
54
+		if ($completed && $created) {
55
+			return
56
+				($start <= $created || $start <= $completed) &&
57
+				($end >= $created || $end >= $completed);
58
+		}
59
+		if ($completed) {
60
+			return ($start <= $completed && $end >= $completed);
61
+		}
62
+		if ($created) {
63
+			return ($end > $created);
64
+		}
65
+		return true;
66
+
67
+	}
68
+
69
+	/**
70
+	 * A simple list of validation rules.
71
+	 *
72
+	 * This is simply a list of properties, and how many times they either
73
+	 * must or must not appear.
74
+	 *
75
+	 * Possible values per property:
76
+	 *   * 0 - Must not appear.
77
+	 *   * 1 - Must appear exactly once.
78
+	 *   * + - Must appear at least once.
79
+	 *   * * - Can appear any number of times.
80
+	 *   * ? - May appear, but not more than once.
81
+	 *
82
+	 * @var array
83
+	 */
84
+	public function getValidationRules() {
85
+
86
+		return [
87
+			'UID'     => 1,
88
+			'DTSTAMP' => 1,
89
+
90
+			'CLASS'         => '?',
91
+			'COMPLETED'     => '?',
92
+			'CREATED'       => '?',
93
+			'DESCRIPTION'   => '?',
94
+			'DTSTART'       => '?',
95
+			'GEO'           => '?',
96
+			'LAST-MODIFIED' => '?',
97
+			'LOCATION'      => '?',
98
+			'ORGANIZER'     => '?',
99
+			'PERCENT'       => '?',
100
+			'PRIORITY'      => '?',
101
+			'RECURRENCE-ID' => '?',
102
+			'SEQUENCE'      => '?',
103
+			'STATUS'        => '?',
104
+			'SUMMARY'       => '?',
105
+			'URL'           => '?',
106
+
107
+			'RRULE'    => '?',
108
+			'DUE'      => '?',
109
+			'DURATION' => '?',
110
+
111
+			'ATTACH'         => '*',
112
+			'ATTENDEE'       => '*',
113
+			'CATEGORIES'     => '*',
114
+			'COMMENT'        => '*',
115
+			'CONTACT'        => '*',
116
+			'EXDATE'         => '*',
117
+			'REQUEST-STATUS' => '*',
118
+			'RELATED-TO'     => '*',
119
+			'RESOURCES'      => '*',
120
+			'RDATE'          => '*',
121
+		];
122
+
123
+	}
124
+
125
+	/**
126
+	 * Validates the node for correctness.
127
+	 *
128
+	 * The following options are supported:
129
+	 *   Node::REPAIR - May attempt to automatically repair the problem.
130
+	 *
131
+	 * This method returns an array with detected problems.
132
+	 * Every element has the following properties:
133
+	 *
134
+	 *  * level - problem level.
135
+	 *  * message - A human-readable string describing the issue.
136
+	 *  * node - A reference to the problematic node.
137
+	 *
138
+	 * The level means:
139
+	 *   1 - The issue was repaired (only happens if REPAIR was turned on)
140
+	 *   2 - An inconsequential issue
141
+	 *   3 - A severe issue.
142
+	 *
143
+	 * @param int $options
144
+	 *
145
+	 * @return array
146
+	 */
147
+	public function validate($options = 0) {
148
+
149
+		$result = parent::validate($options);
150
+		if (isset($this->DUE) && isset($this->DTSTART)) {
151
+
152
+			$due = $this->DUE;
153
+			$dtStart = $this->DTSTART;
154
+
155
+			if ($due->getValueType() !== $dtStart->getValueType()) {
156
+
157
+				$result[] = [
158
+					'level'   => 3,
159
+					'message' => 'The value type (DATE or DATE-TIME) must be identical for DUE and DTSTART',
160
+					'node'    => $due,
161
+				];
162
+
163
+			} elseif ($due->getDateTime() < $dtStart->getDateTime()) {
164
+
165
+				$result[] = [
166
+					'level'   => 3,
167
+					'message' => 'DUE must occur after DTSTART',
168
+					'node'    => $due,
169
+				];
170
+
171
+			}
172
+
173
+		}
174
+
175
+		return $result;
176
+
177
+	}
178
+
179
+	/**
180
+	 * This method should return a list of default property values.
181
+	 *
182
+	 * @return array
183
+	 */
184
+	protected function getDefaults() {
185
+
186
+		return [
187
+			'UID'     => 'sabre-vobject-' . VObject\UUIDUtil::getUUID(),
188
+			'DTSTAMP' => date('Ymd\\THis\\Z'),
189
+		];
190
+
191
+	}
192 192
 
193 193
 }
Please login to merge, or discard this patch.
libraries/SabreDAV/VObject/PHPUnitAssertions.php 1 patch
Indentation   +53 added lines, -53 removed lines patch added patch discarded remove patch
@@ -14,69 +14,69 @@
 block discarded – undo
14 14
  */
15 15
 trait PHPUnitAssertions {
16 16
 
17
-    /**
18
-     * This method tests wether two vcards or icalendar objects are
19
-     * semantically identical.
20
-     *
21
-     * It supports objects being supplied as strings, streams or
22
-     * Sabre\VObject\Component instances.
23
-     *
24
-     * PRODID is removed from both objects as this is often changes and would
25
-     * just get in the way.
26
-     *
27
-     * CALSCALE will automatically get removed if it's set to GREGORIAN.
28
-     *
29
-     * Any property that has the value **ANY** will be treated as a wildcard.
30
-     *
31
-     * @param resource|string|Component $expected
32
-     * @param resource|string|Component $actual
33
-     * @param string $message
34
-     */
35
-    public function assertVObjectEqualsVObject($expected, $actual, $message = '') {
17
+	/**
18
+	 * This method tests wether two vcards or icalendar objects are
19
+	 * semantically identical.
20
+	 *
21
+	 * It supports objects being supplied as strings, streams or
22
+	 * Sabre\VObject\Component instances.
23
+	 *
24
+	 * PRODID is removed from both objects as this is often changes and would
25
+	 * just get in the way.
26
+	 *
27
+	 * CALSCALE will automatically get removed if it's set to GREGORIAN.
28
+	 *
29
+	 * Any property that has the value **ANY** will be treated as a wildcard.
30
+	 *
31
+	 * @param resource|string|Component $expected
32
+	 * @param resource|string|Component $actual
33
+	 * @param string $message
34
+	 */
35
+	public function assertVObjectEqualsVObject($expected, $actual, $message = '') {
36 36
 
37
-        $self = $this;
38
-        $getObj = function($input) use ($self) {
37
+		$self = $this;
38
+		$getObj = function($input) use ($self) {
39 39
 
40
-            if (is_resource($input)) {
41
-                $input = stream_get_contents($input);
42
-            }
43
-            if (is_string($input)) {
44
-                $input = Reader::read($input);
45
-            }
46
-            if (!$input instanceof Component) {
47
-                $this->fail('Input must be a string, stream or VObject component');
48
-            }
49
-            unset($input->PRODID);
50
-            if ($input instanceof Component\VCalendar && (string)$input->CALSCALE === 'GREGORIAN') {
51
-                unset($input->CALSCALE);
52
-            }
53
-            return $input;
40
+			if (is_resource($input)) {
41
+				$input = stream_get_contents($input);
42
+			}
43
+			if (is_string($input)) {
44
+				$input = Reader::read($input);
45
+			}
46
+			if (!$input instanceof Component) {
47
+				$this->fail('Input must be a string, stream or VObject component');
48
+			}
49
+			unset($input->PRODID);
50
+			if ($input instanceof Component\VCalendar && (string)$input->CALSCALE === 'GREGORIAN') {
51
+				unset($input->CALSCALE);
52
+			}
53
+			return $input;
54 54
 
55
-        };
55
+		};
56 56
 
57
-        $expected = $getObj($expected)->serialize();
58
-        $actual = $getObj($actual)->serialize();
57
+		$expected = $getObj($expected)->serialize();
58
+		$actual = $getObj($actual)->serialize();
59 59
 
60
-        // Finding wildcards in expected.
61
-        preg_match_all('|^([A-Z]+):\\*\\*ANY\\*\\*\r$|m', $expected, $matches, PREG_SET_ORDER);
60
+		// Finding wildcards in expected.
61
+		preg_match_all('|^([A-Z]+):\\*\\*ANY\\*\\*\r$|m', $expected, $matches, PREG_SET_ORDER);
62 62
 
63
-        foreach ($matches as $match) {
63
+		foreach ($matches as $match) {
64 64
 
65
-            $actual = preg_replace(
66
-                '|^' . preg_quote($match[1], '|') . ':(.*)\r$|m',
67
-                $match[1] . ':**ANY**' . "\r",
68
-                $actual
69
-            );
65
+			$actual = preg_replace(
66
+				'|^' . preg_quote($match[1], '|') . ':(.*)\r$|m',
67
+				$match[1] . ':**ANY**' . "\r",
68
+				$actual
69
+			);
70 70
 
71
-        }
71
+		}
72 72
 
73
-        $this->assertEquals(
74
-            $expected,
75
-            $actual,
76
-            $message
77
-        );
73
+		$this->assertEquals(
74
+			$expected,
75
+			$actual,
76
+			$message
77
+		);
78 78
 
79
-    }
79
+	}
80 80
 
81 81
 
82 82
 }
Please login to merge, or discard this patch.