1<?php 2 3namespace Sabre\VObject\Component; 4 5use DateTimeImmutable; 6use DateTimeInterface; 7use Sabre\VObject; 8use Sabre\VObject\InvalidDataException; 9 10/** 11 * VAlarm component. 12 * 13 * This component contains some additional functionality specific for VALARMs. 14 * 15 * @copyright Copyright (C) fruux GmbH (https://fruux.com/) 16 * @author Evert Pot (http://evertpot.com/) 17 * @license http://sabre.io/license/ Modified BSD License 18 */ 19class VAlarm extends VObject\Component 20{ 21 /** 22 * Returns a DateTime object when this alarm is going to trigger. 23 * 24 * This ignores repeated alarm, only the first trigger is returned. 25 * 26 * @return DateTimeImmutable 27 */ 28 public function getEffectiveTriggerTime() 29 { 30 $trigger = $this->TRIGGER; 31 if (!isset($trigger['VALUE']) || 'DURATION' === strtoupper($trigger['VALUE'])) { 32 $triggerDuration = VObject\DateTimeParser::parseDuration($this->TRIGGER); 33 $related = (isset($trigger['RELATED']) && 'END' == strtoupper($trigger['RELATED'])) ? 'END' : 'START'; 34 35 $parentComponent = $this->parent; 36 if ('START' === $related) { 37 if ('VTODO' === $parentComponent->name) { 38 $propName = 'DUE'; 39 } else { 40 $propName = 'DTSTART'; 41 } 42 43 $effectiveTrigger = $parentComponent->$propName->getDateTime(); 44 $effectiveTrigger = $effectiveTrigger->add($triggerDuration); 45 } else { 46 if ('VTODO' === $parentComponent->name) { 47 $endProp = 'DUE'; 48 } elseif ('VEVENT' === $parentComponent->name) { 49 $endProp = 'DTEND'; 50 } else { 51 throw new InvalidDataException('time-range filters on VALARM components are only supported when they are a child of VTODO or VEVENT'); 52 } 53 54 if (isset($parentComponent->$endProp)) { 55 $effectiveTrigger = $parentComponent->$endProp->getDateTime(); 56 $effectiveTrigger = $effectiveTrigger->add($triggerDuration); 57 } elseif (isset($parentComponent->DURATION)) { 58 $effectiveTrigger = $parentComponent->DTSTART->getDateTime(); 59 $duration = VObject\DateTimeParser::parseDuration($parentComponent->DURATION); 60 $effectiveTrigger = $effectiveTrigger->add($duration); 61 $effectiveTrigger = $effectiveTrigger->add($triggerDuration); 62 } else { 63 $effectiveTrigger = $parentComponent->DTSTART->getDateTime(); 64 $effectiveTrigger = $effectiveTrigger->add($triggerDuration); 65 } 66 } 67 } else { 68 $effectiveTrigger = $trigger->getDateTime(); 69 } 70 71 return $effectiveTrigger; 72 } 73 74 /** 75 * Returns true or false depending on if the event falls in the specified 76 * time-range. This is used for filtering purposes. 77 * 78 * The rules used to determine if an event falls within the specified 79 * time-range is based on the CalDAV specification. 80 * 81 * @param DateTime $start 82 * @param DateTime $end 83 * 84 * @return bool 85 */ 86 public function isInTimeRange(DateTimeInterface $start, DateTimeInterface $end) 87 { 88 $effectiveTrigger = $this->getEffectiveTriggerTime(); 89 90 if (isset($this->DURATION)) { 91 $duration = VObject\DateTimeParser::parseDuration($this->DURATION); 92 $repeat = (string) $this->REPEAT; 93 if (!$repeat) { 94 $repeat = 1; 95 } 96 97 $period = new \DatePeriod($effectiveTrigger, $duration, (int) $repeat); 98 99 foreach ($period as $occurrence) { 100 if ($start <= $occurrence && $end > $occurrence) { 101 return true; 102 } 103 } 104 105 return false; 106 } else { 107 return $start <= $effectiveTrigger && $end > $effectiveTrigger; 108 } 109 } 110 111 /** 112 * A simple list of validation rules. 113 * 114 * This is simply a list of properties, and how many times they either 115 * must or must not appear. 116 * 117 * Possible values per property: 118 * * 0 - Must not appear. 119 * * 1 - Must appear exactly once. 120 * * + - Must appear at least once. 121 * * * - Can appear any number of times. 122 * * ? - May appear, but not more than once. 123 * 124 * @var array 125 */ 126 public function getValidationRules() 127 { 128 return [ 129 'ACTION' => 1, 130 'TRIGGER' => 1, 131 132 'DURATION' => '?', 133 'REPEAT' => '?', 134 135 'ATTACH' => '?', 136 ]; 137 } 138} 139