58 $this->helper =
$context->getHelper();
59 parent::__construct(
$context->getConnection());
78 $internalDto = $this->getEventConverter()->eventToDto(
$event);
82 $dto = $this->getService()->createEvent($internalDto,
$context->getSectionConnection()->getVendorSectionId());
85 if (
$event->getExcludedDateCollection() &&
$event->getExcludedDateCollection()->count())
87 $context->add(
'sync',
'masterEventId', $dto->id);
89 foreach (
$event->getExcludedDateCollection() as $item)
91 $context->add(
'sync',
'excludeDate', $item);
98 $result->setData($this->prepareResultData($dto));
102 $result->addError(
new Main\Error(
'Error of create a series master event'));
107 $result->addError(
new Main\
Error(
'Error of create event'));
110 catch (ApiException $exception)
112 if ((
int)$exception->getCode() !== 400)
117 $result->addError(
new Main\
Error($exception->getMessage(), $exception->getCode()));
119 catch (AuthException $exception)
121 $result->addError(
new Main\
Error($exception->getMessage(), $exception->getCode()));
142 $internalDto = $this->getEventConverter()->eventToDto(
$event);
143 $this->enrichVendorData($internalDto,
$context->getEventConnection());
147 $dto = $this->getService()->updateEvent(
$context->getEventConnection()->getVendorEventId(), $internalDto);
150 $result->setData($this->prepareResultData($dto));
155 if ((
int)$exception->getCode() !== 400)
160 $result->addError(
new Main\
Error($exception->getMessage(), $exception->getCode()));
164 $result->addError(
new Main\
Error($exception->getMessage(), $exception->getCode()));
187 $this->getService()->deleteEvent(
$context->getEventConnection()->getVendorEventId());
203 'version' => $dto->changeKey,
204 'etag' => $dto->etag,
205 'recurrence' => $dto->seriesMasterId ??
null,
206 'data' => $this->prepareCustomData($dto),
224 $eventLink =
$context->sync[
'instanceLink'];
228 ->setSectionConnection(
$context->getSectionConnection())
229 ->setEventConnection($eventLink)
234 return (
new Result())->addError(
new Main\
Error(
'Not found link for instance'));
252 $event->getOriginalDateFrom()
253 &&
$event->getOriginalDateFrom()->format(
'Ymd') !==
$event->getStart()->format(
'Ymd')
260 $masterLink =
$context->getEventConnection();
264 if ($masterLink &&
$instance = $this->getInstanceForDay($masterLink->getVendorEventId(),
$event->getStart()->getDate()))
266 $dto = $this->getService()->updateEvent(
268 $this->getEventConverter()->eventToDto(
$event),
270 if ($dto && !empty($dto->id))
272 $result->setData($this->prepareResultData($dto));
286 if (!in_array((
int)$exception->getCode(), [400, 404],
true))
291 $result->addError(
new Main\
Error($exception->getMessage(), $exception->getCode()));
295 $result->addError(
new Main\
Error($exception->getMessage(), $exception->getCode()));
321 $masterEventId =
$context->getEventConnection()
322 ?
$context->getEventConnection()->getVendorEventId()
323 : (
$context->sync[
'masterEventId'] ??
null)
328 $context->sync[
'excludeDate']->getDate()->format(
'Ymd 000000'),
330 $event->getStartTimeZone()
331 ?
$event->getStartTimeZone()->getTimeZone()
332 :
new \DateTimeZone(
'UTC')
336 if (
$instance = $this->getInstanceForDay($masterEventId, $excludeDate))
338 $this->getService()->deleteEvent(
349 if ((
int)$e->getCode() !== 400 && (
int)$e->getCode() !== 404)
358 $result->addError(
new Main\
Error($exception->getMessage(), $exception->getCode()));
385 $masterLink =
$context->getEventConnection();
387 if ($masterLink &&
$event->getOriginalDateFrom())
392 $masterLink->getVendorEventId(),
393 $event->getOriginalDateFrom()->getDate()
396 catch (ApiException $exception)
398 if (!in_array((
int)$exception->getCode(), [400, 404],
true))
403 $result->addError(
new Main\
Error($exception->getMessage(), $exception->getCode()));
413 $dto = $this->getService()->updateEvent(
415 $this->getEventConverter()->eventToDto(
$event),
417 if ($dto && !empty($dto->id))
419 $result->setData($this->prepareResultData($dto));
423 $result->addError(
new Main\
Error(
'Error of move instance', 400));
426 catch (NotFoundException $e)
428 $result->addError(
new Main\
Error(
'Instance not found'));
433 $result->addError(
new Main\
Error(
'Instance not found'));
456 public function fetchSectionEvents(SectionConnection $sectionLink): Generator
458 foreach ($this->getService()->getCalendarDelta($sectionLink) as $deltaData)
461 if (!empty($deltaData[Helper::EVENT_TYPES[
'deleted']]))
464 $dto = $deltaData[Helper::EVENT_TYPES[
'deleted']];
468 'version' => $dto->changeKey,
469 'etag' => $dto->etag,
475 elseif (!empty($deltaData[Helper::EVENT_TYPES[
'single']]))
478 $dto = $deltaData[Helper::EVENT_TYPES[
'single']];
481 'event' => $this->context->getConverter()
482 ->convertEvent($dto, $sectionLink->getSection()),
484 'version' => $dto->changeKey,
485 'etag' => $dto->etag,
486 'data' => $this->prepareCustomData($dto),
489 elseif (!empty($deltaData[Helper::EVENT_TYPES[
'series']]))
491 $data = $this->prepareSeries($deltaData, $sectionLink);
522 public function saveRecurrence(
523 SyncEvent $recurrenceEvent,
524 SectionConnection $sectionConnection,
530 if ($recurrenceEvent->getEventConnection())
534 $masterResult = $this->updateRecurrenceInstance($recurrenceEvent,
$context);
536 catch(Calendar\Sync\Exceptions\NotFoundException $e)
538 $this->getEventConnectionMapper()->delete($recurrenceEvent->getEventConnection());
539 $recurrenceEvent->setEventConnection(
null);
540 return $this->saveRecurrence($recurrenceEvent, $sectionConnection,
$context);
545 $masterResult = $this->createRecurrenceInstance($recurrenceEvent, $sectionConnection,
$context);
548 if (!$masterResult->isSuccess())
550 $result->addErrors($masterResult->getErrors());
554 if ($recurrenceEvent->getEventConnection())
556 $recurrenceEvent->getEventConnection()
557 ->setLastSyncStatus(Calendar\Sync\Dictionary::SYNC_STATUS[
'success']);
560 ->setAction(Calendar\Sync\Dictionary::SYNC_STATUS[
'success']);
562 $excludes = $this->getExcludedDatesCollection($recurrenceEvent);
563 if ($recurrenceEvent->getInstanceMap())
566 foreach ($recurrenceEvent->getInstanceMap()->getCollection() as
$instance)
568 if (
$instance->getEvent()->getOriginalDateFrom() ===
null)
571 new Main\
Error(
'Instance is invalid - there is not original date from. ['.
$instance->getEvent()->getId().
']', 400));
579 $instanceResult = $this->updateRecurrenceInstance(
$instance,
$context, $recurrenceEvent->getEventConnection());
581 catch(Calendar\Sync\Exceptions\NotFoundException $e)
583 $this->getEventConnectionMapper()->delete(
$instance->getEventConnection());
585 $instanceResult = $this->createRecurrenceInstance(
589 $recurrenceEvent->getEventConnection()
595 $instanceResult = $this->createRecurrenceInstance(
599 $recurrenceEvent->getEventConnection()
602 $excludes->removeDateFromCollection(
$instance->getEvent()->getOriginalDateFrom());
604 $instance->getEvent()->getStart()->format(
'Ymd')
605 !==
$instance->getEvent()->getOriginalDateFrom()->format(
'Ymd')
608 $excludes->removeDateFromCollection(
$instance->getEvent()->getStart());
610 if (!$instanceResult->isSuccess())
612 $result->addErrors($instanceResult->getErrors());
616 $instance->getEventConnection()->setLastSyncStatus(Calendar\Sync\Dictionary::SYNC_STATUS[
'success']);
621 if ($excludes->count() > 0)
623 $context = (
new EventContext())->setEventConnection($recurrenceEvent->getEventConnection());
625 foreach ($excludes as $excludedDate)
627 $context->add(
'sync',
'excludeDate', $excludedDate);
638 private function getEventConnectionMapper(): Core\Mappers\EventConnection
640 if (empty($this->eventConnectionMapper))
642 $this->eventConnectionMapper =
new Core\Mappers\EventConnection();
645 return $this->eventConnectionMapper;
674 return $this->saveRecurrence($recurrenceEvent, $sectionConnection,
$context);
695 return $this->saveRecurrence($recurrenceEvent, $sectionConnection,
$context);
710 $masterDto = $deltaData[Helper::EVENT_TYPES[
'series']];
712 $exceptionList = $deltaData[Helper::EVENT_TYPES[
'exception']] ?? [];
714 $masterEvent = $this->context->getConverter()->convertEvent($masterDto, $sectionLink->
getSection());
716 if (!empty($exceptionList)) {
717 $exceptionsDates = array_map(
function (
EventDto $exception) {
719 $exception->start->dateTime,
720 $this->helper::TIME_FORMAT_LONG,
721 new DateTimeZone($exception->start->timeZone),
727 $masterEvent->setExcludedDateCollection($excludeCollection);
732 'id' => $masterDto->id,
733 'event' => $masterEvent,
734 'version' => $masterDto->changeKey,
735 'etag' => $masterDto->etag,
736 'data' => $this->prepareCustomData($masterDto),
739 foreach ($exceptionList as $exception) {
740 $event = $this->context->getConverter()->convertEvent($exception, $sectionLink->
getSection());
742 'type' =>
'exception',
744 'id' => $exception->id,
745 'version' => $exception->changeKey,
746 'etag' => $exception->etag,
747 'recurrence' => $exception->seriesMasterId,
748 'data' => $this->prepareCustomData($exception),
771 private function getInstanceForDay(
string $eventId, Main\Type\Date $dayStart): ? EventDto
773 $dateFrom = clone $dayStart;
774 if ($dateFrom instanceof Main\Type\DateTime)
776 $dateFrom->setTime(0,0);
778 $dateTo = clone $dateFrom;
779 $dateTo->add(
'1 day');
781 $instances = $this->getService()->getEventInstances([
783 'event_id' => $eventId,
784 'from' => $dateFrom->format(
'c'),
785 'to' => $dateTo->format(
'c'),
789 return $instances ? $instances[0] :
null;
795 private function getEventConverter(): EventConverter
797 if (empty($this->eventConverter))
799 $this->eventConverter =
new EventConverter();
802 return $this->eventConverter;
813 private function getService(): VendorSyncService
815 return $this->context->getVendorSyncService();
824 private function prepareCustomData(EventDto $dto):
array
827 if (!empty($dto->location))
829 $result[
'location'] = $dto->location->toArray(
true);
831 if (!empty($dto->locations))
839 if (!empty($dto->attendees))
842 foreach ($dto->attendees as $attendee)
844 $result[
'attendees'][] = $attendee->toArray(
true);
857 private function enrichVendorData(EventDto $dto, EventConnection $link)
875 private function createRecurrenceInstance(
876 SyncEvent $syncEvent,
877 SectionConnection $sectionConnection,
879 EventConnection $masterLink =
null
884 $eventContext =
new EventContext();
888 $eventContext->setEventConnection($masterLink);
889 $event = (
new Core\Builders\EventCloner($syncEvent->getEvent()))->build();
894 $eventContext->setSectionConnection($sectionConnection);
895 $event = $this->prepareMasterEvent($syncEvent);
900 if (!$syncEvent->getEvent()->isDeleted())
902 if (!empty(
$result->getData()[
'event'][
'id']))
904 $link = (
new EventConnection())
906 ->setConnection($sectionConnection->getConnection())
907 ->setVersion(
$event->getVersion())
908 ->setVendorEventId(
$result->getData()[
'event'][
'id'])
909 ->setEntityTag(
$result->getData()[
'event'][
'etag'])
910 ->setVendorVersionId(
$result->getData()[
'event'][
'version'])
911 ->setRecurrenceId(
$result->getData()[
'event'][
'recurrence'] ??
null)
912 ->setLastSyncStatus(Calendar\Sync\Dictionary::SYNC_STATUS[
'success'])
915 ->setEventConnection($link)
916 ->setAction(Calendar\Sync\Dictionary::SYNC_STATUS[
'success']);
920 $errMessage =
'Unknown error of creating recurrence '
921 . ($masterLink ?
'master' :
'instance');
928 $syncEvent->setAction(Calendar\Sync\Dictionary::SYNC_EVENT_ACTION[
'delete']);
934 catch (Core\Base\BaseException $e)
936 return (
new Result())->addError(
new Main\
Error($e->getMessage()));
953 private function updateRecurrenceInstance(
954 SyncEvent $syncEvent,
956 EventConnection $masterLink =
null
959 $eventContext =
new EventContext();
964 ->setEventConnection($masterLink)
965 ->add(
'sync',
'instanceLink', $syncEvent->getEventConnection())
971 $eventContext->setEventConnection($syncEvent->getEventConnection());
972 $result = $this->
update($syncEvent->getEvent(), $eventContext);
976 $syncEvent->getEventConnection()
977 ->setEntityTag(
$result->getData()[
'event'][
'etag'])
978 ->setVendorVersionId(
$result->getData()[
'event'][
'version'])
990 private function getExcludedDatesCollection(SyncEvent $recurrenceEvent): Core\Event\Properties\ExcludedDatesCollection
992 $excludes =
new Core\Event\Properties\ExcludedDatesCollection();
995 foreach ($recurrenceEvent->getEvent()->getExcludedDateCollection() as $item)
997 $excludes->add($item);
1007 private function prepareMasterEvent(SyncEvent $syncEvent): Event
1009 $event = (
new Core\Builders\EventCloner($syncEvent->getEvent()))->build();
1010 (
new Calendar\Sync\Util\ExcludeDatesHandler())->prepareEventExcludeDates(
$event, $syncEvent->getInstanceMap());