403Webshell
Server IP : 80.87.202.40  /  Your IP : 216.73.216.169
Web Server : Apache
System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64
User : bitrix ( 600)
PHP Version : 8.2.27
Disable Function : NONE
MySQL : OFF |  cURL : ON |  WGET : ON |  Perl : ON |  Python : OFF |  Sudo : ON |  Pkexec : ON
Directory :  /home/bitrix/ext_www/ilovecveti.ru/bitrix/modules/calendar/lib/sync/office365/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/ilovecveti.ru/bitrix/modules/calendar/lib/sync/office365/eventmanager.php
<?php

namespace Bitrix\Calendar\Sync\Office365;

use Bitrix\Bizproc\Error;
use Bitrix\Calendar;
use Bitrix\Calendar\Sync\Exceptions\GoneException;
use Bitrix\Main;
use Bitrix\Calendar\Core;
use Bitrix\Calendar\Core\Base\BaseException;
use Bitrix\Calendar\Core\Event\Event;
use Bitrix\Calendar\Sync\Entities\SyncEvent;
use Bitrix\Calendar\Sync\Connection\EventConnection;
use Bitrix\Calendar\Sync\Connection\SectionConnection;
use Bitrix\Calendar\Sync\Exceptions\ApiException;
use Bitrix\Calendar\Sync\Exceptions\AuthException;
use Bitrix\Calendar\Sync\Exceptions\ConflictException;
use Bitrix\Calendar\Sync\Exceptions\NotFoundException;
use Bitrix\Calendar\Sync\Exceptions\RemoteAccountException;
use Bitrix\Calendar\Sync\Internals\ContextInterface;
use Bitrix\Calendar\Sync\Internals\HasContextTrait;
use Bitrix\Calendar\Sync\Managers\EventManagerInterface;
use Bitrix\Calendar\Sync\Util\EventContext;
use Bitrix\Calendar\Sync\Office365\Converter\EventConverter;
use Bitrix\Calendar\Sync\Office365\Dto\EventDto;
use Bitrix\Calendar\Sync\Util\Context;
use Bitrix\Calendar\Sync\Office365;
use Bitrix\Calendar\Sync\Util\Result;
use Bitrix\Main\ArgumentException;
use Bitrix\Main\ArgumentNullException;
use Bitrix\Main\LoaderException;
use Bitrix\Main\ObjectException;
use Bitrix\Main\ObjectPropertyException;
use Bitrix\Main\SystemException;
use Bitrix\Main\Type\Date;
use DateTimeZone;
use Generator;

class EventManager extends AbstractManager implements EventManagerInterface
{
	use HasContextTrait;

	private Helper $helper;

	/**
	 * @var ?EventConverter
	 */
	private ?EventConverter $eventConverter;

	private Core\Mappers\EventConnection $eventConnectionMapper;

	/**
	 * @param Office365\Office365Context $context
	 */
	public function __construct(ContextInterface $context)
	{
		$this->context = $context;
		$this->helper = $context->getHelper();
		parent::__construct($context->getConnection());
	}

	/**
	 * @param Event $event
	 * @param EventContext $context
	 *
	 * @return Result
	 *
	 * @throws Main\ArgumentException
	 * @throws Core\Base\BaseException
	 * @throws Main\ObjectPropertyException
	 * @throws Main\SystemException
	 * @throws Calendar\Sync\Exceptions\NotFoundException
	 * @throws LoaderException
	 */
	public function create(Core\Event\Event $event, EventContext $context): Result
	{
		$result = new Result();
		$internalDto = $this->getEventConverter()->eventToDto($event);

		try
		{
			$dto = $this->getService()->createEvent($internalDto, $context->getSectionConnection()->getVendorSectionId());
			if ($dto)
			{
				if ($event->getExcludedDateCollection() && $event->getExcludedDateCollection()->count())
				{
					$context->add('sync', 'masterEventId', $dto->id);
					/** @var Main\Type\DateTime $item */
					foreach ($event->getExcludedDateCollection() as $item)
					{
						$context->add('sync', 'excludeDate', $item);
						$this->deleteInstance($event, $context);
					}
				}

				if (!empty($dto->id))
				{
					$result->setData($this->prepareResultData($dto));
				}
				else
				{
					$result->addError(new Main\Error('Error of create a series master event'));
				}
			}
			else
			{
				$result->addError(new Main\Error('Error of create event'));
			}
		}
		catch (ApiException $exception)
		{
			if ((int)$exception->getCode() !== 400)
			{
				throw $exception;
			}

			$result->addError(new Main\Error($exception->getMessage(), $exception->getCode()));
		}
		catch (AuthException $exception)
		{
			$result->addError(new Main\Error($exception->getMessage(), $exception->getCode()));
		}

		return $result;
	}

	/**
	 * @param Event $event
	 * @param EventContext $context
	 *
	 * @return Result
	 *
	 * @throws Main\ArgumentException
	 * @throws Calendar\Sync\Exceptions\ApiException
	 * @throws Main\ObjectPropertyException
	 * @throws Main\SystemException
	 * @throws LoaderException
	 */
	public function update(Core\Event\Event $event, EventContext $context): Result
	{
		$result = new Result();
		$internalDto = $this->getEventConverter()->eventToDto($event);
		$this->enrichVendorData($internalDto, $context->getEventConnection());

		try
		{
			$dto = $this->getService()->updateEvent($context->getEventConnection()->getVendorEventId(), $internalDto);
			if ($dto)
			{
				$result->setData($this->prepareResultData($dto));
			}
		}
		catch (ApiException $exception)
		{
			if ((int)$exception->getCode() !== 400)
			{
				throw $exception;
			}

			$result->addError(new Main\Error($exception->getMessage(), $exception->getCode()));
		}
		catch (AuthException $exception)
		{
			$result->addError(new Main\Error($exception->getMessage(), $exception->getCode()));
		}

		return $result;
	}

	/**
	 * @param Event $event
	 * @param EventContext $context
	 *
	 * @return Result
	 * @throws ApiException
	 * @throws Main\ArgumentException
	 * @throws Main\ArgumentNullException
	 * @throws AuthException
	 * @throws BaseException
	 * @throws ConflictException
	 * @throws NotFoundException
	 * @throws RemoteAccountException
	 * @throws LoaderException
	 */
	public function delete(Core\Event\Event $event, EventContext $context): Result
	{
		$this->getService()->deleteEvent($context->getEventConnection()->getVendorEventId());

		return new Result();
	}

	/**
	 * @param EventDto $dto
	 *
	 * @return array
	 */
	private function prepareResultData(EventDto $dto): array
	{
		return [
			'dto' => $dto,
			'event' => [
				'id' => $dto->id,
				'version' => $dto->changeKey,
				'etag' => $dto->etag,
				'recurrence' => $dto->seriesMasterId ?? null,
				'data' => $this->prepareCustomData($dto),
			],
		];
	}

	/**
	 * @param Event $event
	 * @param EventContext $context
	 *
	 * @return Result
	 * @throws ArgumentException
	 * @throws Calendar\Sync\Exceptions\ApiException
	 * @throws Main\ObjectPropertyException
	 * @throws Main\SystemException
	 * @throws LoaderException
	 */
	public function updateInstance(Event $event, EventContext $context): Result
	{
		$eventLink = $context->sync['instanceLink'];
		if ($eventLink)
		{
			$eventContext = (new EventContext())
				->setSectionConnection($context->getSectionConnection())
				->setEventConnection($eventLink)
			;
			return $this->update($event, $eventContext);
		}

		return (new Result())->addError(new Main\Error('Not found link for instance'));
	}

	/**
	 * @param Event $event
	 * @param EventContext $context
	 *
	 * @return Result
	 *
	 * @throws Main\ArgumentException
	 * @throws Calendar\Sync\Exceptions\ApiException
	 * @throws Main\ObjectPropertyException
	 * @throws Main\SystemException
	 * @throws LoaderException
	 */
	public function createInstance(Core\Event\Event $event, EventContext $context): Result
	{
		if (
			$event->getOriginalDateFrom()
			&& $event->getOriginalDateFrom()->format('Ymd') !== $event->getStart()->format('Ymd')
		)
		{
			return $this->moveInstance($event, $context);
		}

		$result = new Result();
		$masterLink = $context->getEventConnection();

		try
		{
			if ($masterLink && $instance = $this->getInstanceForDay($masterLink->getVendorEventId(), $event->getStart()->getDate()))
			{
				$dto = $this->getService()->updateEvent(
					$instance->id,
					$this->getEventConverter()->eventToDto($event),
				);
				if ($dto && !empty($dto->id))
				{
					$result->setData($this->prepareResultData($dto));
				}
				else
				{
					$result->addError(new Main\Error("Error of create instance.", 404));
				}
			}
			else
			{
				$result->addError(new Main\Error("Instances for event not found", 404));
			}
		}
		catch (ApiException $exception)
		{
			if (!in_array((int)$exception->getCode(), [400, 404], true))
			{
				throw $exception;
			}

			$result->addError(new Main\Error($exception->getMessage(), $exception->getCode()));
		}
		catch (AuthException $exception)
		{
			$result->addError(new Main\Error($exception->getMessage(), $exception->getCode()));
		}

		return $result;
	}

	/**
	 * @param Event $event
	 * @param EventContext $context
	 *
	 * @return Result
	 *
	 * @throws ApiException
	 * @throws ArgumentException
	 * @throws ArgumentNullException
	 * @throws AuthException
	 * @throws BaseException
	 * @throws ConflictException
	 * @throws NotFoundException
	 * @throws Main\ObjectException
	 * @throws RemoteAccountException
	 * @throws LoaderException
	 */
	public function deleteInstance(Event $event, EventContext $context): Result
	{
		$result = new Result();
		$masterEventId = $context->getEventConnection()
			? $context->getEventConnection()->getVendorEventId()
			: ($context->sync['masterEventId'] ?? null)
		;
		if ($masterEventId)
		{
			$excludeDate = new Main\Type\DateTime(
				$context->sync['excludeDate']->getDate()->format('Ymd 000000'),
				'Ymd His',
				$event->getStartTimeZone()
					? $event->getStartTimeZone()->getTimeZone()
					: new \DateTimeZone('UTC')
			);
			try
			{
				if ($instance = $this->getInstanceForDay($masterEventId, $excludeDate))
				{
					$this->getService()->deleteEvent(
						$instance->id,
					);
				}
				else
				{
					$result->addError(new Main\Error("Instances for event not found", 404));
				}
			}
			catch (ApiException $e)
			{
				if ((int)$e->getCode() !== 400 && (int)$e->getCode() !== 404)
				{
					throw $e;
				}

				$result->addError(new Main\Error($e->getMessage(), $e->getCode()));
			}
			catch (AuthException $exception)
			{
				$result->addError(new Main\Error($exception->getMessage(), $exception->getCode()));
			}
		}

		return $result;
	}

	/**
	 * @param Event $event
	 * @param EventContext $context
	 *
	 * @return Result
	 *
	 * @throws ApiException
	 * @throws ArgumentException
	 * @throws ArgumentNullException
	 * @throws AuthException
	 * @throws BaseException
	 * @throws ConflictException
	 * @throws NotFoundException
	 * @throws RemoteAccountException
	 * @throws LoaderException
	 */
	private function moveInstance(Event $event, EventContext $context): Result
	{
		$result = new Result();
		$instance = null;
		$masterLink = $context->getEventConnection();

		if ($masterLink && $event->getOriginalDateFrom())
		{
			try
			{
				$instance = $this->getInstanceForDay(
					$masterLink->getVendorEventId(),
					$event->getOriginalDateFrom()->getDate()
				);
			}
			catch (ApiException $exception)
			{
				if (!in_array((int)$exception->getCode(), [400, 404], true))
				{
					throw $exception;
				}

				$result->addError(new Main\Error($exception->getMessage(), $exception->getCode()));

				return $result;
			}
		}

		if ($instance)
		{
			try
			{
				$dto = $this->getService()->updateEvent(
					$instance->id,
					$this->getEventConverter()->eventToDto($event),
				);
				if ($dto && !empty($dto->id))
				{
					$result->setData($this->prepareResultData($dto));
				}
				else
				{
					$result->addError(new Main\Error('Error of move instance', 400));
				}
			}
			catch (NotFoundException $e)
			{
				$result->addError(new Main\Error('Instance not found'));
			}
		}
		else
		{
			$result->addError(new Main\Error('Instance not found'));
		}

		return $result;
	}

	/**
	 * @param SectionConnection $sectionLink
	 *
	 * @return Generator|array
	 *
	 * @throws ApiException
	 * @throws ArgumentException
	 * @throws ArgumentNullException
	 * @throws AuthException
	 * @throws BaseException
	 * @throws ConflictException
	 * @throws LoaderException
	 * @throws ObjectException
	 * @throws NotFoundException
	 * @throws RemoteAccountException
	 * @deprecated use Sync\Office365\IncomingManager::getEvents()
	 */
	public function fetchSectionEvents(SectionConnection $sectionLink): Generator
	{
		foreach ($this->getService()->getCalendarDelta($sectionLink) as $deltaData)
		{
			$data = [];
			if (!empty($deltaData[Helper::EVENT_TYPES['deleted']]))
			{
				/** @var EventDto $dto */
				$dto = $deltaData[Helper::EVENT_TYPES['deleted']];
				$data[] = [
					'type' => 'deleted',
					'id' => $dto->id,
					'version' => $dto->changeKey,
					'etag' => $dto->etag,
				];


//				$this->processEventInstance($deltaData[Helper::EVENT_TYPES['deleted']], $sectionLink);
			}
			elseif (!empty($deltaData[Helper::EVENT_TYPES['single']]))
			{
				/** @var EventDto $dto */
				$dto = $deltaData[Helper::EVENT_TYPES['single']];
				$data[] = [
					'type' => 'single',
					'event' => $this->context->getConverter()
						->convertEvent($dto, $sectionLink->getSection()),
					'id' => $dto->id,
					'version' => $dto->changeKey,
					'etag' => $dto->etag,
					'data' => $this->prepareCustomData($dto),
				];
			}
			elseif (!empty($deltaData[Helper::EVENT_TYPES['series']]))
			{
				$data = $this->prepareSeries($deltaData, $sectionLink);

			}

			if ($data)
			{
				yield $data;
			}
		}
	}

	/**
	 * @param SyncEvent $recurrenceEvent
	 * @param SectionConnection $sectionConnection
	 * @param Context $context
	 *
	 * @return Result
	 *
	 * @throws ApiException
	 * @throws ArgumentException
	 * @throws ArgumentNullException
	 * @throws AuthException
	 * @throws BaseException
	 * @throws ConflictException
	 * @throws LoaderException
	 * @throws ObjectPropertyException
	 * @throws SystemException
	 * @throws NotFoundException
	 * @throws ObjectException
	 * @throws RemoteAccountException
	 */
	public function saveRecurrence(
		SyncEvent $recurrenceEvent,
		SectionConnection $sectionConnection,
		Context $context
	): Result
	{
		$result = new Result();

		if ($recurrenceEvent->getEventConnection())
		{
			try
			{
				$masterResult = $this->updateRecurrenceInstance($recurrenceEvent, $context);
			}
			catch(Calendar\Sync\Exceptions\NotFoundException $e)
			{
				$this->getEventConnectionMapper()->delete($recurrenceEvent->getEventConnection());
				$recurrenceEvent->setEventConnection(null);
				return $this->saveRecurrence($recurrenceEvent, $sectionConnection, $context);
			}
		}
		else
		{
			$masterResult = $this->createRecurrenceInstance($recurrenceEvent, $sectionConnection, $context);
		}

		if (!$masterResult->isSuccess())
		{
			$result->addErrors($masterResult->getErrors());
			return $result;
		}

		if ($recurrenceEvent->getEventConnection())
		{
			$recurrenceEvent->getEventConnection()
				->setLastSyncStatus(Calendar\Sync\Dictionary::SYNC_STATUS['success']);
		}
		$recurrenceEvent
			->setAction(Calendar\Sync\Dictionary::SYNC_STATUS['success']);

		$excludes = $this->getExcludedDatesCollection($recurrenceEvent);
		if ($recurrenceEvent->getInstanceMap())
		{
			/** @var SyncEvent $instance */
			foreach ($recurrenceEvent->getInstanceMap()->getCollection() as $instance)
			{
				if ($instance->getEvent()->getOriginalDateFrom() === null)
				{
					$result->addError(
						new Main\Error('Instance is invalid - there is not original date from. ['.$instance->getEvent()->getId().']', 400));
					continue;
				}

				if ($instance->getEventConnection())
				{
					try
					{
						$instanceResult = $this->updateRecurrenceInstance($instance, $context, $recurrenceEvent->getEventConnection());
					}
					catch(Calendar\Sync\Exceptions\NotFoundException $e)
					{
						$this->getEventConnectionMapper()->delete($instance->getEventConnection());
						$instance->setEventConnection(null);
						$instanceResult = $this->createRecurrenceInstance(
							$instance,
							$sectionConnection,
							$context,
							$recurrenceEvent->getEventConnection()
						);
					}
				}
				else
				{
					$instanceResult = $this->createRecurrenceInstance(
						$instance,
						$sectionConnection,
						$context,
						$recurrenceEvent->getEventConnection()
					);
				}
				$excludes->removeDateFromCollection($instance->getEvent()->getOriginalDateFrom());
				if (
					$instance->getEvent()->getStart()->format('Ymd')
					!== $instance->getEvent()->getOriginalDateFrom()->format('Ymd')
				)
				{
					$excludes->removeDateFromCollection($instance->getEvent()->getStart());
				}
				if (!$instanceResult->isSuccess())
				{
					$result->addErrors($instanceResult->getErrors());
				}
				if ($instance->getEventConnection())
				{
					$instance->getEventConnection()->setLastSyncStatus(Calendar\Sync\Dictionary::SYNC_STATUS['success']);
				}
			}
		}

		if ($excludes->count() > 0)
		{
			$context = (new EventContext())->setEventConnection($recurrenceEvent->getEventConnection());
			/** @var Main\Type\Date $excludedDate */
			foreach ($excludes as $excludedDate)
			{
				$context->add('sync', 'excludeDate', $excludedDate);
				$this->deleteInstance($recurrenceEvent->getEvent(), $context);
			}
		}

		return $result;
	}

	/**
	 * @return Core\Mappers\EventConnection
	 */
	private function getEventConnectionMapper(): Core\Mappers\EventConnection
	{
		if (empty($this->eventConnectionMapper))
		{
			$this->eventConnectionMapper = new Core\Mappers\EventConnection();
		}

		return $this->eventConnectionMapper;
	}

	/**
	 * @param SyncEvent $recurrenceEvent
	 * @param SectionConnection $sectionConnection
	 * @param Context $context
	 *
	 * @return Result
	 *
	 * @throws ApiException
	 * @throws ArgumentException
	 * @throws ArgumentNullException
	 * @throws AuthException
	 * @throws BaseException
	 * @throws ConflictException
	 * @throws LoaderException
	 * @throws NotFoundException
	 * @throws ObjectException
	 * @throws ObjectPropertyException
	 * @throws RemoteAccountException
	 * @throws SystemException
	 */
	public function createRecurrence(
		SyncEvent $recurrenceEvent,
		SectionConnection $sectionConnection,
		Context $context
	): Result
	{
		return $this->saveRecurrence($recurrenceEvent, $sectionConnection, $context);
	}

	/**
	 * @param SyncEvent $recurrenceEvent
	 * @param SectionConnection $sectionConnection
	 * @param Context $context
	 *
	 * @return Result
	 *
	 * @throws ArgumentException
	 * @throws Main\ObjectPropertyException
	 * @throws Main\SystemException
	 * @throws LoaderException
	 */
	public function updateRecurrence(
		SyncEvent $recurrenceEvent,
		SectionConnection $sectionConnection,
		Context $context
	): Result
	{
		return $this->saveRecurrence($recurrenceEvent, $sectionConnection, $context);
	}

	/**
	 * @param $deltaData
	 * @param SectionConnection $sectionLink
	 *
	 * @return void
	 *
	 * @throws Main\ObjectException
	 */
	private function prepareSeries($deltaData, SectionConnection $sectionLink): array
	{
		$result = [];
		/** @var EventDto $masterDto */
		$masterDto    = $deltaData[Helper::EVENT_TYPES['series']];
		/** @var EventDto[] $exceptionList */
		$exceptionList = $deltaData[Helper::EVENT_TYPES['exception']] ?? [];

		$masterEvent = $this->context->getConverter()->convertEvent($masterDto, $sectionLink->getSection());

		if (!empty($exceptionList)) {
			$exceptionsDates = array_map(function (EventDto $exception) {
				return (new Main\Type\DateTime(
					$exception->start->dateTime,
					$this->helper::TIME_FORMAT_LONG,
					new DateTimeZone($exception->start->timeZone),
					))->format('d.m.Y');
				}, $exceptionList
			);

			$excludeCollection = new Core\Event\Properties\ExcludedDatesCollection($exceptionsDates);
			$masterEvent->setExcludedDateCollection($excludeCollection);
		}

		$result[] = [
			'type' => 'master',
			'id' => $masterDto->id,
			'event' => $masterEvent,
			'version' => $masterDto->changeKey,
			'etag' => $masterDto->etag,
			'data' => $this->prepareCustomData($masterDto),
		];

		foreach ($exceptionList as $exception) {
			$event = $this->context->getConverter()->convertEvent($exception, $sectionLink->getSection());
			$result[] = [
				'type' => 'exception',
				'event' => $event,
				'id' => $exception->id,
				'version' => $exception->changeKey,
				'etag' => $exception->etag,
				'recurrence' => $exception->seriesMasterId,
				'data' => $this->prepareCustomData($exception),
			];
		}

		return $result;
	}

	/**
	 * @param string $eventId
	 * @param Date $dayStart
	 *
	 * @return EventDto|null
	 *
	 * @throws ApiException
	 * @throws ArgumentException
	 * @throws AuthException
	 * @throws BaseException
	 * @throws GoneException
	 * @throws ConflictException
	 * @throws LoaderException
	 * @throws NotFoundException
	 * @throws RemoteAccountException
	 */
	private function getInstanceForDay(string $eventId, Main\Type\Date $dayStart): ? EventDto
	{
		$dateFrom = clone $dayStart;
		if ($dateFrom instanceof Main\Type\DateTime)
		{
			$dateFrom->setTime(0,0);
		}
		$dateTo = clone $dateFrom;
		$dateTo->add('1 day');

		$instances = $this->getService()->getEventInstances([
			'filter' => [
				'event_id' => $eventId,
				'from' => $dateFrom->format('c'), //($this->helper::TIME_FORMAT_LONG),
				'to' => $dateTo->format('c'), //($this->helper::TIME_FORMAT_LONG),
			],
		]);

		return $instances ? $instances[0] : null;
	}

	/**
	 * @return EventConverter
	 */
	private function getEventConverter(): EventConverter
	{
		if (empty($this->eventConverter))
		{
			$this->eventConverter = new EventConverter();
		}

		return $this->eventConverter;
	}

	/**
	 * @return VendorSyncService
	 *
	 * @throws AuthException
	 * @throws BaseException
	 * @throws LoaderException
	 * @throws RemoteAccountException
	 */
	private function getService(): VendorSyncService
	{
		return $this->context->getVendorSyncService();
	}

	/**
	 * @param EventDto $dto
	 *
	 * @return array
	 * @todo see Sync\Office365\IncomingManager::prepareCustomData()
	 */
	private function prepareCustomData(EventDto $dto): array
	{
		$result = [];
		if (!empty($dto->location))
		{
			$result['location'] = $dto->location->toArray(true);
		}
		if (!empty($dto->locations))
		{
			foreach ($dto->locations as $location)
			{
				$result['locations'][] = $location->toArray(true);
			}
		}

		if (!empty($dto->attendees))
		{
			$result['attendees'] = [];
			foreach ($dto->attendees as $attendee)
			{
				$result['attendees'][] = $attendee->toArray(true);
			}
		}

		return $result;
	}

	/**
	 * @param EventDto $dto
	 * @param EventConnection $link
	 *
	 * @return void
	 */
	private function enrichVendorData(EventDto $dto, EventConnection $link)
	{
		// TODO: add info about attendees, locations and any others
	}

	/**
	 * @param SyncEvent $syncEvent
	 * @param SectionConnection $sectionConnection
	 * @param Context $context
	 * @param EventConnection|null $masterLink
	 *
	 * @return Result
	 *
	 * @throws ArgumentException
	 * @throws LoaderException
	 * @throws ObjectPropertyException
	 * @throws SystemException
	 */
	private function createRecurrenceInstance(
		SyncEvent $syncEvent,
		SectionConnection $sectionConnection,
		Context $context,
		EventConnection $masterLink = null
	): Result
	{
		try
		{
			$eventContext = new EventContext();
			$eventContext->merge($context);
			if ($masterLink)
			{
				$eventContext->setEventConnection($masterLink);
				$event = (new Core\Builders\EventCloner($syncEvent->getEvent()))->build();
				$result = $this->createInstance($event, $eventContext);
			}
			else
			{
				$eventContext->setSectionConnection($sectionConnection);
				$event = $this->prepareMasterEvent($syncEvent);
				$result = $this->create($event, $eventContext);
			}
			if ($result->isSuccess())
			{
				if (!$syncEvent->getEvent()->isDeleted())
				{
					if (!empty($result->getData()['event']['id']))
					{
						$link = (new EventConnection())
							->setEvent($event)
							->setConnection($sectionConnection->getConnection())
							->setVersion($event->getVersion())
							->setVendorEventId($result->getData()['event']['id'])
							->setEntityTag($result->getData()['event']['etag'])
							->setVendorVersionId($result->getData()['event']['version'])
							->setRecurrenceId($result->getData()['event']['recurrence'] ?? null)
							->setLastSyncStatus(Calendar\Sync\Dictionary::SYNC_STATUS['success'])
						;
						$syncEvent
							->setEventConnection($link)
							->setAction(Calendar\Sync\Dictionary::SYNC_STATUS['success']);
					}
					else
					{
						$errMessage = 'Unknown error of creating recurrence '
							. ($masterLink ? 'master' : 'instance');
						$result->addError(new Main\Error($errMessage, 400, ['data' => $result->getData()]));
					}

				}
				else
				{
					$syncEvent->setAction(Calendar\Sync\Dictionary::SYNC_EVENT_ACTION['delete']);
				}
			}

			return $result;
		}
		catch (Core\Base\BaseException $e)
		{
		    return (new Result())->addError(new Main\Error($e->getMessage()));
		}
	}

	/**
	 * @param SyncEvent $syncEvent
	 * @param Context $context
	 * @param EventConnection|null $masterLink
	 *
	 * @return Result
	 *
	 * @throws ArgumentException
	 * @throws Calendar\Sync\Exceptions\ApiException
	 * @throws Main\ObjectPropertyException
	 * @throws Main\SystemException
	 * @throws LoaderException
	 */
	private function updateRecurrenceInstance(
		SyncEvent $syncEvent,
		Context $context,
		EventConnection $masterLink = null
	): Result
	{
		$eventContext = new EventContext();
		$eventContext->merge($context);
		if ($masterLink)
		{
			$eventContext
				->setEventConnection($masterLink)
				->add('sync', 'instanceLink', $syncEvent->getEventConnection())
			;
			$result = $this->updateInstance($syncEvent->getEvent(), $eventContext);
		}
		else
		{
			$eventContext->setEventConnection($syncEvent->getEventConnection());
			$result = $this->update($syncEvent->getEvent(), $eventContext);
		}
		if ($result->isSuccess())
		{
			$syncEvent->getEventConnection()
				->setEntityTag($result->getData()['event']['etag'])
				->setVendorVersionId($result->getData()['event']['version'])
			;
		}

		return $result;
	}

	/**
	 * @param SyncEvent $recurrenceEvent
	 *
	 * @return Core\Event\Properties\ExcludedDatesCollection
	 */
	private function getExcludedDatesCollection(SyncEvent $recurrenceEvent): Core\Event\Properties\ExcludedDatesCollection
	{
		$excludes = new Core\Event\Properties\ExcludedDatesCollection();

		/** @var Core\Base\Date $item */
		foreach ($recurrenceEvent->getEvent()->getExcludedDateCollection() as $item)
		{
			$excludes->add($item);
		}
		return $excludes;
	}

	/**
	 * @param SyncEvent $syncEvent
	 *
	 * @return Event
	 */
	private function prepareMasterEvent(SyncEvent $syncEvent): Event
	{
		$event = (new Core\Builders\EventCloner($syncEvent->getEvent()))->build();
		(new Calendar\Sync\Util\ExcludeDatesHandler())->prepareEventExcludeDates($event, $syncEvent->getInstanceMap());

		return $event;
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit