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/managers/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

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

namespace Bitrix\Calendar\Sync\Managers;

use Bitrix\Calendar\Core;
use Bitrix\Calendar\Core\Base\BaseException;
use Bitrix\Calendar\Core\Base\Map;
use Bitrix\Calendar\Core\Section\Section;
use Bitrix\Calendar\Core\Event\Event;
use Bitrix\Calendar\Internals\EventConnectionTable;
use Bitrix\Calendar\Internals\EventTable;
use Bitrix\Calendar\Sync\Connection\Connection;
use Bitrix\Calendar\Sync\Connection\EventConnection;
use Bitrix\Calendar\Sync\Connection\SectionConnection;
use Bitrix\Calendar\Sync\Dictionary;
use Bitrix\Calendar\Sync\Entities\InstanceMap;
use Bitrix\Calendar\Sync\Entities\SyncEvent;
use Bitrix\Calendar\Sync\Exceptions\RemoteAccountException;
use Bitrix\Calendar\Sync\Factories\FactoriesCollection;
use Bitrix\Calendar\Sync\Factories\FactoryInterface;
use Bitrix\Calendar\Sync;
use Bitrix\Calendar\Sync\Util\Context;
use Bitrix\Calendar\Sync\Util\EventContext;
use Bitrix\Calendar\Sync\Util\ExcludeDatesHandler;
use Bitrix\Calendar\Sync\Util\Result;
use Bitrix\Calendar\Sync\Util\SectionContext;
use Bitrix\Main\ArgumentException;
use Bitrix\Main\DI\ServiceLocator;
use Bitrix\Main\Error;
use Bitrix\Main\ObjectNotFoundException;
use Bitrix\Main\ObjectPropertyException;
use Bitrix\Main\ORM\Query\Query;
use Bitrix\Main\SystemException;
use CCalendar;
use CCalendarSect;
use Exception;

class Synchronization
{
	/** @var VendorSynchronization[]  */
	private array $subManagers = [];
	/**
	 * @var FactoriesCollection
	 */
	private FactoriesCollection $factories;
	/**
	 * @var mixed
	 */
	private Core\Mappers\Factory $mapperFactory;

	/**
	 * @param FactoriesCollection $factories
	 *
	 * @throws ObjectNotFoundException
	 */
	public function __construct(FactoriesCollection $factories)
	{
		$this->factories = $factories;
		$this->mapperFactory = ServiceLocator::getInstance()->get('calendar.service.mappers.factory');

	}

	/**
	 * @param Event $event
	 * @param Context $context
	 *
	 * @return Result
	 * @throws ArgumentException
	 * @throws Core\Base\BaseException
	 * @throws ObjectPropertyException
	 * @throws SystemException
	 */
	public function createEvent(Event $event, Context $context): Result
	{
		if ($event->getExcludedDateCollection() && $event->getExcludedDateCollection()->count())
		{
			$slaveEvents = $this->getSlaveEvents($event);
			$context->add('sync', 'slaveEvents', $slaveEvents);
			$this->prepareEventExDates($event, $slaveEvents);
		}
		return $this->execActionEvent('createEvent', $event, $context);
	}

	/**
	 * @param Event $event
	 * @param Context $context
	 *
	 * @return Result
	 * @throws ArgumentException
	 * @throws Core\Base\BaseException
	 * @throws ObjectPropertyException
	 * @throws SystemException
	 */
	public function updateEvent(Event $event, Context $context): Result
	{
		if ($event->getExcludedDateCollection()->count())
		{
			$slaveEvents = $this->getSlaveEvents($event);
			$context->add('sync', 'slaveEvents', $slaveEvents);
			$this->prepareEventExDates($event, $slaveEvents);
		}
		return $this->execActionEvent('updateEvent', $event, $context);
	}

	/**
	 * @param Event $event
	 * @param Context $context
	 *
	 * @return Result
	 * @throws ArgumentException
	 * @throws Core\Base\BaseException
	 * @throws ObjectPropertyException
	 * @throws SystemException
	 */
	public function deleteEvent(Event $event, Context $context): Result
	{
		return $this->execActionEvent('deleteEvent', $event, $context);
	}

	/**
	 * @param string $method
	 * @param Event $event
	 * @param Context $context
	 *
	 * @return Result
	 * @throws ArgumentException
	 * @throws Core\Base\BaseException
	 * @throws ObjectPropertyException
	 * @throws SystemException
	 */
	private function execActionEvent(string $method, Event $event, Context $context): Result
	{
		$mainResult = new Result();
		$data = [];
		$eventCloner = new Core\Builders\EventCloner($event);
		$pushManager = new PushManager();
		$push = null;

		/** @var FactoryInterface $factory */
		foreach ($this->factories as $factory)
		{
			if ($this->checkExclude($factory, $context, $method))
			{
				continue;
			}

			try
			{

				$clonedEvent = $eventCloner->build();
				$vendorSync = $this->getVendorSynchronization($factory);
				$eventContext = $this->prepareEventContext($clonedEvent, clone $context, $factory);

				if ($eventContext->getSectionConnection()?->getId())
				{
					$push = $pushManager->getPush(PushManager::TYPE_SECTION_CONNECTION, $eventContext->getSectionConnection()->getId());
					$pushManager->setBlockPush($push);
				}

				$vendorResult = $vendorSync->$method($clonedEvent, $eventContext);

				$data[$this->getVendorCode($factory)] = $vendorResult;
				if (!$vendorResult->isSuccess())
				{
					$mainResult->addErrors($vendorResult->getErrors());
				}
			}
			catch (RemoteAccountException $e)
			{
				$mainResult->addError(new Error($e->getMessage(), $e->getCode()));
			}
			finally
			{
				$pushManager->setUnblockPush($push);
			}
		}

		return $mainResult->setData($data);
	}

	/**
	 * @param Event $masterEvent
	 * @param Context $context
	 *
	 * @return Result
	 *
	 * @throws ArgumentException
	 * @throws BaseException
	 * @throws ObjectNotFoundException
	 * @throws ObjectPropertyException
	 * @throws SystemException
	 * @throws Exception
	 */
	public function reCreateRecurrence(Event $masterEvent, Context $context): Result
	{
		$mainResult = new Result();
		$eventExceptionsMap = $this->getEventExceptionsMap($masterEvent);
		$data = [];
		$masterEvent->setVersion($masterEvent->getVersion() + 1);
		$eventCloner = new Core\Builders\EventCloner($masterEvent);

		/** @var FactoryInterface $factory */
		foreach ($this->factories as $factory)
		{
			if ($this->checkExclude($factory, $context))
			{
				continue;
			}
			try
			{
				$safeEvent = $eventCloner->build();
				$safeExceptionsMap = $this->cloneEventMap($eventExceptionsMap);
				$vendorSyncManager = $this->getVendorSynchronization($factory);
				$eventContext = $this->prepareEventContext($safeEvent, clone $context, $factory);

				if ($factory->getServiceName() === Sync\Icloud\Factory::SERVICE_NAME)
				{
					$syncEvent = $this->prepareRecurrenceEvent($safeEvent, $safeExceptionsMap, $factory);
					$vendorResult = $vendorSyncManager->updateRecurrence($syncEvent, $eventContext);
				}
				else
				{
					$syncEvent = $this->prepareRecurrenceEvent($safeEvent, $safeExceptionsMap);
					$deleteResult = $vendorSyncManager->deleteEvent($safeEvent, clone $eventContext);
					if ($deleteResult->isSuccess() && $syncEvent->getEventConnection())
					{
						$this->mapperFactory->getEventConnection()->delete($syncEvent->getEventConnection());
					}
					$syncEvent->setEventConnection(null);
					$vendorResult = $vendorSyncManager->createRecurrence($syncEvent, $eventContext);
				}

				$data[$this->getVendorCode($factory)] = $vendorResult;
				if (!$vendorResult->isSuccess())
				{
					$mainResult->addErrors($vendorResult->getErrors());
				}
			}
			catch (RemoteAccountException $e)
			{
				$mainResult->addError(new Error($e->getMessage(), $e->getCode()));
			}
		}

		return $mainResult->setData($data);
	}

	/**
	 * @param Event $event
	 * @param Context $context
	 *
	 * @return Result
	 *
	 * @throws ArgumentException
	 * @throws Core\Base\BaseException
	 * @throws ObjectPropertyException
	 * @throws SystemException
	 * @throws ObjectNotFoundException
	 * @throws Exception
	 */
	public function createRecurrence(Event $event, Context $context): Result
	{
		// if (empty($event->getRecurringRule()))
		// {
		// 	return $this->createEvent($event, $context);
		// }

		$eventExceptionsMap = $this->getEventExceptionsMap($event);
		$mainResult = new Result();
		$data = [];
		$eventCloner = new Core\Builders\EventCloner($event);
		/** @var FactoryInterface $factory */
		foreach ($this->factories as $factory)
		{
			if ($this->checkExclude($factory, $context))
			{
				continue;
			}
			try
			{
				$safeEvent = $eventCloner->build();
				$vendorSyncManager = $this->getVendorSynchronization($factory);
				$eventContext = $this->prepareEventContext($safeEvent, $context, $factory);
				$syncEvent = $this->prepareRecurrenceEvent($safeEvent, $eventExceptionsMap);

				$vendorResult = $vendorSyncManager->createRecurrence($syncEvent, $eventContext);

				$data[$this->getVendorCode($factory)] = $vendorResult;
				if (!$vendorResult->isSuccess())
				{
					$mainResult->addErrors($vendorResult->getErrors());
				}
			}
			catch (RemoteAccountException $e)
			{
				$mainResult->addError(new Error($e->getMessage(), $e->getCode()));
			}

		}

		return $mainResult->setData($data);
	}

	/**
	 * @param Event $event
	 * @param Context $context
	 *
	 * @return Result
	 * @throws ArgumentException
	 * @throws Core\Base\BaseException
	 * @throws ObjectPropertyException
	 * @throws SystemException
	 */
	public function createInstance(Event $event, Context $context): Result
	{
		return $this->execActionEvent('createInstance', $event, $context);
	}

	/**
	 * @param Event $event
	 * @param Context $context
	 *
	 * @return Result
	 * @throws ArgumentException
	 * @throws Core\Base\BaseException
	 * @throws ObjectPropertyException
	 * @throws SystemException
	 */
	public function updateInstance(Event $event, Context $context): Result
	{
		return $this->execActionEvent('updateInstance', $event, $context);
	}

	/**
	 * @param Event $event
	 * @param Context $context
	 *
	 * @return Result
	 * @throws ArgumentException
	 * @throws Core\Base\BaseException
	 * @throws ObjectPropertyException
	 * @throws SystemException
	 */
	public function deleteInstance(Event $event, Context $context): Result
	{
		$mainResult = new Result();

		if (
			!isset($context->diff['EXDATE'])
			&& !isset($context->sync['excludeDate'])
			&& !$event->getExcludedDateCollection()->count()
		)
		{
			$mainResult->addError(new Error('Not found info about exclude date'));
			return $mainResult;
		}

		if (!isset($context->sync['excludeDate']))
		{
			$diff = is_array($context->diff['EXDATE'])
				? $context->diff['EXDATE']
				: explode(';', $context->diff['EXDATE']);
			if (isset($context->sync['excludeDate']))
			{
				$excludeDate = $context->sync['excludeDate'];
			}
			else
			{
				$excludeDates = array_filter(
					$event->getExcludedDateCollection()->getCollection(),
					function($item) use ($diff)
					{
						return !in_array($item->format(CCalendar::DFormat(false)), $diff);
					});
				$excludeDate = $excludeDates ? reset($excludeDates) : [];
			}

			$context->add('sync', 'excludeDate', $excludeDate);
		}

		return $this->execActionEvent('deleteInstance', $event, $context);

	}

	/**
	 * @param string $method
	 * @param Section $section
	 * @param Context $context
	 *
	 * @return Result
	 * @throws ArgumentException
	 * @throws Core\Base\BaseException
	 * @throws ObjectPropertyException
	 * @throws SystemException
	 */
	private function execActionSection(
		string $method,
		Section $section,
		Context $context
	): Result
	{
		$mainResult = new Result();
		$resultData = [];
		$pushManager = new PushManager();
		$push = null;

		/** @var FactoryInterface $factory */
		foreach ($this->factories as $factory)
		{
			if ($this->checkExclude($factory, $context, $method))
			{
				continue;
			}

			if ($factory->getConnection()->getId())
			{
				$push = $pushManager->getPush(PushManager::TYPE_CONNECTION, $factory->getConnection()->getId());
				$pushManager->setBlockPush($push);
			}

			try
			{
				$vendorSync = $this->getVendorSynchronization($factory);
				$sectionContext = $this->prepareSectionContext($section, $context, $factory);
				$vendorResult = $vendorSync->$method($section, $sectionContext);
				$resultData[$this->getVendorCode($factory)] = $vendorResult;
				if (!$vendorResult->isSuccess())
				{
					$mainResult->addErrors($vendorResult->getErrors());
				}
			}
			catch (RemoteAccountException $e)
			{
				$mainResult->addError(new Error($e->getMessage(), $e->getCode()));
			}
			finally
			{
				$pushManager->setUnblockPush($push);
			}
		}

		return $mainResult->setData($resultData);
	}

	/**
	 * @param Section $section
	 * @param Context $context
	 *
	 * @return Result
	 * @throws ArgumentException
	 * @throws Core\Base\BaseException
	 * @throws ObjectPropertyException
	 * @throws SystemException
	 */
	public function createSection(Section $section, Context $context): Result
	{
		return $this->execActionSection('createSection', $section, $context);
	}

	/**
	 * @param Section $section
	 * @param Context $context
	 *
	 * @return Result
	 * @throws ArgumentException
	 * @throws Core\Base\BaseException
	 * @throws ObjectPropertyException
	 * @throws SystemException
	 */
	public function updateSection(Section $section, Context $context): Result
	{
		return $this->execActionSection('updateSection', $section, $context);
	}

	/**
	 * @param Section $section
	 * @param Context $context
	 *
	 * @return Result
	 * @throws ArgumentException
	 * @throws Core\Base\BaseException
	 * @throws ObjectPropertyException
	 * @throws SystemException
	 */
	public function deleteSection(Section $section, Context $context): Result
	{
		$result = $this->execActionSection('deleteSection', $section, $context);
		CCalendarSect::cleanLinkTables($section->getId());

		return $result;
	}

	/**
	 * @param Event $event
	 * @param Connection $connection
	 * @param string $version
	 *
	 * @return void
	 *
	 * @throws ArgumentException
	 * @throws ObjectPropertyException
	 * @throws SystemException
	 * @throws Exception
	 */
	public function upEventVersion(Event $event, Connection $connection, string $version)
	{
		/** @var EventConnection $link */
		$link = $this->mapperFactory->getEventConnection()->getMap([
			'=CONNECTION_ID' => $connection->getId(),
			'=EVENT_ID' => $event->getId(),
		])->fetch();

		if ($link)
		{
			$link->setVersion((int)$version);
			EventConnectionTable::update($link->getId(), [
				'fields' => [
					'VERSION' => $version,
				],
			]);
		}
	}

	public function deleteInstanceEventConnection(Event $event)
	{
		$links = $this->mapperFactory->getEventConnection()->getMap([
			'=EVENT_ID' => $event->getId(),
		])->getCollection();

		/** @var EventConnection $link */
		foreach ($links as $link)
		{
			EventConnectionTable::delete($link->getId());
		}
	}

	/**
	 * @param FactoryInterface $factory
	 *
	 * @return VendorSynchronization
	 *
	 * @throws ObjectNotFoundException
	 */
	private function getVendorSynchronization(FactoryInterface $factory): VendorSynchronization
	{
		$key = $factory->getConnection()->getVendor()->getCode();
		if (empty($this->subManagers[$key]))
		{
			$this->subManagers[$key] =  new VendorSynchronization($factory);
		}

		return $this->subManagers[$key];
	}

	/**
	 * @param FactoryInterface $factory
	 * @param Context|null $context
	 * @param string $string
	 *
	 * @return bool
	 */
	private function checkExclude(
		FactoryInterface $factory,
		?Context $context,
		string $string = ''
	): bool
	{
		if (isset($context->sync)
			&& !empty($context->sync['originalFrom'])
			&& $context->sync['originalFrom'] === $this->getVendorCode($factory)
		)
		{
			return true;
		}

		return false;
	}

	/**
	 * @param FactoryInterface $factory
	 *
	 * @return string
	 */
	private function getVendorCode(FactoryInterface $factory): string
	{
		return $factory->getConnection()->getVendor()->getCode();
	}

	/**
	 * @param Event $event
	 * @param Context $context
	 * @param FactoryInterface $factory
	 *
	 * @return EventContext
	 * @throws ArgumentException
	 * @throws Core\Base\BaseException
	 * @throws ObjectPropertyException
	 * @throws SystemException
	 */
	private function prepareEventContext(Event $event, Context $context, FactoryInterface $factory): EventContext
	{
		$sectionLink = $context->sync['sectionLink'] ?? $this->getSectionConnection($event->getSection(), $factory);
		$eventLink = $context->sync['eventLink'] ?? $this->getEventConnection($event, $factory);

		return (new EventContext())
			->merge($context)
			->setSectionConnection($sectionLink)
			->setEventConnection($eventLink)
		;
	}

	/**
	 * @param Section $section
	 * @param Context $context
	 * @param FactoryInterface $factory
	 *
	 * @return Context|SectionContext
	 * @throws ArgumentException
	 * @throws Core\Base\BaseException
	 * @throws ObjectPropertyException
	 * @throws SystemException
	 */
	private function prepareSectionContext(Section $section, Context $context, FactoryInterface $factory)
	{
		$sectionLink = $context->sync['sectionLink'] ?? $this->getSectionConnection($section, $factory);

		return (new SectionContext())
			->merge($context)
			->setSectionConnection($sectionLink)
		;
	}

	/**
	 * @param Section $section
	 * @param FactoryInterface $factory
	 *
	 * @return SectionConnection|null
	 * @throws ArgumentException
	 * @throws Core\Base\BaseException
	 * @throws ObjectPropertyException
	 * @throws SystemException
	 */
	private function getSectionConnection(Section $section, FactoryInterface $factory): ?SectionConnection
	{
		return $this->mapperFactory->getSectionConnection()->getMap([
			'=SECTION_ID' => $section->getId(),
			'=CONNECTION_ID' => $factory->getConnection()->getId(),
		])->fetch();
	}

	/**
	 * @param Event $event
	 * @param FactoryInterface $factory
	 *
	 * @return EventConnection|null
	 * @throws ArgumentException
	 * @throws Core\Base\BaseException
	 * @throws SystemException
	 */
	private function getEventConnection(Event $event, ?FactoryInterface $factory): ?EventConnection
	{
		if (!$factory)
		{
			return null;
		}
		$link = $this->mapperFactory->getEventConnection()->getMap([
			'=EVENT_ID' => $event->getId(),
			'=CONNECTION_ID' => $factory->getConnection()->getId(),
		])->fetch();

		return $link;
	}

	/**
	 * @param Event $event
	 *
	 * @return Core\Base\Map
	 *
	 * @throws ArgumentException
	 * @throws SystemException
	 */
	private function getSlaveEvents(Event $event): Core\Base\Map
	{
		$map = $this->getEventExceptionsMap($event);

		return new Core\Event\EventMap(
			array_reduce($map->getCollection(), static function ($result, $value)
			{
				/** @var Event $value */
				if ($value->getOriginalDateFrom())
				{
					$key = $value->getOriginalDateFrom()->format('Ymd');
					$result[$key] = $value->getId();
				}

				return $result;
			}, []) ?? []
		);
	}

	/**
	 * @param Event $event
	 * @param Core\Base\Map $slaveEvents
	 *
	 * @return void
	 */
	private function prepareEventExDates(Event $event, Core\Base\Map $slaveEvents)
	{
		(new ExcludeDatesHandler())->prepareEventExcludeDates($event, $slaveEvents);
	}

	/**
	 * @param Event $event
	 *
	 * @return Core\Base\Map
	 *
	 * @throws ArgumentException
	 * @throws SystemException
	 * todo move it to the special class
	 */
	private function getEventExceptionsMap(Event $event): Core\Base\Map
	{
		$mapClass = Core\Event\EventMap::class;
		$result = new $mapClass;

		$queryResult = EventTable::query()
			->setSelect(['*'])
			->where('RECURRENCE_ID', $event->getParentId())
			->where('DELETED', 'N')
			->where('OWNER_ID', $event->getOwner()->getId())
			->where(Query::filter()
			->logic('or')
				->whereNot('MEETING_STATUS', 'N')
				->whereNull('MEETING_STATUS')
			)
			->whereNotNull('ORIGINAL_DATE_FROM')
			->exec()
		;
		/** @var Event $row */
		while ($row = $queryResult->fetchObject())
		{
			$eventEntity = $this->mapperFactory->getEvent()->getByEntityObject($row);
			if ($eventEntity)
			{
				$result->add($eventEntity, $eventEntity->getId());
			}
		}

		return $result;
	}

	/**
	 * @param Event $event
	 * @param Map $eventExceptionsMap
	 * @param FactoryInterface|null $factory
	 *
	 * @return SyncEvent
	 *
	 * @throws ArgumentException
	 * @throws BaseException
	 * @throws SystemException
	 */
	private function prepareRecurrenceEvent(
		Event $event,
		Core\Base\Map $eventExceptionsMap,
		?FactoryInterface $factory = null
	): SyncEvent
	{
		$masterLink = $this->getEventConnection($event, $factory);
		$syncEvent = (new SyncEvent())
			->setEvent($event)
			->setAction(Dictionary::SYNC_EVENT_ACTION['create'])
			->setEventConnection($masterLink)
			->setInstanceMap(new InstanceMap());
		/** @var Event $exceptionEvent */
		foreach ($eventExceptionsMap as $exceptionEvent)
		{
			$instance = (new SyncEvent())
				->setEvent($exceptionEvent)
				->setAction(Dictionary::SYNC_EVENT_ACTION['create'])
				->setEventConnection($this->getEventConnection($exceptionEvent, $factory));
			$syncEvent->getInstanceMap()->add($instance);
		}
		(new ExcludeDatesHandler())->prepareEventExcludeDates($event, $syncEvent->getInstanceMap());

		return $syncEvent;
	}

	/**
	 * @param Core\Event\EventMap $eventExceptionsMap
	 *
	 * @return Core\Event\EventMap
	 *
	 * @throws ArgumentException
	 */
	private function cloneEventMap(Core\Event\EventMap $eventExceptionsMap): Core\Event\EventMap
	{
		$result = new Core\Event\EventMap();
		foreach ($eventExceptionsMap as $key => $event)
		{
			$result->add((new Core\Builders\EventCloner($event))->build(), $key);
		}

		return $result;
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit