Mercurial > hg > rc1
comparison plugins/libcalendaring/lib/Sabre/VObject/Property.php @ 4:888e774ee983
libcalendar plugin as distributed
author | Charlie Root |
---|---|
date | Sat, 13 Jan 2018 08:57:56 -0500 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
3:f6fe4b6ae66a | 4:888e774ee983 |
---|---|
1 <?php | |
2 | |
3 namespace Sabre\VObject; | |
4 | |
5 /** | |
6 * VObject Property | |
7 * | |
8 * A property in VObject is usually in the form PARAMNAME:paramValue. | |
9 * An example is : SUMMARY:Weekly meeting | |
10 * | |
11 * Properties can also have parameters: | |
12 * SUMMARY;LANG=en:Weekly meeting. | |
13 * | |
14 * Parameters can be accessed using the ArrayAccess interface. | |
15 * | |
16 * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/). | |
17 * @author Evert Pot (http://evertpot.com/) | |
18 * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License | |
19 */ | |
20 class Property extends Node { | |
21 | |
22 /** | |
23 * Propertyname | |
24 * | |
25 * @var string | |
26 */ | |
27 public $name; | |
28 | |
29 /** | |
30 * Group name | |
31 * | |
32 * This may be something like 'HOME' for vcards. | |
33 * | |
34 * @var string | |
35 */ | |
36 public $group; | |
37 | |
38 /** | |
39 * Property parameters | |
40 * | |
41 * @var array | |
42 */ | |
43 public $parameters = array(); | |
44 | |
45 /** | |
46 * Property value | |
47 * | |
48 * @var string | |
49 */ | |
50 public $value; | |
51 | |
52 /** | |
53 * If properties are added to this map, they will be automatically mapped | |
54 * to their respective classes, if parsed by the reader or constructed with | |
55 * the 'create' method. | |
56 * | |
57 * @var array | |
58 */ | |
59 static public $classMap = array( | |
60 'COMPLETED' => 'Sabre\\VObject\\Property\\DateTime', | |
61 'CREATED' => 'Sabre\\VObject\\Property\\DateTime', | |
62 'DTEND' => 'Sabre\\VObject\\Property\\DateTime', | |
63 'DTSTAMP' => 'Sabre\\VObject\\Property\\DateTime', | |
64 'DTSTART' => 'Sabre\\VObject\\Property\\DateTime', | |
65 'DUE' => 'Sabre\\VObject\\Property\\DateTime', | |
66 'EXDATE' => 'Sabre\\VObject\\Property\\MultiDateTime', | |
67 'LAST-MODIFIED' => 'Sabre\\VObject\\Property\\DateTime', | |
68 'RECURRENCE-ID' => 'Sabre\\VObject\\Property\\DateTime', | |
69 'TRIGGER' => 'Sabre\\VObject\\Property\\DateTime', | |
70 'N' => 'Sabre\\VObject\\Property\\Compound', | |
71 'ORG' => 'Sabre\\VObject\\Property\\Compound', | |
72 'ADR' => 'Sabre\\VObject\\Property\\Compound', | |
73 'CATEGORIES' => 'Sabre\\VObject\\Property\\Compound', | |
74 ); | |
75 | |
76 /** | |
77 * Creates the new property by name, but in addition will also see if | |
78 * there's a class mapped to the property name. | |
79 * | |
80 * Parameters can be specified with the optional third argument. Parameters | |
81 * must be a key->value map of the parameter name, and value. If the value | |
82 * is specified as an array, it is assumed that multiple parameters with | |
83 * the same name should be added. | |
84 * | |
85 * @param string $name | |
86 * @param string $value | |
87 * @param array $parameters | |
88 * @return Property | |
89 */ | |
90 static public function create($name, $value = null, array $parameters = array()) { | |
91 | |
92 $name = strtoupper($name); | |
93 $shortName = $name; | |
94 $group = null; | |
95 if (strpos($shortName,'.')!==false) { | |
96 list($group, $shortName) = explode('.', $shortName); | |
97 } | |
98 | |
99 if (isset(self::$classMap[$shortName])) { | |
100 return new self::$classMap[$shortName]($name, $value, $parameters); | |
101 } else { | |
102 return new self($name, $value, $parameters); | |
103 } | |
104 | |
105 } | |
106 | |
107 /** | |
108 * Creates a new property object | |
109 * | |
110 * Parameters can be specified with the optional third argument. Parameters | |
111 * must be a key->value map of the parameter name, and value. If the value | |
112 * is specified as an array, it is assumed that multiple parameters with | |
113 * the same name should be added. | |
114 * | |
115 * @param string $name | |
116 * @param string $value | |
117 * @param array $parameters | |
118 */ | |
119 public function __construct($name, $value = null, array $parameters = array()) { | |
120 | |
121 if (!is_scalar($value) && !is_null($value)) { | |
122 throw new \InvalidArgumentException('The value argument must be scalar or null'); | |
123 } | |
124 | |
125 $name = strtoupper($name); | |
126 $group = null; | |
127 if (strpos($name,'.')!==false) { | |
128 list($group, $name) = explode('.', $name); | |
129 } | |
130 $this->name = $name; | |
131 $this->group = $group; | |
132 $this->setValue($value); | |
133 | |
134 foreach($parameters as $paramName => $paramValues) { | |
135 | |
136 if (!is_array($paramValues)) { | |
137 $paramValues = array($paramValues); | |
138 } | |
139 | |
140 foreach($paramValues as $paramValue) { | |
141 $this->add($paramName, $paramValue); | |
142 } | |
143 | |
144 } | |
145 | |
146 } | |
147 | |
148 /** | |
149 * Updates the internal value | |
150 * | |
151 * @param string $value | |
152 * @return void | |
153 */ | |
154 public function setValue($value) { | |
155 | |
156 $this->value = $value; | |
157 | |
158 } | |
159 | |
160 /** | |
161 * Returns the internal value | |
162 * | |
163 * @param string $value | |
164 * @return string | |
165 */ | |
166 public function getValue() { | |
167 | |
168 return $this->value; | |
169 | |
170 } | |
171 | |
172 /** | |
173 * Turns the object back into a serialized blob. | |
174 * | |
175 * @return string | |
176 */ | |
177 public function serialize() { | |
178 | |
179 $str = $this->name; | |
180 if ($this->group) $str = $this->group . '.' . $this->name; | |
181 | |
182 foreach($this->parameters as $param) { | |
183 | |
184 $str.=';' . $param->serialize(); | |
185 | |
186 } | |
187 | |
188 $src = array( | |
189 '\\', | |
190 "\n", | |
191 "\r", | |
192 ); | |
193 $out = array( | |
194 '\\\\', | |
195 '\n', | |
196 '', | |
197 ); | |
198 | |
199 // avoid double-escaping of \, and \; from Compound properties | |
200 if (method_exists($this, 'setParts')) { | |
201 $src[] = '\\\\,'; | |
202 $out[] = '\\,'; | |
203 $src[] = '\\\\;'; | |
204 $out[] = '\\;'; | |
205 } | |
206 | |
207 $str.=':' . str_replace($src, $out, $this->value); | |
208 | |
209 $out = ''; | |
210 while(strlen($str)>0) { | |
211 if (strlen($str)>75) { | |
212 $out.= mb_strcut($str,0,75,'utf-8') . "\r\n"; | |
213 $str = ' ' . mb_strcut($str,75,strlen($str),'utf-8'); | |
214 } else { | |
215 $out.=$str . "\r\n"; | |
216 $str=''; | |
217 break; | |
218 } | |
219 } | |
220 | |
221 return $out; | |
222 | |
223 } | |
224 | |
225 /** | |
226 * Adds a new componenten or element | |
227 * | |
228 * You can call this method with the following syntaxes: | |
229 * | |
230 * add(Parameter $element) | |
231 * add(string $name, $value) | |
232 * | |
233 * The first version adds an Parameter | |
234 * The second adds a property as a string. | |
235 * | |
236 * @param mixed $item | |
237 * @param mixed $itemValue | |
238 * @return void | |
239 */ | |
240 public function add($item, $itemValue = null) { | |
241 | |
242 if ($item instanceof Parameter) { | |
243 if (!is_null($itemValue)) { | |
244 throw new \InvalidArgumentException('The second argument must not be specified, when passing a VObject'); | |
245 } | |
246 $item->parent = $this; | |
247 $this->parameters[] = $item; | |
248 } elseif(is_string($item)) { | |
249 | |
250 $parameter = new Parameter($item,$itemValue); | |
251 $parameter->parent = $this; | |
252 $this->parameters[] = $parameter; | |
253 | |
254 } else { | |
255 | |
256 throw new \InvalidArgumentException('The first argument must either be a Node a string'); | |
257 | |
258 } | |
259 | |
260 } | |
261 | |
262 /* ArrayAccess interface {{{ */ | |
263 | |
264 /** | |
265 * Checks if an array element exists | |
266 * | |
267 * @param mixed $name | |
268 * @return bool | |
269 */ | |
270 public function offsetExists($name) { | |
271 | |
272 if (is_int($name)) return parent::offsetExists($name); | |
273 | |
274 $name = strtoupper($name); | |
275 | |
276 foreach($this->parameters as $parameter) { | |
277 if ($parameter->name == $name) return true; | |
278 } | |
279 return false; | |
280 | |
281 } | |
282 | |
283 /** | |
284 * Returns a parameter, or parameter list. | |
285 * | |
286 * @param string $name | |
287 * @return Node | |
288 */ | |
289 public function offsetGet($name) { | |
290 | |
291 if (is_int($name)) return parent::offsetGet($name); | |
292 $name = strtoupper($name); | |
293 | |
294 $result = array(); | |
295 foreach($this->parameters as $parameter) { | |
296 if ($parameter->name == $name) | |
297 $result[] = $parameter; | |
298 } | |
299 | |
300 if (count($result)===0) { | |
301 return null; | |
302 } elseif (count($result)===1) { | |
303 return $result[0]; | |
304 } else { | |
305 $result[0]->setIterator(new ElementList($result)); | |
306 return $result[0]; | |
307 } | |
308 | |
309 } | |
310 | |
311 /** | |
312 * Creates a new parameter | |
313 * | |
314 * @param string $name | |
315 * @param mixed $value | |
316 * @return void | |
317 */ | |
318 public function offsetSet($name, $value) { | |
319 | |
320 if (is_int($name)) parent::offsetSet($name, $value); | |
321 | |
322 if (is_scalar($value)) { | |
323 if (!is_string($name)) | |
324 throw new \InvalidArgumentException('A parameter name must be specified. This means you cannot use the $array[]="string" to add parameters.'); | |
325 | |
326 $this->offsetUnset($name); | |
327 $parameter = new Parameter($name, $value); | |
328 $parameter->parent = $this; | |
329 $this->parameters[] = $parameter; | |
330 | |
331 } elseif ($value instanceof Parameter) { | |
332 if (!is_null($name)) | |
333 throw new \InvalidArgumentException('Don\'t specify a parameter name if you\'re passing a \\Sabre\\VObject\\Parameter. Add using $array[]=$parameterObject.'); | |
334 | |
335 $value->parent = $this; | |
336 $this->parameters[] = $value; | |
337 } else { | |
338 throw new \InvalidArgumentException('You can only add parameters to the property object'); | |
339 } | |
340 | |
341 } | |
342 | |
343 /** | |
344 * Removes one or more parameters with the specified name | |
345 * | |
346 * @param string $name | |
347 * @return void | |
348 */ | |
349 public function offsetUnset($name) { | |
350 | |
351 if (is_int($name)) parent::offsetUnset($name); | |
352 $name = strtoupper($name); | |
353 | |
354 foreach($this->parameters as $key=>$parameter) { | |
355 if ($parameter->name == $name) { | |
356 $parameter->parent = null; | |
357 unset($this->parameters[$key]); | |
358 } | |
359 | |
360 } | |
361 | |
362 } | |
363 | |
364 /* }}} */ | |
365 | |
366 /** | |
367 * Called when this object is being cast to a string | |
368 * | |
369 * @return string | |
370 */ | |
371 public function __toString() { | |
372 | |
373 return (string)$this->value; | |
374 | |
375 } | |
376 | |
377 /** | |
378 * This method is automatically called when the object is cloned. | |
379 * Specifically, this will ensure all child elements are also cloned. | |
380 * | |
381 * @return void | |
382 */ | |
383 public function __clone() { | |
384 | |
385 foreach($this->parameters as $key=>$child) { | |
386 $this->parameters[$key] = clone $child; | |
387 $this->parameters[$key]->parent = $this; | |
388 } | |
389 | |
390 } | |
391 | |
392 /** | |
393 * Validates the node for correctness. | |
394 * | |
395 * The following options are supported: | |
396 * - Node::REPAIR - If something is broken, and automatic repair may | |
397 * be attempted. | |
398 * | |
399 * An array is returned with warnings. | |
400 * | |
401 * Every item in the array has the following properties: | |
402 * * level - (number between 1 and 3 with severity information) | |
403 * * message - (human readable message) | |
404 * * node - (reference to the offending node) | |
405 * | |
406 * @param int $options | |
407 * @return array | |
408 */ | |
409 public function validate($options = 0) { | |
410 | |
411 $warnings = array(); | |
412 | |
413 // Checking if our value is UTF-8 | |
414 if (!StringUtil::isUTF8($this->value)) { | |
415 $warnings[] = array( | |
416 'level' => 1, | |
417 'message' => 'Property is not valid UTF-8!', | |
418 'node' => $this, | |
419 ); | |
420 if ($options & self::REPAIR) { | |
421 $this->value = StringUtil::convertToUTF8($this->value); | |
422 } | |
423 } | |
424 | |
425 // Checking if the propertyname does not contain any invalid bytes. | |
426 if (!preg_match('/^([A-Z0-9-]+)$/', $this->name)) { | |
427 $warnings[] = array( | |
428 'level' => 1, | |
429 'message' => 'The propertyname: ' . $this->name . ' contains invalid characters. Only A-Z, 0-9 and - are allowed', | |
430 'node' => $this, | |
431 ); | |
432 if ($options & self::REPAIR) { | |
433 // Uppercasing and converting underscores to dashes. | |
434 $this->name = strtoupper( | |
435 str_replace('_', '-', $this->name) | |
436 ); | |
437 // Removing every other invalid character | |
438 $this->name = preg_replace('/([^A-Z0-9-])/u', '', $this->name); | |
439 | |
440 } | |
441 | |
442 } | |
443 | |
444 // Validating inner parameters | |
445 foreach($this->parameters as $param) { | |
446 $warnings = array_merge($warnings, $param->validate($options)); | |
447 } | |
448 | |
449 return $warnings; | |
450 | |
451 } | |
452 | |
453 } |