app/Http/Controllers/DAV/Backend/CalDAV/CalDAVBackend.php (96 lines of code) (raw):

<?php namespace App\Http\Controllers\DAV\Backend\CalDAV; use Sabre\DAV; use Sabre\CalDAV\Backend\SyncSupport; use Sabre\CalDAV\Backend\AbstractBackend; class CalDAVBackend extends AbstractBackend implements SyncSupport { /** * Set the Calendar backends. * * @return array */ private function getBackends(): array { return [ new CalDAVBirthdays(), new CalDAVTasks(), ]; } /** * Get the backend for this id. * * @return AbstractCalDAVBackend|null */ private function getBackend($id) { return collect($this->getBackends())->first(function ($backend) use ($id) { return $backend->backendUri() === $id; }); } /** * Returns a list of calendars for a principal. * * Every project is an array with the following keys: * * id, a unique id that will be used by other functions to modify the * calendar. This can be the same as the uri or a database key. * * uri, which is the basename of the uri with which the calendar is * accessed. * * principaluri. The owner of the calendar. Almost always the same as * principalUri passed to this method. * * Furthermore it can contain webdav properties in clark notation. A very * common one is '{DAV:}displayname'. * * Many clients also require: * {urn:ietf:params:xml:ns:caldav}supported-calendar-component-set * For this property, you can just return an instance of * Sabre\CalDAV\Property\SupportedCalendarComponentSet. * * If you return {http://sabredav.org/ns}read-only and set the value to 1, * ACL will automatically be put in read-only mode. * * @param string $principalUri * @return array */ public function getCalendarsForUser($principalUri) { return array_map(function ($backend) { return $backend->getDescription(); }, $this->getBackends()); } /** * The getChanges method returns all the changes that have happened, since * the specified syncToken in the specified calendar. * * This function should return an array, such as the following: * * [ * 'syncToken' => 'The current synctoken', * 'added' => [ * 'new.txt', * ], * 'modified' => [ * 'modified.txt', * ], * 'deleted' => [ * 'foo.php.bak', * 'old.txt' * ] * ); * * The returned syncToken property should reflect the *current* syncToken * of the calendar, as reported in the {http://sabredav.org/ns}sync-token * property This is * needed here too, to ensure the operation is atomic. * * If the $syncToken argument is specified as null, this is an initial * sync, and all members should be reported. * * The modified property is an array of nodenames that have changed since * the last token. * * The deleted property is an array with nodenames, that have been deleted * from collection. * * The $syncLevel argument is basically the 'depth' of the report. If it's * 1, you only have to report changes that happened only directly in * immediate descendants. If it's 2, it should also include changes from * the nodes below the child collections. (grandchildren) * * The $limit argument allows a client to specify how many results should * be returned at most. If the limit is not specified, it should be treated * as infinite. * * If the limit (infinite or not) is higher than you're willing to return, * you should throw a Sabre\DAV\Exception\TooMuchMatches() exception. * * If the syncToken is expired (due to data cleanup) or unknown, you must * return null. * * The limit is 'suggestive'. You are free to ignore it. * * @param string $calendarId * @param string $syncToken * @param int $syncLevel * @param int $limit * @return array */ public function getChangesForCalendar($calendarId, $syncToken, $syncLevel, $limit = null) { $backend = $this->getBackend($calendarId); if ($backend) { return $backend->getChanges($syncToken); } return []; } /** * Returns all calendar objects within a calendar. * * Every item contains an array with the following keys: * * calendardata - The iCalendar-compatible calendar data * * uri - a unique key which will be used to construct the uri. This can * be any arbitrary string, but making sure it ends with '.ics' is a * good idea. This is only the basename, or filename, not the full * path. * * lastmodified - a timestamp of the last modification time * * etag - An arbitrary string, surrounded by double-quotes. (e.g.: * '"abcdef"') * * size - The size of the calendar objects, in bytes. * * component - optional, a string containing the type of object, such * as 'vevent' or 'vtodo'. If specified, this will be used to populate * the Content-Type header. * * Note that the etag is optional, but it's highly encouraged to return for * speed reasons. * * The calendardata is also optional. If it's not returned * 'getCalendarObject' will be called later, which *is* expected to return * calendardata. * * If neither etag or size are specified, the calendardata will be * used/fetched to determine these numbers. If both are specified the * amount of times this is needed is reduced by a great degree. * * @param mixed $calendarId * @return array */ public function getCalendarObjects($calendarId) { $backend = $this->getBackend($calendarId); if ($backend) { $objs = $backend->getObjects(); return $objs ->map(function ($date) use ($backend) { return $backend->prepareData($date); }) ->filter(function ($event) { return ! is_null($event); }) ->toArray(); } return []; } /** * Returns information from a single calendar object, based on it's object * uri. * * The object uri is only the basename, or filename and not a full path. * * The returned array must have the same keys as getCalendarObjects. The * 'calendardata' object is required here though, while it's not required * for getCalendarObjects. * * This method must return null if the object did not exist. * * @param mixed $calendarId * @param string $objectUri * @return array|null */ public function getCalendarObject($calendarId, $objectUri) { $backend = $this->getBackend($calendarId); if ($backend) { $obj = $backend->getObject($objectUri); if ($obj) { return $backend->prepareData($obj); } } return []; } /** * Creates a new calendar object. * * The object uri is only the basename, or filename and not a full path. * * It is possible to return an etag from this function, which will be used * in the response to this PUT request. Note that the ETag must be * surrounded by double-quotes. * * However, you should only really return this ETag if you don't mangle the * calendar-data. If the result of a subsequent GET to this object is not * the exact same as this request body, you should omit the ETag. * * @param mixed $calendarId * @param string $objectUri * @param string $calendarData * @return string|null */ public function createCalendarObject($calendarId, $objectUri, $calendarData) { return $this->updateCalendarObject($calendarId, $objectUri, $calendarData); } /** * Updates an existing calendarobject, based on it's uri. * * The object uri is only the basename, or filename and not a full path. * * It is possible return an etag from this function, which will be used in * the response to this PUT request. Note that the ETag must be surrounded * by double-quotes. * * However, you should only really return this ETag if you don't mangle the * calendar-data. If the result of a subsequent GET to this object is not * the exact same as this request body, you should omit the ETag. * * @param mixed $calendarId * @param string $objectUri * @param string $calendarData * @return string|null */ public function updateCalendarObject($calendarId, $objectUri, $calendarData): ?string { $backend = $this->getBackend($calendarId); return $backend ? $backend->updateOrCreateCalendarObject($objectUri, $calendarData) : null; } /** * Deletes an existing calendar object. * * The object uri is only the basename, or filename and not a full path. * * @param mixed $calendarId * @param string $objectUri * @return void */ public function deleteCalendarObject($calendarId, $objectUri) { $backend = $this->getBackend($calendarId); if ($backend) { $backend->deleteCalendarObject($objectUri); } } /** * Creates a new calendar for a principal. * * If the creation was a success, an id must be returned that can be used to * reference this calendar in other methods, such as updateCalendar. * * The id can be any type, including ints, strings, objects or array. * * @param string $principalUri * @param string $calendarUri * @param array $properties * * @return void */ public function createCalendar($principalUri, $calendarUri, array $properties): void { } /** * Delete a calendar and all its objects. * * @param mixed $calendarId * @return void */ public function deleteCalendar($calendarId) { } /** * Creates a new subscription for a principal. * * If the creation was a success, an id must be returned that can be used to reference * this subscription in other methods, such as updateSubscription. * * @param string $principalUri * @param string $uri * @param array $properties * @return mixed */ public function createSubscription($principalUri, $uri, array $properties) { return false; } /** * Updates a subscription. * * The list of mutations is stored in a Sabre\DAV\PropPatch object. * To do the actual updates, you must tell this object which properties * you're going to process with the handle() method. * * Calling the handle method is like telling the PropPatch object "I * promise I can handle updating this property". * * Read the PropPatch documentation for more info and examples. * * @param mixed $subscriptionId * @param \Sabre\DAV\PropPatch $propPatch * @return void */ public function updateSubscription($subscriptionId, DAV\PropPatch $propPatch) { } /** * Deletes a subscription. * * @param mixed $subscriptionId * @return void */ public function deleteSubscription($subscriptionId) { } }