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 } |
