Completed
Push — developer ( 637a0a...986412 )
by Błażej
246:14 queued 198:06
created
libraries/SabreDAV/VObject/Parser/Json.php 2 patches
Unused Use Statements   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -4,8 +4,8 @@
 block discarded – undo
4 4
 
5 5
 use Sabre\VObject\Component\VCalendar;
6 6
 use Sabre\VObject\Component\VCard;
7
-use Sabre\VObject\ParseException;
8 7
 use Sabre\VObject\EofException;
8
+use Sabre\VObject\ParseException;
9 9
 
10 10
 /**
11 11
  * Json Parser.
Please login to merge, or discard this patch.
Indentation   +175 added lines, -175 removed lines patch added patch discarded remove patch
@@ -18,180 +18,180 @@
 block discarded – undo
18 18
  */
19 19
 class Json extends Parser {
20 20
 
21
-    /**
22
-     * The input data.
23
-     *
24
-     * @var array
25
-     */
26
-    protected $input;
27
-
28
-    /**
29
-     * Root component.
30
-     *
31
-     * @var Document
32
-     */
33
-    protected $root;
34
-
35
-    /**
36
-     * This method starts the parsing process.
37
-     *
38
-     * If the input was not supplied during construction, it's possible to pass
39
-     * it here instead.
40
-     *
41
-     * If either input or options are not supplied, the defaults will be used.
42
-     *
43
-     * @param resource|string|array|null $input
44
-     * @param int $options
45
-     *
46
-     * @return Sabre\VObject\Document
47
-     */
48
-    public function parse($input = null, $options = 0) {
49
-
50
-        if (!is_null($input)) {
51
-            $this->setInput($input);
52
-        }
53
-        if (is_null($this->input)) {
54
-            throw new EofException('End of input stream, or no input supplied');
55
-        }
56
-
57
-        if (0 !== $options) {
58
-            $this->options = $options;
59
-        }
60
-
61
-        switch ($this->input[0]) {
62
-            case 'vcalendar' :
63
-                $this->root = new VCalendar([], false);
64
-                break;
65
-            case 'vcard' :
66
-                $this->root = new VCard([], false);
67
-                break;
68
-            default :
69
-                throw new ParseException('The root component must either be a vcalendar, or a vcard');
70
-
71
-        }
72
-        foreach ($this->input[1] as $prop) {
73
-            $this->root->add($this->parseProperty($prop));
74
-        }
75
-        if (isset($this->input[2])) foreach ($this->input[2] as $comp) {
76
-            $this->root->add($this->parseComponent($comp));
77
-        }
78
-
79
-        // Resetting the input so we can throw an feof exception the next time.
80
-        $this->input = null;
81
-
82
-        return $this->root;
83
-
84
-    }
85
-
86
-    /**
87
-     * Parses a component.
88
-     *
89
-     * @param array $jComp
90
-     *
91
-     * @return \Sabre\VObject\Component
92
-     */
93
-    public function parseComponent(array $jComp) {
94
-
95
-        // We can remove $self from PHP 5.4 onward.
96
-        $self = $this;
97
-
98
-        $properties = array_map(
99
-            function($jProp) use ($self) {
100
-                return $self->parseProperty($jProp);
101
-            },
102
-            $jComp[1]
103
-        );
104
-
105
-        if (isset($jComp[2])) {
106
-
107
-            $components = array_map(
108
-                function($jComp) use ($self) {
109
-                    return $self->parseComponent($jComp);
110
-                },
111
-                $jComp[2]
112
-            );
113
-
114
-        } else $components = [];
115
-
116
-        return $this->root->createComponent(
117
-            $jComp[0],
118
-            array_merge($properties, $components),
119
-            $defaults = false
120
-        );
121
-
122
-    }
123
-
124
-    /**
125
-     * Parses properties.
126
-     *
127
-     * @param array $jProp
128
-     *
129
-     * @return \Sabre\VObject\Property
130
-     */
131
-    public function parseProperty(array $jProp) {
132
-
133
-        list(
134
-            $propertyName,
135
-            $parameters,
136
-            $valueType
137
-        ) = $jProp;
138
-
139
-        $propertyName = strtoupper($propertyName);
140
-
141
-        // This is the default class we would be using if we didn't know the
142
-        // value type. We're using this value later in this function.
143
-        $defaultPropertyClass = $this->root->getClassNameForPropertyName($propertyName);
144
-
145
-        $parameters = (array)$parameters;
146
-
147
-        $value = array_slice($jProp, 3);
148
-
149
-        $valueType = strtoupper($valueType);
150
-
151
-        if (isset($parameters['group'])) {
152
-            $propertyName = $parameters['group'] . '.' . $propertyName;
153
-            unset($parameters['group']);
154
-        }
155
-
156
-        $prop = $this->root->createProperty($propertyName, null, $parameters, $valueType);
157
-        $prop->setJsonValue($value);
158
-
159
-        // We have to do something awkward here. FlatText as well as Text
160
-        // represents TEXT values. We have to normalize these here. In the
161
-        // future we can get rid of FlatText once we're allowed to break BC
162
-        // again.
163
-        if ($defaultPropertyClass === 'Sabre\VObject\Property\FlatText') {
164
-            $defaultPropertyClass = 'Sabre\VObject\Property\Text';
165
-        }
166
-
167
-        // If the value type we received (e.g.: TEXT) was not the default value
168
-        // type for the given property (e.g.: BDAY), we need to add a VALUE=
169
-        // parameter.
170
-        if ($defaultPropertyClass !== get_class($prop)) {
171
-            $prop["VALUE"] = $valueType;
172
-        }
173
-
174
-        return $prop;
175
-
176
-    }
177
-
178
-    /**
179
-     * Sets the input data.
180
-     *
181
-     * @param resource|string|array $input
182
-     *
183
-     * @return void
184
-     */
185
-    public function setInput($input) {
186
-
187
-        if (is_resource($input)) {
188
-            $input = stream_get_contents($input);
189
-        }
190
-        if (is_string($input)) {
191
-            $input = json_decode($input);
192
-        }
193
-        $this->input = $input;
194
-
195
-    }
21
+	/**
22
+	 * The input data.
23
+	 *
24
+	 * @var array
25
+	 */
26
+	protected $input;
27
+
28
+	/**
29
+	 * Root component.
30
+	 *
31
+	 * @var Document
32
+	 */
33
+	protected $root;
34
+
35
+	/**
36
+	 * This method starts the parsing process.
37
+	 *
38
+	 * If the input was not supplied during construction, it's possible to pass
39
+	 * it here instead.
40
+	 *
41
+	 * If either input or options are not supplied, the defaults will be used.
42
+	 *
43
+	 * @param resource|string|array|null $input
44
+	 * @param int $options
45
+	 *
46
+	 * @return Sabre\VObject\Document
47
+	 */
48
+	public function parse($input = null, $options = 0) {
49
+
50
+		if (!is_null($input)) {
51
+			$this->setInput($input);
52
+		}
53
+		if (is_null($this->input)) {
54
+			throw new EofException('End of input stream, or no input supplied');
55
+		}
56
+
57
+		if (0 !== $options) {
58
+			$this->options = $options;
59
+		}
60
+
61
+		switch ($this->input[0]) {
62
+			case 'vcalendar' :
63
+				$this->root = new VCalendar([], false);
64
+				break;
65
+			case 'vcard' :
66
+				$this->root = new VCard([], false);
67
+				break;
68
+			default :
69
+				throw new ParseException('The root component must either be a vcalendar, or a vcard');
70
+
71
+		}
72
+		foreach ($this->input[1] as $prop) {
73
+			$this->root->add($this->parseProperty($prop));
74
+		}
75
+		if (isset($this->input[2])) foreach ($this->input[2] as $comp) {
76
+			$this->root->add($this->parseComponent($comp));
77
+		}
78
+
79
+		// Resetting the input so we can throw an feof exception the next time.
80
+		$this->input = null;
81
+
82
+		return $this->root;
83
+
84
+	}
85
+
86
+	/**
87
+	 * Parses a component.
88
+	 *
89
+	 * @param array $jComp
90
+	 *
91
+	 * @return \Sabre\VObject\Component
92
+	 */
93
+	public function parseComponent(array $jComp) {
94
+
95
+		// We can remove $self from PHP 5.4 onward.
96
+		$self = $this;
97
+
98
+		$properties = array_map(
99
+			function($jProp) use ($self) {
100
+				return $self->parseProperty($jProp);
101
+			},
102
+			$jComp[1]
103
+		);
104
+
105
+		if (isset($jComp[2])) {
106
+
107
+			$components = array_map(
108
+				function($jComp) use ($self) {
109
+					return $self->parseComponent($jComp);
110
+				},
111
+				$jComp[2]
112
+			);
113
+
114
+		} else $components = [];
115
+
116
+		return $this->root->createComponent(
117
+			$jComp[0],
118
+			array_merge($properties, $components),
119
+			$defaults = false
120
+		);
121
+
122
+	}
123
+
124
+	/**
125
+	 * Parses properties.
126
+	 *
127
+	 * @param array $jProp
128
+	 *
129
+	 * @return \Sabre\VObject\Property
130
+	 */
131
+	public function parseProperty(array $jProp) {
132
+
133
+		list(
134
+			$propertyName,
135
+			$parameters,
136
+			$valueType
137
+		) = $jProp;
138
+
139
+		$propertyName = strtoupper($propertyName);
140
+
141
+		// This is the default class we would be using if we didn't know the
142
+		// value type. We're using this value later in this function.
143
+		$defaultPropertyClass = $this->root->getClassNameForPropertyName($propertyName);
144
+
145
+		$parameters = (array)$parameters;
146
+
147
+		$value = array_slice($jProp, 3);
148
+
149
+		$valueType = strtoupper($valueType);
150
+
151
+		if (isset($parameters['group'])) {
152
+			$propertyName = $parameters['group'] . '.' . $propertyName;
153
+			unset($parameters['group']);
154
+		}
155
+
156
+		$prop = $this->root->createProperty($propertyName, null, $parameters, $valueType);
157
+		$prop->setJsonValue($value);
158
+
159
+		// We have to do something awkward here. FlatText as well as Text
160
+		// represents TEXT values. We have to normalize these here. In the
161
+		// future we can get rid of FlatText once we're allowed to break BC
162
+		// again.
163
+		if ($defaultPropertyClass === 'Sabre\VObject\Property\FlatText') {
164
+			$defaultPropertyClass = 'Sabre\VObject\Property\Text';
165
+		}
166
+
167
+		// If the value type we received (e.g.: TEXT) was not the default value
168
+		// type for the given property (e.g.: BDAY), we need to add a VALUE=
169
+		// parameter.
170
+		if ($defaultPropertyClass !== get_class($prop)) {
171
+			$prop["VALUE"] = $valueType;
172
+		}
173
+
174
+		return $prop;
175
+
176
+	}
177
+
178
+	/**
179
+	 * Sets the input data.
180
+	 *
181
+	 * @param resource|string|array $input
182
+	 *
183
+	 * @return void
184
+	 */
185
+	public function setInput($input) {
186
+
187
+		if (is_resource($input)) {
188
+			$input = stream_get_contents($input);
189
+		}
190
+		if (is_string($input)) {
191
+			$input = json_decode($input);
192
+		}
193
+		$this->input = $input;
194
+
195
+	}
196 196
 
197 197
 }
Please login to merge, or discard this patch.
libraries/SabreDAV/VObject/Property/UtcOffset.php 1 patch
Indentation   +52 added lines, -52 removed lines patch added patch discarded remove patch
@@ -13,65 +13,65 @@
 block discarded – undo
13 13
  */
14 14
 class UtcOffset extends Text {
15 15
 
16
-    /**
17
-     * In case this is a multi-value property. This string will be used as a
18
-     * delimiter.
19
-     *
20
-     * @var string|null
21
-     */
22
-    public $delimiter = null;
16
+	/**
17
+	 * In case this is a multi-value property. This string will be used as a
18
+	 * delimiter.
19
+	 *
20
+	 * @var string|null
21
+	 */
22
+	public $delimiter = null;
23 23
 
24
-    /**
25
-     * Returns the type of value.
26
-     *
27
-     * This corresponds to the VALUE= parameter. Every property also has a
28
-     * 'default' valueType.
29
-     *
30
-     * @return string
31
-     */
32
-    public function getValueType() {
24
+	/**
25
+	 * Returns the type of value.
26
+	 *
27
+	 * This corresponds to the VALUE= parameter. Every property also has a
28
+	 * 'default' valueType.
29
+	 *
30
+	 * @return string
31
+	 */
32
+	public function getValueType() {
33 33
 
34
-        return 'UTC-OFFSET';
34
+		return 'UTC-OFFSET';
35 35
 
36
-    }
36
+	}
37 37
 
38
-    /**
39
-     * Sets the JSON value, as it would appear in a jCard or jCal object.
40
-     *
41
-     * The value must always be an array.
42
-     *
43
-     * @param array $value
44
-     *
45
-     * @return void
46
-     */
47
-    public function setJsonValue(array $value) {
38
+	/**
39
+	 * Sets the JSON value, as it would appear in a jCard or jCal object.
40
+	 *
41
+	 * The value must always be an array.
42
+	 *
43
+	 * @param array $value
44
+	 *
45
+	 * @return void
46
+	 */
47
+	public function setJsonValue(array $value) {
48 48
 
49
-        $value = array_map(
50
-            function($value) {
51
-                return str_replace(':', '', $value);
52
-            },
53
-            $value
54
-        );
55
-        parent::setJsonValue($value);
49
+		$value = array_map(
50
+			function($value) {
51
+				return str_replace(':', '', $value);
52
+			},
53
+			$value
54
+		);
55
+		parent::setJsonValue($value);
56 56
 
57
-    }
57
+	}
58 58
 
59
-    /**
60
-     * Returns the value, in the format it should be encoded for JSON.
61
-     *
62
-     * This method must always return an array.
63
-     *
64
-     * @return array
65
-     */
66
-    public function getJsonValue() {
59
+	/**
60
+	 * Returns the value, in the format it should be encoded for JSON.
61
+	 *
62
+	 * This method must always return an array.
63
+	 *
64
+	 * @return array
65
+	 */
66
+	public function getJsonValue() {
67 67
 
68
-        return array_map(
69
-            function($value) {
70
-                return substr($value, 0, -2) . ':' .
71
-                       substr($value, -2);
72
-            },
73
-            parent::getJsonValue()
74
-        );
68
+		return array_map(
69
+			function($value) {
70
+				return substr($value, 0, -2) . ':' .
71
+					   substr($value, -2);
72
+			},
73
+			parent::getJsonValue()
74
+		);
75 75
 
76
-    }
76
+	}
77 77
 }
Please login to merge, or discard this patch.
libraries/SabreDAV/VObject/Property/ICalendar/DateTime.php 1 patch
Indentation   +375 added lines, -375 removed lines patch added patch discarded remove patch
@@ -26,379 +26,379 @@
 block discarded – undo
26 26
  */
27 27
 class DateTime extends Property {
28 28
 
29
-    /**
30
-     * In case this is a multi-value property. This string will be used as a
31
-     * delimiter.
32
-     *
33
-     * @var string|null
34
-     */
35
-    public $delimiter = ',';
36
-
37
-    /**
38
-     * Sets a multi-valued property.
39
-     *
40
-     * You may also specify DateTime objects here.
41
-     *
42
-     * @param array $parts
43
-     *
44
-     * @return void
45
-     */
46
-    public function setParts(array $parts) {
47
-
48
-        if (isset($parts[0]) && $parts[0] instanceof DateTimeInterface) {
49
-            $this->setDateTimes($parts);
50
-        } else {
51
-            parent::setParts($parts);
52
-        }
53
-
54
-    }
55
-
56
-    /**
57
-     * Updates the current value.
58
-     *
59
-     * This may be either a single, or multiple strings in an array.
60
-     *
61
-     * Instead of strings, you may also use DateTime here.
62
-     *
63
-     * @param string|array|DateTimeInterface $value
64
-     *
65
-     * @return void
66
-     */
67
-    public function setValue($value) {
68
-
69
-        if (is_array($value) && isset($value[0]) && $value[0] instanceof DateTimeInterface) {
70
-            $this->setDateTimes($value);
71
-        } elseif ($value instanceof DateTimeInterface) {
72
-            $this->setDateTimes([$value]);
73
-        } else {
74
-            parent::setValue($value);
75
-        }
76
-
77
-    }
78
-
79
-    /**
80
-     * Sets a raw value coming from a mimedir (iCalendar/vCard) file.
81
-     *
82
-     * This has been 'unfolded', so only 1 line will be passed. Unescaping is
83
-     * not yet done, but parameters are not included.
84
-     *
85
-     * @param string $val
86
-     *
87
-     * @return void
88
-     */
89
-    public function setRawMimeDirValue($val) {
90
-
91
-        $this->setValue(explode($this->delimiter, $val));
92
-
93
-    }
94
-
95
-    /**
96
-     * Returns a raw mime-dir representation of the value.
97
-     *
98
-     * @return string
99
-     */
100
-    public function getRawMimeDirValue() {
101
-
102
-        return implode($this->delimiter, $this->getParts());
103
-
104
-    }
105
-
106
-    /**
107
-     * Returns true if this is a DATE-TIME value, false if it's a DATE.
108
-     *
109
-     * @return bool
110
-     */
111
-    public function hasTime() {
112
-
113
-        return strtoupper((string)$this['VALUE']) !== 'DATE';
114
-
115
-    }
116
-
117
-    /**
118
-     * Returns true if this is a floating DATE or DATE-TIME.
119
-     *
120
-     * Note that DATE is always floating.
121
-     */
122
-    public function isFloating() {
123
-
124
-        return
125
-            !$this->hasTime() ||
126
-            (
127
-                !isset($this['TZID']) &&
128
-                strpos($this->getValue(), 'Z') === false
129
-            );
130
-
131
-    }
132
-
133
-    /**
134
-     * Returns a date-time value.
135
-     *
136
-     * Note that if this property contained more than 1 date-time, only the
137
-     * first will be returned. To get an array with multiple values, call
138
-     * getDateTimes.
139
-     *
140
-     * If no timezone information is known, because it's either an all-day
141
-     * property or floating time, we will use the DateTimeZone argument to
142
-     * figure out the exact date.
143
-     *
144
-     * @param DateTimeZone $timeZone
145
-     *
146
-     * @return DateTimeImmutable
147
-     */
148
-    public function getDateTime(DateTimeZone $timeZone = null) {
149
-
150
-        $dt = $this->getDateTimes($timeZone);
151
-        if (!$dt) return;
152
-
153
-        return $dt[0];
154
-
155
-    }
156
-
157
-    /**
158
-     * Returns multiple date-time values.
159
-     *
160
-     * If no timezone information is known, because it's either an all-day
161
-     * property or floating time, we will use the DateTimeZone argument to
162
-     * figure out the exact date.
163
-     *
164
-     * @param DateTimeZone $timeZone
165
-     *
166
-     * @return DateTimeImmutable[]
167
-     * @return \DateTime[]
168
-     */
169
-    public function getDateTimes(DateTimeZone $timeZone = null) {
170
-
171
-        // Does the property have a TZID?
172
-        $tzid = $this['TZID'];
173
-
174
-        if ($tzid) {
175
-            $timeZone = TimeZoneUtil::getTimeZone((string)$tzid, $this->root);
176
-        }
177
-
178
-        $dts = [];
179
-        foreach ($this->getParts() as $part) {
180
-            $dts[] = DateTimeParser::parse($part, $timeZone);
181
-        }
182
-        return $dts;
183
-
184
-    }
185
-
186
-    /**
187
-     * Sets the property as a DateTime object.
188
-     *
189
-     * @param DateTimeInterface $dt
190
-     * @param bool isFloating If set to true, timezones will be ignored.
191
-     *
192
-     * @return void
193
-     */
194
-    public function setDateTime(DateTimeInterface $dt, $isFloating = false) {
195
-
196
-        $this->setDateTimes([$dt], $isFloating);
197
-
198
-    }
199
-
200
-    /**
201
-     * Sets the property as multiple date-time objects.
202
-     *
203
-     * The first value will be used as a reference for the timezones, and all
204
-     * the otehr values will be adjusted for that timezone
205
-     *
206
-     * @param DateTimeInterface[] $dt
207
-     * @param bool isFloating If set to true, timezones will be ignored.
208
-     *
209
-     * @return void
210
-     */
211
-    public function setDateTimes(array $dt, $isFloating = false) {
212
-
213
-        $values = [];
214
-
215
-        if ($this->hasTime()) {
216
-
217
-            $tz = null;
218
-            $isUtc = false;
219
-
220
-            foreach ($dt as $d) {
221
-
222
-                if ($isFloating) {
223
-                    $values[] = $d->format('Ymd\\THis');
224
-                    continue;
225
-                }
226
-                if (is_null($tz)) {
227
-                    $tz = $d->getTimeZone();
228
-                    $isUtc = in_array($tz->getName(), ['UTC', 'GMT', 'Z', '+00:00']);
229
-                    if (!$isUtc) {
230
-                        $this->offsetSet('TZID', $tz->getName());
231
-                    }
232
-                } else {
233
-                    $d = $d->setTimeZone($tz);
234
-                }
235
-
236
-                if ($isUtc) {
237
-                    $values[] = $d->format('Ymd\\THis\\Z');
238
-                } else {
239
-                    $values[] = $d->format('Ymd\\THis');
240
-                }
241
-
242
-            }
243
-            if ($isUtc || $isFloating) {
244
-                $this->offsetUnset('TZID');
245
-            }
246
-
247
-        } else {
248
-
249
-            foreach ($dt as $d) {
250
-
251
-                $values[] = $d->format('Ymd');
252
-
253
-            }
254
-            $this->offsetUnset('TZID');
255
-
256
-        }
257
-
258
-        $this->value = $values;
259
-
260
-    }
261
-
262
-    /**
263
-     * Returns the type of value.
264
-     *
265
-     * This corresponds to the VALUE= parameter. Every property also has a
266
-     * 'default' valueType.
267
-     *
268
-     * @return string
269
-     */
270
-    public function getValueType() {
271
-
272
-        return $this->hasTime() ? 'DATE-TIME' : 'DATE';
273
-
274
-    }
275
-
276
-    /**
277
-     * Returns the value, in the format it should be encoded for JSON.
278
-     *
279
-     * This method must always return an array.
280
-     *
281
-     * @return array
282
-     */
283
-    public function getJsonValue() {
284
-
285
-        $dts = $this->getDateTimes();
286
-        $hasTime = $this->hasTime();
287
-        $isFloating = $this->isFloating();
288
-
289
-        $tz = $dts[0]->getTimeZone();
290
-        $isUtc = $isFloating ? false : in_array($tz->getName(), ['UTC', 'GMT', 'Z']);
291
-
292
-        return array_map(
293
-            function(DateTimeInterface $dt) use ($hasTime, $isUtc) {
294
-
295
-                if ($hasTime) {
296
-                    return $dt->format('Y-m-d\\TH:i:s') . ($isUtc ? 'Z' : '');
297
-                } else {
298
-                    return $dt->format('Y-m-d');
299
-                }
300
-
301
-            },
302
-            $dts
303
-        );
304
-
305
-    }
306
-
307
-    /**
308
-     * Sets the json value, as it would appear in a jCard or jCal object.
309
-     *
310
-     * The value must always be an array.
311
-     *
312
-     * @param array $value
313
-     *
314
-     * @return void
315
-     */
316
-    public function setJsonValue(array $value) {
317
-
318
-        // dates and times in jCal have one difference to dates and times in
319
-        // iCalendar. In jCal date-parts are separated by dashes, and
320
-        // time-parts are separated by colons. It makes sense to just remove
321
-        // those.
322
-        $this->setValue(
323
-            array_map(
324
-                function($item) {
325
-
326
-                    return strtr($item, [':' => '', '-' => '']);
327
-
328
-                },
329
-                $value
330
-            )
331
-        );
332
-
333
-    }
334
-
335
-    /**
336
-     * We need to intercept offsetSet, because it may be used to alter the
337
-     * VALUE from DATE-TIME to DATE or vice-versa.
338
-     *
339
-     * @param string $name
340
-     * @param mixed $value
341
-     *
342
-     * @return void
343
-     */
344
-    public function offsetSet($name, $value) {
345
-
346
-        parent::offsetSet($name, $value);
347
-        if (strtoupper($name) !== 'VALUE') {
348
-            return;
349
-        }
350
-
351
-        // This will ensure that dates are correctly encoded.
352
-        $this->setDateTimes($this->getDateTimes());
353
-
354
-    }
355
-
356
-    /**
357
-     * Validates the node for correctness.
358
-     *
359
-     * The following options are supported:
360
-     *   Node::REPAIR - May attempt to automatically repair the problem.
361
-     *
362
-     * This method returns an array with detected problems.
363
-     * Every element has the following properties:
364
-     *
365
-     *  * level - problem level.
366
-     *  * message - A human-readable string describing the issue.
367
-     *  * node - A reference to the problematic node.
368
-     *
369
-     * The level means:
370
-     *   1 - The issue was repaired (only happens if REPAIR was turned on)
371
-     *   2 - An inconsequential issue
372
-     *   3 - A severe issue.
373
-     *
374
-     * @param int $options
375
-     *
376
-     * @return array
377
-     */
378
-    public function validate($options = 0) {
379
-
380
-        $messages = parent::validate($options);
381
-        $valueType = $this->getValueType();
382
-        $values = $this->getParts();
383
-        try {
384
-            foreach ($values as $value) {
385
-                switch ($valueType) {
386
-                    case 'DATE' :
387
-                        DateTimeParser::parseDate($value);
388
-                        break;
389
-                    case 'DATE-TIME' :
390
-                        DateTimeParser::parseDateTime($value);
391
-                        break;
392
-                }
393
-            }
394
-        } catch (InvalidDataException $e) {
395
-            $messages[] = [
396
-                'level'   => 3,
397
-                'message' => 'The supplied value (' . $value . ') is not a correct ' . $valueType,
398
-                'node'    => $this,
399
-            ];
400
-        }
401
-        return $messages;
402
-
403
-    }
29
+	/**
30
+	 * In case this is a multi-value property. This string will be used as a
31
+	 * delimiter.
32
+	 *
33
+	 * @var string|null
34
+	 */
35
+	public $delimiter = ',';
36
+
37
+	/**
38
+	 * Sets a multi-valued property.
39
+	 *
40
+	 * You may also specify DateTime objects here.
41
+	 *
42
+	 * @param array $parts
43
+	 *
44
+	 * @return void
45
+	 */
46
+	public function setParts(array $parts) {
47
+
48
+		if (isset($parts[0]) && $parts[0] instanceof DateTimeInterface) {
49
+			$this->setDateTimes($parts);
50
+		} else {
51
+			parent::setParts($parts);
52
+		}
53
+
54
+	}
55
+
56
+	/**
57
+	 * Updates the current value.
58
+	 *
59
+	 * This may be either a single, or multiple strings in an array.
60
+	 *
61
+	 * Instead of strings, you may also use DateTime here.
62
+	 *
63
+	 * @param string|array|DateTimeInterface $value
64
+	 *
65
+	 * @return void
66
+	 */
67
+	public function setValue($value) {
68
+
69
+		if (is_array($value) && isset($value[0]) && $value[0] instanceof DateTimeInterface) {
70
+			$this->setDateTimes($value);
71
+		} elseif ($value instanceof DateTimeInterface) {
72
+			$this->setDateTimes([$value]);
73
+		} else {
74
+			parent::setValue($value);
75
+		}
76
+
77
+	}
78
+
79
+	/**
80
+	 * Sets a raw value coming from a mimedir (iCalendar/vCard) file.
81
+	 *
82
+	 * This has been 'unfolded', so only 1 line will be passed. Unescaping is
83
+	 * not yet done, but parameters are not included.
84
+	 *
85
+	 * @param string $val
86
+	 *
87
+	 * @return void
88
+	 */
89
+	public function setRawMimeDirValue($val) {
90
+
91
+		$this->setValue(explode($this->delimiter, $val));
92
+
93
+	}
94
+
95
+	/**
96
+	 * Returns a raw mime-dir representation of the value.
97
+	 *
98
+	 * @return string
99
+	 */
100
+	public function getRawMimeDirValue() {
101
+
102
+		return implode($this->delimiter, $this->getParts());
103
+
104
+	}
105
+
106
+	/**
107
+	 * Returns true if this is a DATE-TIME value, false if it's a DATE.
108
+	 *
109
+	 * @return bool
110
+	 */
111
+	public function hasTime() {
112
+
113
+		return strtoupper((string)$this['VALUE']) !== 'DATE';
114
+
115
+	}
116
+
117
+	/**
118
+	 * Returns true if this is a floating DATE or DATE-TIME.
119
+	 *
120
+	 * Note that DATE is always floating.
121
+	 */
122
+	public function isFloating() {
123
+
124
+		return
125
+			!$this->hasTime() ||
126
+			(
127
+				!isset($this['TZID']) &&
128
+				strpos($this->getValue(), 'Z') === false
129
+			);
130
+
131
+	}
132
+
133
+	/**
134
+	 * Returns a date-time value.
135
+	 *
136
+	 * Note that if this property contained more than 1 date-time, only the
137
+	 * first will be returned. To get an array with multiple values, call
138
+	 * getDateTimes.
139
+	 *
140
+	 * If no timezone information is known, because it's either an all-day
141
+	 * property or floating time, we will use the DateTimeZone argument to
142
+	 * figure out the exact date.
143
+	 *
144
+	 * @param DateTimeZone $timeZone
145
+	 *
146
+	 * @return DateTimeImmutable
147
+	 */
148
+	public function getDateTime(DateTimeZone $timeZone = null) {
149
+
150
+		$dt = $this->getDateTimes($timeZone);
151
+		if (!$dt) return;
152
+
153
+		return $dt[0];
154
+
155
+	}
156
+
157
+	/**
158
+	 * Returns multiple date-time values.
159
+	 *
160
+	 * If no timezone information is known, because it's either an all-day
161
+	 * property or floating time, we will use the DateTimeZone argument to
162
+	 * figure out the exact date.
163
+	 *
164
+	 * @param DateTimeZone $timeZone
165
+	 *
166
+	 * @return DateTimeImmutable[]
167
+	 * @return \DateTime[]
168
+	 */
169
+	public function getDateTimes(DateTimeZone $timeZone = null) {
170
+
171
+		// Does the property have a TZID?
172
+		$tzid = $this['TZID'];
173
+
174
+		if ($tzid) {
175
+			$timeZone = TimeZoneUtil::getTimeZone((string)$tzid, $this->root);
176
+		}
177
+
178
+		$dts = [];
179
+		foreach ($this->getParts() as $part) {
180
+			$dts[] = DateTimeParser::parse($part, $timeZone);
181
+		}
182
+		return $dts;
183
+
184
+	}
185
+
186
+	/**
187
+	 * Sets the property as a DateTime object.
188
+	 *
189
+	 * @param DateTimeInterface $dt
190
+	 * @param bool isFloating If set to true, timezones will be ignored.
191
+	 *
192
+	 * @return void
193
+	 */
194
+	public function setDateTime(DateTimeInterface $dt, $isFloating = false) {
195
+
196
+		$this->setDateTimes([$dt], $isFloating);
197
+
198
+	}
199
+
200
+	/**
201
+	 * Sets the property as multiple date-time objects.
202
+	 *
203
+	 * The first value will be used as a reference for the timezones, and all
204
+	 * the otehr values will be adjusted for that timezone
205
+	 *
206
+	 * @param DateTimeInterface[] $dt
207
+	 * @param bool isFloating If set to true, timezones will be ignored.
208
+	 *
209
+	 * @return void
210
+	 */
211
+	public function setDateTimes(array $dt, $isFloating = false) {
212
+
213
+		$values = [];
214
+
215
+		if ($this->hasTime()) {
216
+
217
+			$tz = null;
218
+			$isUtc = false;
219
+
220
+			foreach ($dt as $d) {
221
+
222
+				if ($isFloating) {
223
+					$values[] = $d->format('Ymd\\THis');
224
+					continue;
225
+				}
226
+				if (is_null($tz)) {
227
+					$tz = $d->getTimeZone();
228
+					$isUtc = in_array($tz->getName(), ['UTC', 'GMT', 'Z', '+00:00']);
229
+					if (!$isUtc) {
230
+						$this->offsetSet('TZID', $tz->getName());
231
+					}
232
+				} else {
233
+					$d = $d->setTimeZone($tz);
234
+				}
235
+
236
+				if ($isUtc) {
237
+					$values[] = $d->format('Ymd\\THis\\Z');
238
+				} else {
239
+					$values[] = $d->format('Ymd\\THis');
240
+				}
241
+
242
+			}
243
+			if ($isUtc || $isFloating) {
244
+				$this->offsetUnset('TZID');
245
+			}
246
+
247
+		} else {
248
+
249
+			foreach ($dt as $d) {
250
+
251
+				$values[] = $d->format('Ymd');
252
+
253
+			}
254
+			$this->offsetUnset('TZID');
255
+
256
+		}
257
+
258
+		$this->value = $values;
259
+
260
+	}
261
+
262
+	/**
263
+	 * Returns the type of value.
264
+	 *
265
+	 * This corresponds to the VALUE= parameter. Every property also has a
266
+	 * 'default' valueType.
267
+	 *
268
+	 * @return string
269
+	 */
270
+	public function getValueType() {
271
+
272
+		return $this->hasTime() ? 'DATE-TIME' : 'DATE';
273
+
274
+	}
275
+
276
+	/**
277
+	 * Returns the value, in the format it should be encoded for JSON.
278
+	 *
279
+	 * This method must always return an array.
280
+	 *
281
+	 * @return array
282
+	 */
283
+	public function getJsonValue() {
284
+
285
+		$dts = $this->getDateTimes();
286
+		$hasTime = $this->hasTime();
287
+		$isFloating = $this->isFloating();
288
+
289
+		$tz = $dts[0]->getTimeZone();
290
+		$isUtc = $isFloating ? false : in_array($tz->getName(), ['UTC', 'GMT', 'Z']);
291
+
292
+		return array_map(
293
+			function(DateTimeInterface $dt) use ($hasTime, $isUtc) {
294
+
295
+				if ($hasTime) {
296
+					return $dt->format('Y-m-d\\TH:i:s') . ($isUtc ? 'Z' : '');
297
+				} else {
298
+					return $dt->format('Y-m-d');
299
+				}
300
+
301
+			},
302
+			$dts
303
+		);
304
+
305
+	}
306
+
307
+	/**
308
+	 * Sets the json value, as it would appear in a jCard or jCal object.
309
+	 *
310
+	 * The value must always be an array.
311
+	 *
312
+	 * @param array $value
313
+	 *
314
+	 * @return void
315
+	 */
316
+	public function setJsonValue(array $value) {
317
+
318
+		// dates and times in jCal have one difference to dates and times in
319
+		// iCalendar. In jCal date-parts are separated by dashes, and
320
+		// time-parts are separated by colons. It makes sense to just remove
321
+		// those.
322
+		$this->setValue(
323
+			array_map(
324
+				function($item) {
325
+
326
+					return strtr($item, [':' => '', '-' => '']);
327
+
328
+				},
329
+				$value
330
+			)
331
+		);
332
+
333
+	}
334
+
335
+	/**
336
+	 * We need to intercept offsetSet, because it may be used to alter the
337
+	 * VALUE from DATE-TIME to DATE or vice-versa.
338
+	 *
339
+	 * @param string $name
340
+	 * @param mixed $value
341
+	 *
342
+	 * @return void
343
+	 */
344
+	public function offsetSet($name, $value) {
345
+
346
+		parent::offsetSet($name, $value);
347
+		if (strtoupper($name) !== 'VALUE') {
348
+			return;
349
+		}
350
+
351
+		// This will ensure that dates are correctly encoded.
352
+		$this->setDateTimes($this->getDateTimes());
353
+
354
+	}
355
+
356
+	/**
357
+	 * Validates the node for correctness.
358
+	 *
359
+	 * The following options are supported:
360
+	 *   Node::REPAIR - May attempt to automatically repair the problem.
361
+	 *
362
+	 * This method returns an array with detected problems.
363
+	 * Every element has the following properties:
364
+	 *
365
+	 *  * level - problem level.
366
+	 *  * message - A human-readable string describing the issue.
367
+	 *  * node - A reference to the problematic node.
368
+	 *
369
+	 * The level means:
370
+	 *   1 - The issue was repaired (only happens if REPAIR was turned on)
371
+	 *   2 - An inconsequential issue
372
+	 *   3 - A severe issue.
373
+	 *
374
+	 * @param int $options
375
+	 *
376
+	 * @return array
377
+	 */
378
+	public function validate($options = 0) {
379
+
380
+		$messages = parent::validate($options);
381
+		$valueType = $this->getValueType();
382
+		$values = $this->getParts();
383
+		try {
384
+			foreach ($values as $value) {
385
+				switch ($valueType) {
386
+					case 'DATE' :
387
+						DateTimeParser::parseDate($value);
388
+						break;
389
+					case 'DATE-TIME' :
390
+						DateTimeParser::parseDateTime($value);
391
+						break;
392
+				}
393
+			}
394
+		} catch (InvalidDataException $e) {
395
+			$messages[] = [
396
+				'level'   => 3,
397
+				'message' => 'The supplied value (' . $value . ') is not a correct ' . $valueType,
398
+				'node'    => $this,
399
+			];
400
+		}
401
+		return $messages;
402
+
403
+	}
404 404
 }
Please login to merge, or discard this patch.