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 function isInTimeRange(DateTimeInterface $start, DateTimeInterface $end) { 35 36 list($effectiveStart, $effectiveEnd) = $this->getEffectiveStartEnd(); 37 return ( 38 (is_null($effectiveStart) || $start < $effectiveEnd) && 39 (is_null($effectiveEnd) || $end > $effectiveStart) 40 ); 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 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 75 /** 76 * A simple list of validation rules. 77 * 78 * This is simply a list of properties, and how many times they either 79 * must or must not appear. 80 * 81 * Possible values per property: 82 * * 0 - Must not appear. 83 * * 1 - Must appear exactly once. 84 * * + - Must appear at least once. 85 * * * - Can appear any number of times. 86 * * ? - May appear, but not more than once. 87 * 88 * @var array 89 */ 90 function getValidationRules() { 91 92 return [ 93 'UID' => 1, 94 'DTSTAMP' => 1, 95 96 'BUSYTYPE' => '?', 97 'CLASS' => '?', 98 'CREATED' => '?', 99 'DESCRIPTION' => '?', 100 'DTSTART' => '?', 101 'LAST-MODIFIED' => '?', 102 'ORGANIZER' => '?', 103 'PRIORITY' => '?', 104 'SEQUENCE' => '?', 105 'SUMMARY' => '?', 106 'URL' => '?', 107 'DTEND' => '?', 108 'DURATION' => '?', 109 110 'CATEGORIES' => '*', 111 'COMMENT' => '*', 112 'CONTACT' => '*', 113 ]; 114 115 } 116 117 /** 118 * Validates the node for correctness. 119 * 120 * The following options are supported: 121 * Node::REPAIR - May attempt to automatically repair the problem. 122 * Node::PROFILE_CARDDAV - Validate the vCard for CardDAV purposes. 123 * Node::PROFILE_CALDAV - Validate the iCalendar for CalDAV purposes. 124 * 125 * This method returns an array with detected problems. 126 * Every element has the following properties: 127 * 128 * * level - problem level. 129 * * message - A human-readable string describing the issue. 130 * * node - A reference to the problematic node. 131 * 132 * The level means: 133 * 1 - The issue was repaired (only happens if REPAIR was turned on). 134 * 2 - A warning. 135 * 3 - An error. 136 * 137 * @param int $options 138 * 139 * @return array 140 */ 141 function validate($options = 0) { 142 143 $result = parent::validate($options); 144 145 if (isset($this->DTEND) && isset($this->DURATION)) { 146 $result[] = [ 147 'level' => 3, 148 'message' => 'DTEND and DURATION cannot both be present', 149 'node' => $this 150 ]; 151 } 152 153 return $result; 154 155 } 156} 157