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 }