1<?php 2 3namespace Sabre\VObject\Component; 4 5use DateTimeInterface; 6use Sabre\VObject; 7 8/** 9 * The VAvailability component. 10 * 11 * This component adds functionality to a component, specific for VAVAILABILITY 12 * components. 13 * 14 * @copyright Copyright (C) fruux GmbH (https://fruux.com/) 15 * @author Ivan Enderlin 16 * @license http://sabre.io/license/ Modified BSD License 17 */ 18class VAvailability extends VObject\Component 19{ 20 /** 21 * Returns true or false depending on if the event falls in the specified 22 * time-range. This is used for filtering purposes. 23 * 24 * The rules used to determine if an event falls within the specified 25 * time-range is based on: 26 * 27 * https://tools.ietf.org/html/draft-daboo-calendar-availability-05#section-3.1 28 * 29 * @param DateTimeInterface $start 30 * @param DateTimeInterface $end 31 * 32 * @return bool 33 */ 34 public function isInTimeRange(DateTimeInterface $start, DateTimeInterface $end) 35 { 36 list($effectiveStart, $effectiveEnd) = $this->getEffectiveStartEnd(); 37 38 return 39 (is_null($effectiveStart) || $start < $effectiveEnd) && 40 (is_null($effectiveEnd) || $end > $effectiveStart) 41 ; 42 } 43 44 /** 45 * Returns the 'effective start' and 'effective end' of this VAVAILABILITY 46 * component. 47 * 48 * We use the DTSTART and DTEND or DURATION to determine this. 49 * 50 * The returned value is an array containing DateTimeImmutable instances. 51 * If either the start or end is 'unbounded' its value will be null 52 * instead. 53 * 54 * @return array 55 */ 56 public function getEffectiveStartEnd() 57 { 58 $effectiveStart = null; 59 $effectiveEnd = null; 60 61 if (isset($this->DTSTART)) { 62 $effectiveStart = $this->DTSTART->getDateTime(); 63 } 64 if (isset($this->DTEND)) { 65 $effectiveEnd = $this->DTEND->getDateTime(); 66 } elseif ($effectiveStart && isset($this->DURATION)) { 67 $effectiveEnd = $effectiveStart->add(VObject\DateTimeParser::parseDuration($this->DURATION)); 68 } 69 70 return [$effectiveStart, $effectiveEnd]; 71 } 72 73 /** 74 * A simple list of validation rules. 75 * 76 * This is simply a list of properties, and how many times they either 77 * must or must not appear. 78 * 79 * Possible values per property: 80 * * 0 - Must not appear. 81 * * 1 - Must appear exactly once. 82 * * + - Must appear at least once. 83 * * * - Can appear any number of times. 84 * * ? - May appear, but not more than once. 85 * 86 * @var array 87 */ 88 public function getValidationRules() 89 { 90 return [ 91 'UID' => 1, 92 'DTSTAMP' => 1, 93 94 'BUSYTYPE' => '?', 95 'CLASS' => '?', 96 'CREATED' => '?', 97 'DESCRIPTION' => '?', 98 'DTSTART' => '?', 99 'LAST-MODIFIED' => '?', 100 'ORGANIZER' => '?', 101 'PRIORITY' => '?', 102 'SEQUENCE' => '?', 103 'SUMMARY' => '?', 104 'URL' => '?', 105 'DTEND' => '?', 106 'DURATION' => '?', 107 108 'CATEGORIES' => '*', 109 'COMMENT' => '*', 110 'CONTACT' => '*', 111 ]; 112 } 113 114 /** 115 * Validates the node for correctness. 116 * 117 * The following options are supported: 118 * Node::REPAIR - May attempt to automatically repair the problem. 119 * Node::PROFILE_CARDDAV - Validate the vCard for CardDAV purposes. 120 * Node::PROFILE_CALDAV - Validate the iCalendar for CalDAV purposes. 121 * 122 * This method returns an array with detected problems. 123 * Every element has the following properties: 124 * 125 * * level - problem level. 126 * * message - A human-readable string describing the issue. 127 * * node - A reference to the problematic node. 128 * 129 * The level means: 130 * 1 - The issue was repaired (only happens if REPAIR was turned on). 131 * 2 - A warning. 132 * 3 - An error. 133 * 134 * @param int $options 135 * 136 * @return array 137 */ 138 public function validate($options = 0) 139 { 140 $result = parent::validate($options); 141 142 if (isset($this->DTEND) && isset($this->DURATION)) { 143 $result[] = [ 144 'level' => 3, 145 'message' => 'DTEND and DURATION cannot both be present', 146 'node' => $this, 147 ]; 148 } 149 150 return $result; 151 } 152} 153