getCalendarObject($calendarId, $uri); }, $uris); } /** * Performs a calendar-query on the contents of this calendar. * * The calendar-query is defined in RFC4791 : CalDAV. Using the * calendar-query it is possible for a client to request a specific set of * object, based on contents of iCalendar properties, date-ranges and * iCalendar component types (VTODO, VEVENT). * * This method should just return a list of (relative) urls that match this * query. * * The list of filters are specified as an array. The exact array is * documented by \Sabre\CalDAV\CalendarQueryParser. * * Note that it is extremely likely that getCalendarObject for every path * returned from this method will be called almost immediately after. You * may want to anticipate this to speed up these requests. * * This method provides a default implementation, which parses *all* the * iCalendar objects in the specified calendar. * * This default may well be good enough for personal use, and calendars * that aren't very large. But if you anticipate high usage, big calendars * or high loads, you are strongly adviced to optimize certain paths. * * The best way to do so is override this method and to optimize * specifically for 'common filters'. * * Requests that are extremely common are: * * requests for just VEVENTS * * requests for just VTODO * * requests with a time-range-filter on either VEVENT or VTODO. * * ..and combinations of these requests. It may not be worth it to try to * handle every possible situation and just rely on the (relatively * easy to use) CalendarQueryValidator to handle the rest. * * Note that especially time-range-filters may be difficult to parse. A * time-range filter specified on a VEVENT must for instance also handle * recurrence rules correctly. * A good example of how to interprete all these filters can also simply * be found in \Sabre\CalDAV\CalendarQueryFilter. This class is as correct * as possible, so it gives you a good idea on what type of stuff you need * to think of. * * @param mixed $calendarId * @param array $filters * @return array */ function calendarQuery($calendarId, array $filters) { $result = []; $objects = $this->getCalendarObjects($calendarId); foreach ($objects as $object) { if ($this->validateFilterForObject($object, $filters)) { $result[] = $object['uri']; } } return $result; } /** * This method validates if a filter (as passed to calendarQuery) matches * the given object. * * @param array $object * @param array $filters * @return bool */ protected function validateFilterForObject(array $object, array $filters) { // Unfortunately, setting the 'calendardata' here is optional. If // it was excluded, we actually need another call to get this as // well. if (!isset($object['calendardata'])) { $object = $this->getCalendarObject($object['calendarid'], $object['uri']); } $vObject = VObject\Reader::read($object['calendardata']); $validator = new CalDAV\CalendarQueryValidator(); return $validator->validate($vObject, $filters); } /** * Searches through all of a users calendars and calendar objects to find * an object with a specific UID. * * This method should return the path to this object, relative to the * calendar home, so this path usually only contains two parts: * * calendarpath/objectpath.ics * * If the uid is not found, return null. * * This method should only consider * objects that the principal owns, so * any calendars owned by other principals that also appear in this * collection should be ignored. * * @param string $principalUri * @param string $uid * @return string|null */ function getCalendarObjectByUID($principalUri, $uid) { // Note: this is a super slow naive implementation of this method. You // are highly recommended to optimize it, if your backend allows it. foreach ($this->getCalendarsForUser($principalUri) as $calendar) { // We must ignore calendars owned by other principals. if ($calendar['principaluri'] !== $principalUri) { continue; } // Ignore calendars that are shared. if (isset($calendar['{http://sabredav.org/ns}owner-principal']) && $calendar['{http://sabredav.org/ns}owner-principal'] !== $principalUri) { continue; } $results = $this->calendarQuery( $calendar['id'], [ 'name' => 'VCALENDAR', 'prop-filters' => [], 'comp-filters' => [ [ 'name' => 'VEVENT', 'is-not-defined' => false, 'time-range' => null, 'comp-filters' => [], 'prop-filters' => [ [ 'name' => 'UID', 'is-not-defined' => false, 'time-range' => null, 'text-match' => [ 'value' => $uid, 'negate-condition' => false, 'collation' => 'i;octet', ], 'param-filters' => [], ], ] ] ], ] ); if ($results) { // We have a match return $calendar['uri'] . '/' . $results[0]; } } } }