1<?php 2 3namespace Sabre\CalDAV; 4 5/** 6 * The CalendarObject represents a single VEVENT or VTODO within a Calendar. 7 * 8 * @copyright Copyright (C) fruux GmbH (https://fruux.com/) 9 * @author Evert Pot (http://evertpot.com/) 10 * @license http://sabre.io/license/ Modified BSD License 11 */ 12class CalendarObject extends \Sabre\DAV\File implements ICalendarObject, \Sabre\DAVACL\IACL { 13 14 use \Sabre\DAVACL\ACLTrait; 15 16 /** 17 * Sabre\CalDAV\Backend\BackendInterface 18 * 19 * @var Backend\AbstractBackend 20 */ 21 protected $caldavBackend; 22 23 /** 24 * Array with information about this CalendarObject 25 * 26 * @var array 27 */ 28 protected $objectData; 29 30 /** 31 * Array with information about the containing calendar 32 * 33 * @var array 34 */ 35 protected $calendarInfo; 36 37 /** 38 * Constructor 39 * 40 * The following properties may be passed within $objectData: 41 * 42 * * calendarid - This must refer to a calendarid from a caldavBackend 43 * * uri - A unique uri. Only the 'basename' must be passed. 44 * * calendardata (optional) - The iCalendar data 45 * * etag - (optional) The etag for this object, MUST be encloded with 46 * double-quotes. 47 * * size - (optional) The size of the data in bytes. 48 * * lastmodified - (optional) format as a unix timestamp. 49 * * acl - (optional) Use this to override the default ACL for the node. 50 * 51 * @param Backend\BackendInterface $caldavBackend 52 * @param array $calendarInfo 53 * @param array $objectData 54 */ 55 function __construct(Backend\BackendInterface $caldavBackend, array $calendarInfo, array $objectData) { 56 57 $this->caldavBackend = $caldavBackend; 58 59 if (!isset($objectData['uri'])) { 60 throw new \InvalidArgumentException('The objectData argument must contain an \'uri\' property'); 61 } 62 63 $this->calendarInfo = $calendarInfo; 64 $this->objectData = $objectData; 65 66 } 67 68 /** 69 * Returns the uri for this object 70 * 71 * @return string 72 */ 73 function getName() { 74 75 return $this->objectData['uri']; 76 77 } 78 79 /** 80 * Returns the ICalendar-formatted object 81 * 82 * @return string 83 */ 84 function get() { 85 86 // Pre-populating the 'calendardata' is optional, if we don't have it 87 // already we fetch it from the backend. 88 if (!isset($this->objectData['calendardata'])) { 89 $this->objectData = $this->caldavBackend->getCalendarObject($this->calendarInfo['id'], $this->objectData['uri']); 90 } 91 return $this->objectData['calendardata']; 92 93 } 94 95 /** 96 * Updates the ICalendar-formatted object 97 * 98 * @param string|resource $calendarData 99 * @return string 100 */ 101 function put($calendarData) { 102 103 if (is_resource($calendarData)) { 104 $calendarData = stream_get_contents($calendarData); 105 } 106 $etag = $this->caldavBackend->updateCalendarObject($this->calendarInfo['id'], $this->objectData['uri'], $calendarData); 107 $this->objectData['calendardata'] = $calendarData; 108 $this->objectData['etag'] = $etag; 109 110 return $etag; 111 112 } 113 114 /** 115 * Deletes the calendar object 116 * 117 * @return void 118 */ 119 function delete() { 120 121 $this->caldavBackend->deleteCalendarObject($this->calendarInfo['id'], $this->objectData['uri']); 122 123 } 124 125 /** 126 * Returns the mime content-type 127 * 128 * @return string 129 */ 130 function getContentType() { 131 132 $mime = 'text/calendar; charset=utf-8'; 133 if (isset($this->objectData['component']) && $this->objectData['component']) { 134 $mime .= '; component=' . $this->objectData['component']; 135 } 136 return $mime; 137 138 } 139 140 /** 141 * Returns an ETag for this object. 142 * 143 * The ETag is an arbitrary string, but MUST be surrounded by double-quotes. 144 * 145 * @return string 146 */ 147 function getETag() { 148 149 if (isset($this->objectData['etag'])) { 150 return $this->objectData['etag']; 151 } else { 152 return '"' . md5($this->get()) . '"'; 153 } 154 155 } 156 157 /** 158 * Returns the last modification date as a unix timestamp 159 * 160 * @return int 161 */ 162 function getLastModified() { 163 164 return $this->objectData['lastmodified']; 165 166 } 167 168 /** 169 * Returns the size of this object in bytes 170 * 171 * @return int 172 */ 173 function getSize() { 174 175 if (array_key_exists('size', $this->objectData)) { 176 return $this->objectData['size']; 177 } else { 178 return strlen($this->get()); 179 } 180 181 } 182 183 /** 184 * Returns the owner principal 185 * 186 * This must be a url to a principal, or null if there's no owner 187 * 188 * @return string|null 189 */ 190 function getOwner() { 191 192 return $this->calendarInfo['principaluri']; 193 194 } 195 196 /** 197 * Returns a list of ACE's for this node. 198 * 199 * Each ACE has the following properties: 200 * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are 201 * currently the only supported privileges 202 * * 'principal', a url to the principal who owns the node 203 * * 'protected' (optional), indicating that this ACE is not allowed to 204 * be updated. 205 * 206 * @return array 207 */ 208 function getACL() { 209 210 // An alternative acl may be specified in the object data. 211 if (isset($this->objectData['acl'])) { 212 return $this->objectData['acl']; 213 } 214 215 // The default ACL 216 return [ 217 [ 218 'privilege' => '{DAV:}all', 219 'principal' => $this->calendarInfo['principaluri'], 220 'protected' => true, 221 ], 222 [ 223 'privilege' => '{DAV:}all', 224 'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-write', 225 'protected' => true, 226 ], 227 [ 228 'privilege' => '{DAV:}read', 229 'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-read', 230 'protected' => true, 231 ], 232 233 ]; 234 235 } 236 237} 238