/** * update one record * * NOTE: clients might send their original (creation) data w.o. our adoptions for update * therefore we need reapply them * * @param Calendar_Model_Event $_event * @param bool $_checkBusyConflicts * @return Calendar_Model_Event * @throws Tinebase_Exception_AccessDenied * @throws Tinebase_Exception_Record_Validation */ public function update(Tinebase_Record_Interface $_event, $_checkBusyConflicts = FALSE) { if ($_event->recurid) { throw new Tinebase_Exception_UnexpectedValue('recur event instances must be saved as part of the base event'); } $currentOriginEvent = $this->_eventController->get($_event->getId()); $this->_fromiTIP($_event, $currentOriginEvent); // NOTE: create an update must be handled equally as apple devices do not fetch events after creation. // an update from the creating device would change defaults otherwise // NOTE2: Being organizer without attending is not possible when sync is in use as every update // from a sync device of the organizer adds the organizer as attendee :-( // -> in the sync world this is scenario is called delegation and handled differently // -> it might be consequent to have the same behavior (organizer is always attendee with role chair) // in tine20 in general. This is how Thunderbird handles it as well $_event->assertAttendee($this->getCalendarUser()); $exceptions = $_event->exdate instanceof Tinebase_Record_RecordSet ? $_event->exdate : new Tinebase_Record_RecordSet('Calendar_Model_Event'); $exceptions->addIndices(array('is_deleted')); $currentPersistentExceptions = $_event->rrule ? $this->_eventController->getRecurExceptions($_event, FALSE) : new Tinebase_Record_RecordSet('Calendar_Model_Event'); $newPersistentExceptions = $exceptions->filter('is_deleted', 0); $migration = $this->_getExceptionsMigration($currentPersistentExceptions, $newPersistentExceptions); $this->_eventController->delete($migration['toDelete']->getId()); // NOTE: we need to exclude the toCreate exdates here to not confuse computations in createRecurException! $_event->exdate = array_diff($exceptions->getOriginalDtStart(), $migration['toCreate']->getOriginalDtStart()); $updatedBaseEvent = $this->_eventController->update($_event, $_checkBusyConflicts); if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Found ' . count($migration['toCreate']) . ' exceptions to create and ' . count($migration['toUpdate']) . ' to update.'); } foreach ($migration['toCreate'] as $exception) { $exception->assertAttendee($this->getCalendarUser()); $this->_prepareException($updatedBaseEvent, $exception); $this->_eventController->createRecurException($exception, !!$exception->is_deleted); } $updatedExceptions = array(); foreach ($migration['toUpdate'] as $exception) { if (in_array($exception->getId(), $updatedExceptions)) { if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' ' . ' Exdate ' . $exception->getId() . ' already updated'); } continue; } if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' ' . ' Update exdate ' . $exception->getId() . ' at ' . $exception->dtstart->toString()); } $exception->assertAttendee($this->getCalendarUser()); $this->_prepareException($updatedBaseEvent, $exception); $this->_addStatusAuthkeyForOwnAttender($exception); // skip concurrency check here by setting the seq of the current record $currentException = $currentPersistentExceptions->getById($exception->getId()); $exception->seq = $currentException->seq; if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' Updating exception: ' . print_r($exception->toArray(), TRUE)); } $this->_eventController->update($exception, $_checkBusyConflicts); $updatedExceptions[] = $exception->getId(); } // NOTE: we need to refetch here, otherwise eTag fail's as exception updates change baseEvents seq return $this->get($updatedBaseEvent->getId()); }
/** * update one record * * @param Calendar_Model_Event $_record * @param bool $_checkBusyConflicts * @return Calendar_Model_Event * @throws Tinebase_Exception_AccessDenied * @throws Tinebase_Exception_Record_Validation */ public function update(Tinebase_Record_Interface $_event, $_checkBusyConflicts = FALSE) { if ($_event->recurid) { throw new Tinebase_Exception_UnexpectedValue('recur event instances must be saved as part of the base event'); } $exceptions = $_event->exdate instanceof Tinebase_Record_RecordSet ? $_event->exdate : new Tinebase_Record_RecordSet('Calendar_Model_Event'); $_event->exdate = $exceptions->getOriginalDtStart(); $currentPersistentExceptions = $_event->rrule ? $this->_eventController->getRecurExceptions($_event, FALSE) : new Tinebase_Record_RecordSet('Calendar_Model_Event'); $newPersistentExceptions = $exceptions->filter('is_deleted', 0); $this->_prepareException($_event, $newPersistentExceptions); $migration = $this->_getExceptionsMigration($currentPersistentExceptions, $newPersistentExceptions); $this->_eventController->delete($migration['toDelete']->getId()); foreach ($migration['toCreate'] as $exception) { $this->_eventController->createRecurException($exception, !!$exception->is_deleted); } foreach ($migration['toUpdate'] as $exception) { $this->_eventController->update($exception, $_checkBusyConflicts); } $updatedBaseEvent = $this->_eventController->update($_event, $_checkBusyConflicts); return $this->_toiTIP($updatedBaseEvent); }