53 $this->connection = $connection;
55 $this->mapperFactory = ServiceLocator::getInstance()->get(
'calendar.service.mappers.factory');
63 public function importSections():
Result
72 'vendorSections' => [],
76 $getResult = $this->getFactory()->getIncomingSectionManager()->getSections();
77 if ($getResult->isSuccess())
79 $sections = $getResult->getData()[
'externalSyncSectionMap'];
81 $mapper = $this->mapperFactory->getSection();
83 foreach ($sections as $syncSection)
87 if ($link = $this->getSectionLinkByVendorId($syncSection->getSectionConnection()->getVendorSectionId()))
89 $resultData[
'linkedSectionIds'][] = $link->getSection()->getId();
90 if (!$link->isActive())
92 $resultData[
'links'][
'skipped'][] = $link;
96 !empty($syncSection->getAction() ===
'updated')
97 && $syncSection->getSection()->getDateModified() > $link->getSection()->getDateModified()
100 $section = $this->mergeSections($link->getSection(), $syncSection->getSection());
101 $mapper->update($section, [
102 'originalFrom' => $this->connection->getVendor()->getCode(),
106 $resultData[
'importedSectionIds'][] = $link->getSection()->getId();
107 $resultData[
'links'][
'updated'][] = $link;
112 $link = $this->importSectionSimple(
113 $syncSection->getSection(),
114 $syncSection->getSectionConnection()->getVendorSectionId(),
115 $syncSection->getSectionConnection()->getVersionId() ??
null,
116 $syncSection->getSectionConnection()->isPrimary() ??
null,
118 $resultData[
'links'][
'imported'][] = $link;
122 $resultData[
'importedSectionIds'][] = $link->getSection()->getId();
126 catch (SystemException $e)
132 return $result->setData($resultData);
136 $result->addErrors($getResult->getErrors());
151 private function getSectionLinkByVendorId(
string $sectionId): ?SectionConnection
153 $mapper = $this->mapperFactory->getSectionConnection();
154 $map = $mapper->getMap([
155 '=CONNECTION_ID' => $this->connection->getId(),
156 '=VENDOR_SECTION_ID' => $sectionId,
159 return $map->fetch();
170 public function import(): Result
173 $result =
new Result();
175 $sections = $this->getFactory()->getSectionManager()->getSections($this->connection);
182 foreach ($sections as $vendorSectionPack)
185 $sectionLink = $this->importSection(
186 $vendorSectionPack[
'section'],
187 $vendorSectionPack[
'id'],
188 $vendorSectionPack[
'version'] ??
null,
189 $vendorSectionPack[
'is_primary'] ??
null,
192 $resultData[
'importedSectionIds'][] = $sectionLink->getSection()->getId();
193 if ($sectionLink->isActive())
195 $eventsResult = $this->importSectionEvents($sectionLink);
196 $resultData[
'events'][$vendorSectionPack[
'id']] = $eventsResult->getData();
202 $resultData[
'events'][$vendorSectionPack[
'id']] =
null;
204 }
catch (SystemException $e) {
209 return $result->setData($resultData);
215 private function getFactory(): FactoryInterface
217 if (empty($this->factory))
219 $this->factory = FactoryBuilder::create(
220 $this->connection->getVendor()->getCode(),
226 return $this->factory;
247 private function importSection(
250 string $vendorVersion =
null,
251 bool $isPrimary =
false
254 $sectionFactory =
new SectionConnectionFactory();
255 $link = $sectionFactory->getSectionConnection([
257 'CONNECTION_ID' => $this->connection->getId(),
258 'VENDOR_SECTION_ID' => $vendorId,
260 'connectionObject' => $this->connection,
265 'NAME' => $section->getName(),
267 'DESCRIPTION' => $section->getDescription() ??
'',
268 'COLOR' => $section->getColor() ??
'',
269 'CAL_TYPE' => $this->connection->getOwner()
270 ? $this->connection->getOwner()->getType()
271 : Core\Role\User::TYPE
273 'OWNER_ID' => $this->connection->getOwner()
274 ? $this->connection->getOwner()->getId()
277 'CREATED_BY' => $this->connection->getOwner()->getId(),
278 'DATE_CREATE' =>
new DateTime(),
279 'TIMESTAMP_X' =>
new DateTime(),
280 'EXTERNAL_TYPE' => $this->connection->getVendor()->getCode(),
282 if ($sectionId = CCalendar::SaveSection([
283 'arFields' => $fields,
284 'originalFrom' => $this->connection->getVendor()->getCode(),
288 $section = $this->mapperFactory->getSection()->resetCacheById($sectionId)->getById($sectionId);
290 $protoLink = (
new SectionConnection())
292 ->setConnection($this->connection)
293 ->setVendorSectionId($vendorId)
294 ->setVersionId($vendorVersion)
295 ->setPrimary($isPrimary)
297 $link = $this->mapperFactory->getSectionConnection()->create($protoLink);
301 throw new SystemException(
"Can't create Bitrix Calendar Section", 500, __FILE__, __LINE__ );
307 $this->subscribeSection($link);
326 private function importSectionSimple(
329 string $vendorVersion =
null,
330 bool $isPrimary =
null
334 if ($section = $this->saveSection($section))
336 if ($link = $this->createSectionConnection($section, $vendorId, $vendorVersion, $isPrimary))
342 throw new SystemException(
"Can't create Section Connection link.", 500, __FILE__, __LINE__ );
347 throw new SystemException(
"Can't create Bitrix Calendar Section.", 500, __FILE__, __LINE__ );
362 private function createSectionConnection(
365 string $vendorVersion =
null,
366 bool $isPrimary =
null
367 ): ?SectionConnection
369 $entity = (
new SectionConnection())
371 ->setConnection($this->connection)
372 ->setVendorSectionId($vendorId)
373 ->setVersionId($vendorVersion)
374 ->setPrimary($isPrimary ??
false)
377 $result = (
new Core\Mappers\SectionConnection())->create($entity);
392 private function subscribeSection(SectionConnection $link): Result
394 $mainResult =
new Result();
395 if ($this->getSyncManager()->canSubscribeSection())
397 $pushManager =
new PushManager();
398 $subscription = $pushManager->getPush(
402 if ($subscription && !$subscription->isExpired())
404 $result = $this->getSyncManager()->renewPush($subscription);
405 if ($result->isSuccess())
407 $mainResult = $pushManager->renewPush($subscription, $result->getData());
411 $mainResult->addError(
new Error(
'Error of renew subscription.'));
412 $mainResult->addErrors($result->getErrors());
417 $subscribeResult = $this->getSyncManager()->subscribeSection($link);
418 if ($subscribeResult->isSuccess())
420 if ($subscription !==
null)
422 $pushManager->renewPush($subscription, $subscribeResult->getData());
426 $pushManager->addPush(
427 'SECTION_CONNECTION',
429 $subscribeResult->getData()
435 $mainResult->addError(
new Error(
'Error of add subscription.'));
436 $mainResult->addErrors($subscribeResult->getErrors());
452 public function importSectionEvents(SectionConnection $sectionLink): Result
454 $mainResult =
new Result();
465 $pushResult =
static function(array $result) use (&$resultData)
467 if (empty($result[
'entityType']))
471 if ($result[
'entityType'] ===
'link')
473 $resultData[
'events'][$result[
'action']] = $result[
'entity']->getEvent()->getId();
475 elseif ($result[
'entityType'] ===
'eventId')
477 $resultData[
'events'][$result[
'action']] = $result[
'entity'];
481 $vendorManager = $this->getFactory()->getEventManager();
482 foreach ($vendorManager->fetchSectionEvents($sectionLink) as $eventPack)
485 foreach ($eventPack as $eventData)
488 if ($event = $eventData[
'event'])
490 $event->setSection($sectionLink->getSection());
492 if ($eventData[
'type'] ===
'deleted')
494 $result = $this->deleteInstance($eventData[
'id']);
495 if ($result->isSuccess())
497 $resultData[
'events'][
'deleted'][] = $result->getData()[
'eventId'];
498 $resultData[$eventData[
'id']] =
'delete success';
502 $resultData[
'events'][
'error'][] = $result->getData()[
'eventId'];
503 $resultData[$eventData[
'id']] =
'delete fail';
506 elseif ($eventData[
'type'] ===
'single')
508 $result = $this->importEvent(
511 $eventData[
'version'],
513 'data' => $eventData[
'data'] ??
null,
516 if ($result->isSuccess())
518 $pushResult($result->getData());
519 $resultData[$eventData[
'id']] =
'create success';
523 $resultData[$eventData[
'id']] =
'create fail';
526 elseif ($eventData[
'type'] ===
'master')
528 $result = $this->importEvent(
531 $eventData[
'version'],
533 'recursionEditMode' =>
'all',
534 'data' => $eventData[
'data'] ??
null,
536 if ($result->isSuccess())
538 $masterId = $result->getData()[
'id'];
539 $resultData[$eventData[
'id']] =
'create success';
543 $resultData[$eventData[
'id']] =
'create fail';
546 elseif ($eventData[
'type'] ===
'exception')
548 if ($masterId ===
null)
550 $resultData[$eventData[
'id']] =
'create fail: master event not found';
553 $eventData[
'event']->setRecurrenceId($masterId);
554 $result = $this->importEvent(
557 $eventData[
'version'],
559 'data' => $eventData[
'data'] ??
null,
562 if ($result->isSuccess())
564 $masterId = $result->getData()[
'id'];
565 $resultData[$eventData[
'id']] =
'create success';
569 $resultData[$eventData[
'id']] =
'create fail';
575 return $mainResult->setData($resultData);
586 private function deleteInstance(
string $vendorId): Result
588 $result =
new Result();
589 $linkData = EventConnectionTable::query()
590 ->setSelect([
'*',
'EVENT'])
591 ->addFilter(
'CONNECTION_ID', $this->connection->getId())
592 ->addFilter(
'=VENDOR_EVENT_ID', $vendorId)
593 ->exec()->fetchObject();
597 if (!CCalendarEvent::Delete([
598 'id' => $linkData->getEventId(),
599 'userId' => $this->connection->getOwner()->getId(),
600 'bMarkDeleted' =>
true,
601 'originalFrom' => $this->connection->getVendor()->getCode(),
604 $result->addError(
new Error(
'Error of delete event'));
605 $result->setData([
'eventId' => $linkData->getEventId()]);
610 $result->addError(
new Error(
'Event not found'));
628 private function importEvent(
631 string $vendorVersion =
null,
635 $prepareResult =
function (
string $action,
string $entityType, $entity)
638 'type' => $entityType,
644 $result =
new Result();
646 $mapper =
new Core\Mappers\Event();
648 $link = (
new EventConnectionFactory())->getEventConnection([
650 'CONNECTION_ID' => $this->connection->getId(),
651 '=VENDOR_EVENT_ID' => $vendorId,
653 'connection' => $this->connection,
658 if ($vendorVersion && $link->getEntityTag() === $vendorVersion)
660 $resultData = $prepareResult(
'skipped',
'link', $link);
663 empty($event->getDateModified())
664 || empty($link->getEvent()->getDateModified())
665 || ($link->getEvent()->getDateModified()->getTimestamp() >= $event->getDateModified()->getTimestamp())
668 $resultData = $prepareResult(
'skipped',
'link', $link);
673 $event->setId($link->getEvent()->getId());
674 $event->setOwner(Core\Role\Helper::getRole(
675 $this->connection->getOwner()->getId(),
676 $this->connection->getOwner()->getType(),
678 $this->mergeReminders($event, $link->getEvent());
679 $mapper->update($event, [
680 'originalFrom' => $this->connection->getVendor()->getCode(),
681 'userId' => $this->connection->getOwner()->getId(),
683 EventConnectionTable::update($link->getId(), [
684 'ENTITY_TAG' => $vendorVersion,
685 'DATA' => $params[
'data'] ??
null,
687 $resultData = $prepareResult(
'updated',
'link', $link);
690 catch (Exception $e) {
691 $resultData = $prepareResult(
'error',
'link', $link);
692 $result->addError(
new Error($e->getMessage(), $e->getCode()));
700 $event->setOwner(Core\Role\Helper::getRole(
701 $this->connection->getOwner()->getId(),
702 $this->connection->getOwner()->getType(),
704 $newEvent = $mapper->create($event, [
705 'originalFrom' => $this->connection->getVendor()->getCode(),
706 'userId' => $this->connection->getOwner()->getId(),
708 $linkResult = EventConnectionTable::add([
709 'EVENT_ID' => $newEvent->getId(),
710 'CONNECTION_ID' => $this->connection->getId(),
711 'VENDOR_EVENT_ID' => $vendorId,
713 'ENTITY_TAG' => $vendorVersion,
715 'DATA' => $params[
'data'] ??
null,
717 if ($linkResult->isSuccess())
719 $resultData = $prepareResult(
'imported',
'eventId', $newEvent->getId());
723 $resultData = $prepareResult(
'error',
'eventId', $newEvent->getId());
724 $result->addError(reset($linkResult->getErrors()));
729 $resultData = $prepareResult(
'error',
'vendorId', $vendorId);
730 $result->addError(
new Error($e->getMessage()));
734 return $result->setData($resultData ?? []);
742 private function getSyncManager(): VendorSynchronization
744 if (empty($this->syncManager))
746 $this->syncManager =
new VendorSynchronization($this->getFactory());
749 return $this->syncManager;
752 private function mergeSections(Section $baseSection, Section $newSection): Section
755 ->setId($newSection->getId() ?: $baseSection->getId())
756 ->setName($newSection->getName() ?: $baseSection->getName())
757 ->setDescription($newSection->getDescription())
758 ->setIsActive($newSection->isActive())
759 ->setColor($newSection->getColor())
773 private function saveSection(Section $section): ?Section
775 if ($this->connection->getOwner() ===
null)
777 throw new Core\Base\BaseException(
'The connection must have an owner');
781 'NAME' => $section->getName(),
783 'DESCRIPTION' => $section->getDescription() ??
'',
784 'COLOR' => $section->getColor() ??
'',
785 'CAL_TYPE' => $this->connection->getOwner()->getType(),
786 'OWNER_ID' => $this->connection->getOwner()->getId(),
787 'CREATED_BY' => $this->connection->getOwner()->getId(),
788 'DATE_CREATE' =>
new DateTime(),
789 'TIMESTAMP_X' =>
new DateTime(),
790 'EXTERNAL_TYPE' => $this->connection->getVendor()->getCode(),
793 'arFields' => $fields,
794 'originalFrom' => $this->connection->getVendor()->getCode(),
799 return $this->mapperFactory->getSection()
800 ->resetCacheById($sectionId)
801 ->getById($sectionId)
814 private function mergeReminders(Event $targetEvent, Event $sourceEvent)
816 foreach ($sourceEvent->getRemindCollection()->getCollection() as $item)
818 $targetEvent->getRemindCollection()->add($item);
836 $this->deleteSectionConnection($section->getId(), $linkId);
838 if ($section->getExternalType() !==
'local')
840 CCalendarSect::Delete($section->getId(),
false, [
841 'originalFrom' => $this->connection->getVendor()->getCode(),
846 $this->exportLocalSection($section);
857 private function deleteSectionConnection(
int $sectionId,
int $sectionConnectionId)
861 if ($this->connection->getId() && $sectionId)
864 DELETE FROM b_calendar_event_connection
865 WHERE CONNECTION_ID = " . $this->connection->getId() .
"
866 AND EVENT_ID IN (SELECT EV.ID FROM b_calendar_event EV
867 WHERE EV.SECTION_ID = " . $sectionId .
" );"
871 if ($sectionConnectionId)
873 SectionConnectionTable::delete($sectionConnectionId);
886 private function exportLocalSection(Section $section): void
888 $manager =
new OutgoingManager($this->connection);
889 $sectionResult = $manager->exportSectionSimple($section);
890 if ($sectionResult->isSuccess() && $sectionResult->getData()[
'exported'])
893 $sectionLink = $sectionResult->getData()[
'exported'];
894 $manager->exportSectionEvents($sectionLink);