1<?php 2 3namespace Sabre\CalDAV\Backend; 4 5use Sabre\VObject; 6use Sabre\CalDAV; 7 8/** 9 * Abstract Calendaring backend. Extend this class to create your own backends. 10 * 11 * Checkout the BackendInterface for all the methods that must be implemented. 12 * 13 * @copyright Copyright (C) 2007-2015 fruux GmbH (https://fruux.com/). 14 * @author Evert Pot (http://evertpot.com/) 15 * @license http://sabre.io/license/ Modified BSD License 16 */ 17abstract class AbstractBackend implements BackendInterface { 18 19 /** 20 * Updates properties for a calendar. 21 * 22 * The list of mutations is stored in a Sabre\DAV\PropPatch object. 23 * To do the actual updates, you must tell this object which properties 24 * you're going to process with the handle() method. 25 * 26 * Calling the handle method is like telling the PropPatch object "I 27 * promise I can handle updating this property". 28 * 29 * Read the PropPatch documenation for more info and examples. 30 * 31 * @param string $path 32 * @param \Sabre\DAV\PropPatch $propPatch 33 * @return void 34 */ 35 function updateCalendar($calendarId, \Sabre\DAV\PropPatch $propPatch) { 36 37 } 38 39 /** 40 * Returns a list of calendar objects. 41 * 42 * This method should work identical to getCalendarObject, but instead 43 * return all the calendar objects in the list as an array. 44 * 45 * If the backend supports this, it may allow for some speed-ups. 46 * 47 * @param mixed $calendarId 48 * @param array $uris 49 * @return array 50 */ 51 function getMultipleCalendarObjects($calendarId, array $uris) { 52 53 return array_map(function($uri) use ($calendarId) { 54 return $this->getCalendarObject($calendarId, $uri); 55 }, $uris); 56 57 } 58 59 /** 60 * Performs a calendar-query on the contents of this calendar. 61 * 62 * The calendar-query is defined in RFC4791 : CalDAV. Using the 63 * calendar-query it is possible for a client to request a specific set of 64 * object, based on contents of iCalendar properties, date-ranges and 65 * iCalendar component types (VTODO, VEVENT). 66 * 67 * This method should just return a list of (relative) urls that match this 68 * query. 69 * 70 * The list of filters are specified as an array. The exact array is 71 * documented by \Sabre\CalDAV\CalendarQueryParser. 72 * 73 * Note that it is extremely likely that getCalendarObject for every path 74 * returned from this method will be called almost immediately after. You 75 * may want to anticipate this to speed up these requests. 76 * 77 * This method provides a default implementation, which parses *all* the 78 * iCalendar objects in the specified calendar. 79 * 80 * This default may well be good enough for personal use, and calendars 81 * that aren't very large. But if you anticipate high usage, big calendars 82 * or high loads, you are strongly adviced to optimize certain paths. 83 * 84 * The best way to do so is override this method and to optimize 85 * specifically for 'common filters'. 86 * 87 * Requests that are extremely common are: 88 * * requests for just VEVENTS 89 * * requests for just VTODO 90 * * requests with a time-range-filter on either VEVENT or VTODO. 91 * 92 * ..and combinations of these requests. It may not be worth it to try to 93 * handle every possible situation and just rely on the (relatively 94 * easy to use) CalendarQueryValidator to handle the rest. 95 * 96 * Note that especially time-range-filters may be difficult to parse. A 97 * time-range filter specified on a VEVENT must for instance also handle 98 * recurrence rules correctly. 99 * A good example of how to interprete all these filters can also simply 100 * be found in \Sabre\CalDAV\CalendarQueryFilter. This class is as correct 101 * as possible, so it gives you a good idea on what type of stuff you need 102 * to think of. 103 * 104 * @param mixed $calendarId 105 * @param array $filters 106 * @return array 107 */ 108 function calendarQuery($calendarId, array $filters) { 109 110 $result = []; 111 $objects = $this->getCalendarObjects($calendarId); 112 113 foreach ($objects as $object) { 114 115 if ($this->validateFilterForObject($object, $filters)) { 116 $result[] = $object['uri']; 117 } 118 119 } 120 121 return $result; 122 123 } 124 125 /** 126 * This method validates if a filter (as passed to calendarQuery) matches 127 * the given object. 128 * 129 * @param array $object 130 * @param array $filters 131 * @return bool 132 */ 133 protected function validateFilterForObject(array $object, array $filters) { 134 135 // Unfortunately, setting the 'calendardata' here is optional. If 136 // it was excluded, we actually need another call to get this as 137 // well. 138 if (!isset($object['calendardata'])) { 139 $object = $this->getCalendarObject($object['calendarid'], $object['uri']); 140 } 141 142 $vObject = VObject\Reader::read($object['calendardata']); 143 144 $validator = new CalDAV\CalendarQueryValidator(); 145 return $validator->validate($vObject, $filters); 146 147 } 148 149 /** 150 * Searches through all of a users calendars and calendar objects to find 151 * an object with a specific UID. 152 * 153 * This method should return the path to this object, relative to the 154 * calendar home, so this path usually only contains two parts: 155 * 156 * calendarpath/objectpath.ics 157 * 158 * If the uid is not found, return null. 159 * 160 * This method should only consider * objects that the principal owns, so 161 * any calendars owned by other principals that also appear in this 162 * collection should be ignored. 163 * 164 * @param string $principalUri 165 * @param string $uid 166 * @return string|null 167 */ 168 function getCalendarObjectByUID($principalUri, $uid) { 169 170 // Note: this is a super slow naive implementation of this method. You 171 // are highly recommended to optimize it, if your backend allows it. 172 foreach ($this->getCalendarsForUser($principalUri) as $calendar) { 173 174 // We must ignore calendars owned by other principals. 175 if ($calendar['principaluri'] !== $principalUri) { 176 continue; 177 } 178 179 // Ignore calendars that are shared. 180 if (isset($calendar['{http://sabredav.org/ns}owner-principal']) && $calendar['{http://sabredav.org/ns}owner-principal'] !== $principalUri) { 181 continue; 182 } 183 184 $results = $this->calendarQuery( 185 $calendar['id'], 186 [ 187 'name' => 'VCALENDAR', 188 'prop-filters' => [], 189 'comp-filters' => [ 190 [ 191 'name' => 'VEVENT', 192 'is-not-defined' => false, 193 'time-range' => null, 194 'comp-filters' => [], 195 'prop-filters' => [ 196 [ 197 'name' => 'UID', 198 'is-not-defined' => false, 199 'time-range' => null, 200 'text-match' => [ 201 'value' => $uid, 202 'negate-condition' => false, 203 'collation' => 'i;octet', 204 ], 205 'param-filters' => [], 206 ], 207 ] 208 ] 209 ], 210 ] 211 ); 212 if ($results) { 213 // We have a match 214 return $calendar['uri'] . '/' . $results[0]; 215 } 216 217 } 218 219 } 220 221} 222