Mercurial > hg > rc1
comparison vendor/sabre/vobject/lib/Property/ICalendar/DateTime.php @ 7:430dbd5346f7
vendor sabre as distributed
| author | Charlie Root |
|---|---|
| date | Sat, 13 Jan 2018 09:06:10 -0500 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 6:cec75ba50afc | 7:430dbd5346f7 |
|---|---|
| 1 <?php | |
| 2 | |
| 3 namespace Sabre\VObject\Property\ICalendar; | |
| 4 | |
| 5 use DateTimeZone; | |
| 6 use Sabre\VObject\Property; | |
| 7 use Sabre\VObject\DateTimeParser; | |
| 8 use Sabre\VObject\TimeZoneUtil; | |
| 9 | |
| 10 /** | |
| 11 * DateTime property | |
| 12 * | |
| 13 * This object represents DATE-TIME values, as defined here: | |
| 14 * | |
| 15 * http://tools.ietf.org/html/rfc5545#section-3.3.4 | |
| 16 * | |
| 17 * This particular object has a bit of hackish magic that it may also in some | |
| 18 * cases represent a DATE value. This is because it's a common usecase to be | |
| 19 * able to change a DATE-TIME into a DATE. | |
| 20 * | |
| 21 * @copyright Copyright (C) 2011-2015 fruux GmbH (https://fruux.com/). | |
| 22 * @author Evert Pot (http://evertpot.com/) | |
| 23 * @license http://sabre.io/license/ Modified BSD License | |
| 24 */ | |
| 25 class DateTime extends Property { | |
| 26 | |
| 27 /** | |
| 28 * In case this is a multi-value property. This string will be used as a | |
| 29 * delimiter. | |
| 30 * | |
| 31 * @var string|null | |
| 32 */ | |
| 33 public $delimiter = ','; | |
| 34 | |
| 35 /** | |
| 36 * Sets a multi-valued property. | |
| 37 * | |
| 38 * You may also specify DateTime objects here. | |
| 39 * | |
| 40 * @param array $parts | |
| 41 * @return void | |
| 42 */ | |
| 43 public function setParts(array $parts) { | |
| 44 | |
| 45 if (isset($parts[0]) && $parts[0] instanceof \DateTime) { | |
| 46 $this->setDateTimes($parts); | |
| 47 } else { | |
| 48 parent::setParts($parts); | |
| 49 } | |
| 50 | |
| 51 } | |
| 52 | |
| 53 /** | |
| 54 * Updates the current value. | |
| 55 * | |
| 56 * This may be either a single, or multiple strings in an array. | |
| 57 * | |
| 58 * Instead of strings, you may also use DateTime here. | |
| 59 * | |
| 60 * @param string|array|\DateTime $value | |
| 61 * @return void | |
| 62 */ | |
| 63 public function setValue($value) { | |
| 64 | |
| 65 if (is_array($value) && isset($value[0]) && $value[0] instanceof \DateTime) { | |
| 66 $this->setDateTimes($value); | |
| 67 } elseif ($value instanceof \DateTime) { | |
| 68 $this->setDateTimes(array($value)); | |
| 69 } else { | |
| 70 parent::setValue($value); | |
| 71 } | |
| 72 | |
| 73 } | |
| 74 | |
| 75 /** | |
| 76 * Sets a raw value coming from a mimedir (iCalendar/vCard) file. | |
| 77 * | |
| 78 * This has been 'unfolded', so only 1 line will be passed. Unescaping is | |
| 79 * not yet done, but parameters are not included. | |
| 80 * | |
| 81 * @param string $val | |
| 82 * @return void | |
| 83 */ | |
| 84 public function setRawMimeDirValue($val) { | |
| 85 | |
| 86 $this->setValue(explode($this->delimiter, $val)); | |
| 87 | |
| 88 } | |
| 89 | |
| 90 /** | |
| 91 * Returns a raw mime-dir representation of the value. | |
| 92 * | |
| 93 * @return string | |
| 94 */ | |
| 95 public function getRawMimeDirValue() { | |
| 96 | |
| 97 return implode($this->delimiter, $this->getParts()); | |
| 98 | |
| 99 } | |
| 100 | |
| 101 /** | |
| 102 * Returns true if this is a DATE-TIME value, false if it's a DATE. | |
| 103 * | |
| 104 * @return bool | |
| 105 */ | |
| 106 public function hasTime() { | |
| 107 | |
| 108 return strtoupper((string)$this['VALUE']) !== 'DATE'; | |
| 109 | |
| 110 } | |
| 111 | |
| 112 /** | |
| 113 * Returns true if this is a floating DATE or DATE-TIME. | |
| 114 * | |
| 115 * Note that DATE is always floating. | |
| 116 */ | |
| 117 public function isFloating() { | |
| 118 | |
| 119 return | |
| 120 !$this->hasTime() || | |
| 121 ( | |
| 122 !isset($this['TZID']) && | |
| 123 strpos($this->getValue(),'Z')===false | |
| 124 ); | |
| 125 | |
| 126 } | |
| 127 | |
| 128 /** | |
| 129 * Returns a date-time value. | |
| 130 * | |
| 131 * Note that if this property contained more than 1 date-time, only the | |
| 132 * first will be returned. To get an array with multiple values, call | |
| 133 * getDateTimes. | |
| 134 * | |
| 135 * If no timezone information is known, because it's either an all-day | |
| 136 * property or floating time, we will use the DateTimeZone argument to | |
| 137 * figure out the exact date. | |
| 138 * | |
| 139 * @param DateTimeZone $timeZone | |
| 140 * @return \DateTime | |
| 141 */ | |
| 142 public function getDateTime(DateTimeZone $timeZone = null) { | |
| 143 | |
| 144 $dt = $this->getDateTimes($timeZone); | |
| 145 if (!$dt) return null; | |
| 146 | |
| 147 return $dt[0]; | |
| 148 | |
| 149 } | |
| 150 | |
| 151 /** | |
| 152 * Returns multiple date-time values. | |
| 153 * | |
| 154 * If no timezone information is known, because it's either an all-day | |
| 155 * property or floating time, we will use the DateTimeZone argument to | |
| 156 * figure out the exact date. | |
| 157 * | |
| 158 * @param DateTimeZone $timeZone | |
| 159 * @return \DateTime[] | |
| 160 */ | |
| 161 public function getDateTimes(DateTimeZone $timeZone = null) { | |
| 162 | |
| 163 // Does the property have a TZID? | |
| 164 $tzid = $this['TZID']; | |
| 165 | |
| 166 if ($tzid) { | |
| 167 $timeZone = TimeZoneUtil::getTimeZone((string)$tzid, $this->root); | |
| 168 } | |
| 169 | |
| 170 $dts = array(); | |
| 171 foreach($this->getParts() as $part) { | |
| 172 $dts[] = DateTimeParser::parse($part, $timeZone); | |
| 173 } | |
| 174 return $dts; | |
| 175 | |
| 176 } | |
| 177 | |
| 178 /** | |
| 179 * Sets the property as a DateTime object. | |
| 180 * | |
| 181 * @param \DateTime $dt | |
| 182 * @param bool isFloating If set to true, timezones will be ignored. | |
| 183 * @return void | |
| 184 */ | |
| 185 public function setDateTime(\DateTime $dt, $isFloating = false) { | |
| 186 | |
| 187 $this->setDateTimes(array($dt), $isFloating); | |
| 188 | |
| 189 } | |
| 190 | |
| 191 /** | |
| 192 * Sets the property as multiple date-time objects. | |
| 193 * | |
| 194 * The first value will be used as a reference for the timezones, and all | |
| 195 * the otehr values will be adjusted for that timezone | |
| 196 * | |
| 197 * @param \DateTime[] $dt | |
| 198 * @param bool isFloating If set to true, timezones will be ignored. | |
| 199 * @return void | |
| 200 */ | |
| 201 public function setDateTimes(array $dt, $isFloating = false) { | |
| 202 | |
| 203 $values = array(); | |
| 204 | |
| 205 if($this->hasTime()) { | |
| 206 | |
| 207 $tz = null; | |
| 208 $isUtc = false; | |
| 209 | |
| 210 foreach($dt as $d) { | |
| 211 | |
| 212 if ($isFloating) { | |
| 213 $values[] = $d->format('Ymd\\THis'); | |
| 214 continue; | |
| 215 } | |
| 216 if (is_null($tz)) { | |
| 217 $tz = $d->getTimeZone(); | |
| 218 $isUtc = in_array($tz->getName() , array('UTC', 'GMT', 'Z')); | |
| 219 if (!$isUtc) { | |
| 220 $this->offsetSet('TZID', $tz->getName()); | |
| 221 } | |
| 222 } else { | |
| 223 $d->setTimeZone($tz); | |
| 224 } | |
| 225 | |
| 226 if ($isUtc) { | |
| 227 $values[] = $d->format('Ymd\\THis\\Z'); | |
| 228 } else { | |
| 229 $values[] = $d->format('Ymd\\THis'); | |
| 230 } | |
| 231 | |
| 232 } | |
| 233 if ($isUtc || $isFloating) { | |
| 234 $this->offsetUnset('TZID'); | |
| 235 } | |
| 236 | |
| 237 } else { | |
| 238 | |
| 239 foreach($dt as $d) { | |
| 240 | |
| 241 $values[] = $d->format('Ymd'); | |
| 242 | |
| 243 } | |
| 244 $this->offsetUnset('TZID'); | |
| 245 | |
| 246 } | |
| 247 | |
| 248 $this->value = $values; | |
| 249 | |
| 250 } | |
| 251 | |
| 252 /** | |
| 253 * Returns the type of value. | |
| 254 * | |
| 255 * This corresponds to the VALUE= parameter. Every property also has a | |
| 256 * 'default' valueType. | |
| 257 * | |
| 258 * @return string | |
| 259 */ | |
| 260 public function getValueType() { | |
| 261 | |
| 262 return $this->hasTime()?'DATE-TIME':'DATE'; | |
| 263 | |
| 264 } | |
| 265 | |
| 266 /** | |
| 267 * Returns the value, in the format it should be encoded for json. | |
| 268 * | |
| 269 * This method must always return an array. | |
| 270 * | |
| 271 * @return array | |
| 272 */ | |
| 273 public function getJsonValue() { | |
| 274 | |
| 275 $dts = $this->getDateTimes(); | |
| 276 $hasTime = $this->hasTime(); | |
| 277 $isFloating = $this->isFloating(); | |
| 278 | |
| 279 $tz = $dts[0]->getTimeZone(); | |
| 280 $isUtc = $isFloating ? false : in_array($tz->getName() , array('UTC', 'GMT', 'Z')); | |
| 281 | |
| 282 return array_map( | |
| 283 function($dt) use ($hasTime, $isUtc) { | |
| 284 | |
| 285 if ($hasTime) { | |
| 286 return $dt->format('Y-m-d\\TH:i:s') . ($isUtc?'Z':''); | |
| 287 } else { | |
| 288 return $dt->format('Y-m-d'); | |
| 289 } | |
| 290 | |
| 291 }, | |
| 292 $dts | |
| 293 ); | |
| 294 | |
| 295 } | |
| 296 | |
| 297 /** | |
| 298 * Sets the json value, as it would appear in a jCard or jCal object. | |
| 299 * | |
| 300 * The value must always be an array. | |
| 301 * | |
| 302 * @param array $value | |
| 303 * @return void | |
| 304 */ | |
| 305 public function setJsonValue(array $value) { | |
| 306 | |
| 307 // dates and times in jCal have one difference to dates and times in | |
| 308 // iCalendar. In jCal date-parts are separated by dashes, and | |
| 309 // time-parts are separated by colons. It makes sense to just remove | |
| 310 // those. | |
| 311 $this->setValue( | |
| 312 array_map( | |
| 313 function($item) { | |
| 314 | |
| 315 return strtr($item, array(':'=>'', '-'=>'')); | |
| 316 | |
| 317 }, | |
| 318 $value | |
| 319 ) | |
| 320 ); | |
| 321 | |
| 322 } | |
| 323 /** | |
| 324 * We need to intercept offsetSet, because it may be used to alter the | |
| 325 * VALUE from DATE-TIME to DATE or vice-versa. | |
| 326 * | |
| 327 * @param string $name | |
| 328 * @param mixed $value | |
| 329 * @return void | |
| 330 */ | |
| 331 public function offsetSet($name, $value) { | |
| 332 | |
| 333 parent::offsetSet($name, $value); | |
| 334 if (strtoupper($name)!=='VALUE') { | |
| 335 return; | |
| 336 } | |
| 337 | |
| 338 // This will ensure that dates are correctly encoded. | |
| 339 $this->setDateTimes($this->getDateTimes()); | |
| 340 | |
| 341 } | |
| 342 | |
| 343 /** | |
| 344 * Validates the node for correctness. | |
| 345 * | |
| 346 * The following options are supported: | |
| 347 * Node::REPAIR - May attempt to automatically repair the problem. | |
| 348 * | |
| 349 * This method returns an array with detected problems. | |
| 350 * Every element has the following properties: | |
| 351 * | |
| 352 * * level - problem level. | |
| 353 * * message - A human-readable string describing the issue. | |
| 354 * * node - A reference to the problematic node. | |
| 355 * | |
| 356 * The level means: | |
| 357 * 1 - The issue was repaired (only happens if REPAIR was turned on) | |
| 358 * 2 - An inconsequential issue | |
| 359 * 3 - A severe issue. | |
| 360 * | |
| 361 * @param int $options | |
| 362 * @return array | |
| 363 */ | |
| 364 public function validate($options = 0) { | |
| 365 | |
| 366 $messages = parent::validate($options); | |
| 367 $valueType = $this->getValueType(); | |
| 368 $value = $this->getValue(); | |
| 369 try { | |
| 370 switch($valueType) { | |
| 371 case 'DATE' : | |
| 372 $foo = DateTimeParser::parseDate($value); | |
| 373 break; | |
| 374 case 'DATE-TIME' : | |
| 375 $foo = DateTimeParser::parseDateTime($value); | |
| 376 break; | |
| 377 } | |
| 378 } catch (\LogicException $e) { | |
| 379 $messages[] = array( | |
| 380 'level' => 3, | |
| 381 'message' => 'The supplied value (' . $value . ') is not a correct ' . $valueType, | |
| 382 'node' => $this, | |
| 383 ); | |
| 384 } | |
| 385 return $messages; | |
| 386 | |
| 387 } | |
| 388 } |
