1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
synchronization.php
См. документацию.
1<?php
2
3namespace Bitrix\Calendar\Sync\Managers;
4
5use Bitrix\Calendar\Core;
6use Bitrix\Calendar\Core\Base\BaseException;
7use Bitrix\Calendar\Core\Base\Map;
8use Bitrix\Calendar\Core\Section\Section;
9use Bitrix\Calendar\Core\Event\Event;
10use Bitrix\Calendar\Internals\EventConnectionTable;
11use Bitrix\Calendar\Internals\EventTable;
12use Bitrix\Calendar\Sync\Connection\Connection;
13use Bitrix\Calendar\Sync\Connection\EventConnection;
14use Bitrix\Calendar\Sync\Connection\SectionConnection;
15use Bitrix\Calendar\Sync\Dictionary;
16use Bitrix\Calendar\Sync\Entities\InstanceMap;
17use Bitrix\Calendar\Sync\Entities\SyncEvent;
18use Bitrix\Calendar\Sync\Exceptions\RemoteAccountException;
19use Bitrix\Calendar\Sync\Factories\FactoriesCollection;
20use Bitrix\Calendar\Sync\Factories\FactoryInterface;
21use Bitrix\Calendar\Sync;
22use Bitrix\Calendar\Sync\Util\Context;
23use Bitrix\Calendar\Sync\Util\EventContext;
24use Bitrix\Calendar\Sync\Util\ExcludeDatesHandler;
25use Bitrix\Calendar\Sync\Util\Result;
26use Bitrix\Calendar\Sync\Util\SectionContext;
27use Bitrix\Main\ArgumentException;
28use Bitrix\Main\DI\ServiceLocator;
29use Bitrix\Main\Error;
30use Bitrix\Main\ObjectNotFoundException;
31use Bitrix\Main\ObjectPropertyException;
32use Bitrix\Main\ORM\Query\Query;
33use Bitrix\Main\SystemException;
34use CCalendar;
35use CCalendarSect;
36use Exception;
37
39{
41 private array $subManagers = [];
45 private FactoriesCollection $factories;
49 private Core\Mappers\Factory $mapperFactory;
50
56 public function __construct(FactoriesCollection $factories)
57 {
58 $this->factories = $factories;
59 $this->mapperFactory = ServiceLocator::getInstance()->get('calendar.service.mappers.factory');
60
61 }
62
74 {
75 if ($event->getExcludedDateCollection() && $event->getExcludedDateCollection()->count())
76 {
77 $slaveEvents = $this->getSlaveEvents($event);
78 $context->add('sync', 'slaveEvents', $slaveEvents);
79 $this->prepareEventExDates($event, $slaveEvents);
80 }
81 return $this->execActionEvent('createEvent', $event, $context);
82 }
83
95 {
96 if ($event->getExcludedDateCollection()->count())
97 {
98 $slaveEvents = $this->getSlaveEvents($event);
99 $context->add('sync', 'slaveEvents', $slaveEvents);
100 $this->prepareEventExDates($event, $slaveEvents);
101 }
102 return $this->execActionEvent('updateEvent', $event, $context);
103 }
104
116 {
117 return $this->execActionEvent('deleteEvent', $event, $context);
118 }
119
131 private function execActionEvent(string $method, Event $event, Context $context): Result
132 {
133 $mainResult = new Result();
134 $data = [];
135 $eventCloner = new Core\Builders\EventCloner($event);
136 $pushManager = new PushManager();
137 $push = null;
138
140 foreach ($this->factories as $factory)
141 {
142 if ($this->checkExclude($factory, $context, $method))
143 {
144 continue;
145 }
146
147 try
148 {
149
150 $clonedEvent = $eventCloner->build();
151 $vendorSync = $this->getVendorSynchronization($factory);
152 $eventContext = $this->prepareEventContext($clonedEvent, clone $context, $factory);
153
154 if ($eventContext->getSectionConnection()?->getId())
155 {
156 $push = $pushManager->getPush(PushManager::TYPE_SECTION_CONNECTION, $eventContext->getSectionConnection()->getId());
157 $pushManager->setBlockPush($push);
158 }
159
160 $vendorResult = $vendorSync->$method($clonedEvent, $eventContext);
161
162 $data[$this->getVendorCode($factory)] = $vendorResult;
163 if (!$vendorResult->isSuccess())
164 {
165 $mainResult->addErrors($vendorResult->getErrors());
166 }
167 }
168 catch (RemoteAccountException $e)
169 {
170 $mainResult->addError(new Error($e->getMessage(), $e->getCode()));
171 }
172 finally
173 {
174 $pushManager->setUnblockPush($push);
175 }
176 }
177
178 return $mainResult->setData($data);
179 }
180
194 public function reCreateRecurrence(Event $masterEvent, Context $context): Result
195 {
196 $mainResult = new Result();
197 $eventExceptionsMap = $this->getEventExceptionsMap($masterEvent);
198 $data = [];
199 $masterEvent->setVersion($masterEvent->getVersion() + 1);
200 $eventCloner = new Core\Builders\EventCloner($masterEvent);
201
203 foreach ($this->factories as $factory)
204 {
205 if ($this->checkExclude($factory, $context))
206 {
207 continue;
208 }
209 try
210 {
211 $safeEvent = $eventCloner->build();
212 $safeExceptionsMap = $this->cloneEventMap($eventExceptionsMap);
213 $vendorSyncManager = $this->getVendorSynchronization($factory);
214 $eventContext = $this->prepareEventContext($safeEvent, clone $context, $factory);
215
216 if ($factory->getServiceName() === Sync\Icloud\Factory::SERVICE_NAME)
217 {
218 $syncEvent = $this->prepareRecurrenceEvent($safeEvent, $safeExceptionsMap, $factory);
219 $vendorResult = $vendorSyncManager->updateRecurrence($syncEvent, $eventContext);
220 }
221 else
222 {
223 $syncEvent = $this->prepareRecurrenceEvent($safeEvent, $safeExceptionsMap);
224 $deleteResult = $vendorSyncManager->deleteEvent($safeEvent, clone $eventContext);
225 if ($deleteResult->isSuccess() && $syncEvent->getEventConnection())
226 {
227 $this->mapperFactory->getEventConnection()->delete($syncEvent->getEventConnection());
228 }
229 $syncEvent->setEventConnection(null);
230 $vendorResult = $vendorSyncManager->createRecurrence($syncEvent, $eventContext);
231 }
232
233 $data[$this->getVendorCode($factory)] = $vendorResult;
234 if (!$vendorResult->isSuccess())
235 {
236 $mainResult->addErrors($vendorResult->getErrors());
237 }
238 }
239 catch (RemoteAccountException $e)
240 {
241 $mainResult->addError(new Error($e->getMessage(), $e->getCode()));
242 }
243 }
244
245 return $mainResult->setData($data);
246 }
247
261 public function createRecurrence(Event $event, Context $context): Result
262 {
263 // if (empty($event->getRecurringRule()))
264 // {
265 // return $this->createEvent($event, $context);
266 // }
267
268 $eventExceptionsMap = $this->getEventExceptionsMap($event);
269 $mainResult = new Result();
270 $data = [];
271 $eventCloner = new Core\Builders\EventCloner($event);
273 foreach ($this->factories as $factory)
274 {
275 if ($this->checkExclude($factory, $context))
276 {
277 continue;
278 }
279 try
280 {
281 $safeEvent = $eventCloner->build();
282 $vendorSyncManager = $this->getVendorSynchronization($factory);
283 $eventContext = $this->prepareEventContext($safeEvent, $context, $factory);
284 $syncEvent = $this->prepareRecurrenceEvent($safeEvent, $eventExceptionsMap);
285
286 $vendorResult = $vendorSyncManager->createRecurrence($syncEvent, $eventContext);
287
288 $data[$this->getVendorCode($factory)] = $vendorResult;
289 if (!$vendorResult->isSuccess())
290 {
291 $mainResult->addErrors($vendorResult->getErrors());
292 }
293 }
294 catch (RemoteAccountException $e)
295 {
296 $mainResult->addError(new Error($e->getMessage(), $e->getCode()));
297 }
298
299 }
300
301 return $mainResult->setData($data);
302 }
303
315 {
316 return $this->execActionEvent('createInstance', $event, $context);
317 }
318
330 {
331 return $this->execActionEvent('updateInstance', $event, $context);
332 }
333
345 {
346 $mainResult = new Result();
347
348 if (
349 !isset($context->diff['EXDATE'])
350 && !isset($context->sync['excludeDate'])
351 && !$event->getExcludedDateCollection()->count()
352 )
353 {
354 $mainResult->addError(new Error('Not found info about exclude date'));
355 return $mainResult;
356 }
357
358 if (!isset($context->sync['excludeDate']))
359 {
360 $diff = is_array($context->diff['EXDATE'])
361 ? $context->diff['EXDATE']
362 : explode(';', $context->diff['EXDATE']);
363 if (isset($context->sync['excludeDate']))
364 {
365 $excludeDate = $context->sync['excludeDate'];
366 }
367 else
368 {
369 $excludeDates = array_filter(
370 $event->getExcludedDateCollection()->getCollection(),
371 function($item) use ($diff)
372 {
373 return !in_array($item->format(CCalendar::DFormat(false)), $diff);
374 });
375 $excludeDate = $excludeDates ? reset($excludeDates) : [];
376 }
377
378 $context->add('sync', 'excludeDate', $excludeDate);
379 }
380
381 return $this->execActionEvent('deleteInstance', $event, $context);
382
383 }
384
396 private function execActionSection(
397 string $method,
398 Section $section,
400 ): Result
401 {
402 $mainResult = new Result();
403 $resultData = [];
404 $pushManager = new PushManager();
405 $push = null;
406
408 foreach ($this->factories as $factory)
409 {
410 if ($this->checkExclude($factory, $context, $method))
411 {
412 continue;
413 }
414
415 if ($factory->getConnection()->getId())
416 {
417 $push = $pushManager->getPush(PushManager::TYPE_CONNECTION, $factory->getConnection()->getId());
418 $pushManager->setBlockPush($push);
419 }
420
421 try
422 {
423 $vendorSync = $this->getVendorSynchronization($factory);
424 $sectionContext = $this->prepareSectionContext($section, $context, $factory);
425 $vendorResult = $vendorSync->$method($section, $sectionContext);
426 $resultData[$this->getVendorCode($factory)] = $vendorResult;
427 if (!$vendorResult->isSuccess())
428 {
429 $mainResult->addErrors($vendorResult->getErrors());
430 }
431 }
432 catch (RemoteAccountException $e)
433 {
434 $mainResult->addError(new Error($e->getMessage(), $e->getCode()));
435 }
436 finally
437 {
438 $pushManager->setUnblockPush($push);
439 }
440 }
441
442 return $mainResult->setData($resultData);
443 }
444
455 public function createSection(Section $section, Context $context): Result
456 {
457 return $this->execActionSection('createSection', $section, $context);
458 }
459
470 public function updateSection(Section $section, Context $context): Result
471 {
472 return $this->execActionSection('updateSection', $section, $context);
473 }
474
485 public function deleteSection(Section $section, Context $context): Result
486 {
487 $result = $this->execActionSection('deleteSection', $section, $context);
488 CCalendarSect::cleanLinkTables($section->getId());
489
490 return $result;
491 }
492
505 public function upEventVersion(Event $event, Connection $connection, string $version)
506 {
508 $link = $this->mapperFactory->getEventConnection()->getMap([
509 '=CONNECTION_ID' => $connection->getId(),
510 '=EVENT_ID' => $event->getId(),
511 ])->fetch();
512
513 if ($link)
514 {
515 $link->setVersion((int)$version);
516 EventConnectionTable::update($link->getId(), [
517 'fields' => [
518 'VERSION' => $version,
519 ],
520 ]);
521 }
522 }
523
524 public function deleteInstanceEventConnection(Event $event)
525 {
526 $links = $this->mapperFactory->getEventConnection()->getMap([
527 '=EVENT_ID' => $event->getId(),
528 ])->getCollection();
529
531 foreach ($links as $link)
532 {
533 EventConnectionTable::delete($link->getId());
534 }
535 }
536
544 private function getVendorSynchronization(FactoryInterface $factory): VendorSynchronization
545 {
546 $key = $factory->getConnection()->getVendor()->getCode();
547 if (empty($this->subManagers[$key]))
548 {
549 $this->subManagers[$key] = new VendorSynchronization($factory);
550 }
551
552 return $this->subManagers[$key];
553 }
554
562 private function checkExclude(
563 FactoryInterface $factory,
564 ?Context $context,
565 string $string = ''
566 ): bool
567 {
568 if (isset($context->sync)
569 && !empty($context->sync['originalFrom'])
570 && $context->sync['originalFrom'] === $this->getVendorCode($factory)
571 )
572 {
573 return true;
574 }
575
576 return false;
577 }
578
584 private function getVendorCode(FactoryInterface $factory): string
585 {
586 return $factory->getConnection()->getVendor()->getCode();
587 }
588
600 private function prepareEventContext(Event $event, Context $context, FactoryInterface $factory): EventContext
601 {
602 $sectionLink = $context->sync['sectionLink'] ?? $this->getSectionConnection($event->getSection(), $factory);
603 $eventLink = $context->sync['eventLink'] ?? $this->getEventConnection($event, $factory);
604
605 return (new EventContext())
606 ->merge($context)
607 ->setSectionConnection($sectionLink)
608 ->setEventConnection($eventLink)
609 ;
610 }
611
623 private function prepareSectionContext(Section $section, Context $context, FactoryInterface $factory)
624 {
625 $sectionLink = $context->sync['sectionLink'] ?? $this->getSectionConnection($section, $factory);
626
627 return (new SectionContext())
628 ->merge($context)
629 ->setSectionConnection($sectionLink)
630 ;
631 }
632
643 private function getSectionConnection(Section $section, FactoryInterface $factory): ?SectionConnection
644 {
645 return $this->mapperFactory->getSectionConnection()->getMap([
646 '=SECTION_ID' => $section->getId(),
647 '=CONNECTION_ID' => $factory->getConnection()->getId(),
648 ])->fetch();
649 }
650
660 private function getEventConnection(Event $event, ?FactoryInterface $factory): ?EventConnection
661 {
662 if (!$factory)
663 {
664 return null;
665 }
666 $link = $this->mapperFactory->getEventConnection()->getMap([
667 '=EVENT_ID' => $event->getId(),
668 '=CONNECTION_ID' => $factory->getConnection()->getId(),
669 ])->fetch();
670
671 return $link;
672 }
673
682 private function getSlaveEvents(Event $event): Core\Base\Map
683 {
684 $map = $this->getEventExceptionsMap($event);
685
686 return new Core\Event\EventMap(
687 array_reduce($map->getCollection(), static function ($result, $value)
688 {
690 if ($value->getOriginalDateFrom())
691 {
692 $key = $value->getOriginalDateFrom()->format('Ymd');
693 $result[$key] = $value->getId();
694 }
695
696 return $result;
697 }, []) ?? []
698 );
699 }
700
707 private function prepareEventExDates(Event $event, Core\Base\Map $slaveEvents)
708 {
709 (new ExcludeDatesHandler())->prepareEventExcludeDates($event, $slaveEvents);
710 }
711
721 private function getEventExceptionsMap(Event $event): Core\Base\Map
722 {
723 $mapClass = Core\Event\EventMap::class;
724 $result = new $mapClass;
725
726 $queryResult = EventTable::query()
727 ->setSelect(['*'])
728 ->where('RECURRENCE_ID', $event->getParentId())
729 ->where('DELETED', 'N')
730 ->where('OWNER_ID', $event->getOwner()->getId())
731 ->where(Query::filter()
732 ->logic('or')
733 ->whereNot('MEETING_STATUS', 'N')
734 ->whereNull('MEETING_STATUS')
735 )
736 ->whereNotNull('ORIGINAL_DATE_FROM')
737 ->exec()
738 ;
740 while ($row = $queryResult->fetchObject())
741 {
742 $eventEntity = $this->mapperFactory->getEvent()->getByEntityObject($row);
743 if ($eventEntity)
744 {
745 $result->add($eventEntity, $eventEntity->getId());
746 }
747 }
748
749 return $result;
750 }
751
763 private function prepareRecurrenceEvent(
764 Event $event,
765 Core\Base\Map $eventExceptionsMap,
766 ?FactoryInterface $factory = null
767 ): SyncEvent
768 {
769 $masterLink = $this->getEventConnection($event, $factory);
770 $syncEvent = (new SyncEvent())
771 ->setEvent($event)
772 ->setAction(Dictionary::SYNC_EVENT_ACTION['create'])
773 ->setEventConnection($masterLink)
774 ->setInstanceMap(new InstanceMap());
776 foreach ($eventExceptionsMap as $exceptionEvent)
777 {
778 $instance = (new SyncEvent())
779 ->setEvent($exceptionEvent)
780 ->setAction(Dictionary::SYNC_EVENT_ACTION['create'])
781 ->setEventConnection($this->getEventConnection($exceptionEvent, $factory));
782 $syncEvent->getInstanceMap()->add($instance);
783 }
784 (new ExcludeDatesHandler())->prepareEventExcludeDates($event, $syncEvent->getInstanceMap());
785
786 return $syncEvent;
787 }
788
796 private function cloneEventMap(Core\Event\EventMap $eventExceptionsMap): Core\Event\EventMap
797 {
798 $result = new Core\Event\EventMap();
799 foreach ($eventExceptionsMap as $key => $event)
800 {
801 $result->add((new Core\Builders\EventCloner($event))->build(), $key);
802 }
803
804 return $result;
805 }
806}
$connection
Определения actionsdefinitions.php:38
const SYNC_EVENT_ACTION
Определения dictionary.php:47
createInstance(Event $event, Context $context)
Определения synchronization.php:314
updateSection(Section $section, Context $context)
Определения synchronization.php:470
deleteSection(Section $section, Context $context)
Определения synchronization.php:485
deleteInstance(Event $event, Context $context)
Определения synchronization.php:344
createEvent(Event $event, Context $context)
Определения synchronization.php:73
updateEvent(Event $event, Context $context)
Определения synchronization.php:94
deleteEvent(Event $event, Context $context)
Определения synchronization.php:115
__construct(FactoriesCollection $factories)
Определения synchronization.php:56
createSection(Section $section, Context $context)
Определения synchronization.php:455
updateInstance(Event $event, Context $context)
Определения synchronization.php:329
Определения error.php:15
$data['IS_AVAILABLE']
Определения .description.php:13
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
$result
Определения get_property_values.php:14
$context
Определения csv_new_setup.php:223
$map
Определения config.php:5
$value
Определения Param.php:39
Определения culture.php:9
trait Error
Определения error.php:11
$event
Определения prolog_after.php:141
$instance
Определения ps_b24_final.php:14
if(empty($signedUserToken)) $key
Определения quickway.php:257
$method
Определения index.php:27