1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
eventmanager.php
См. документацию.
1<?php
2
3namespace Bitrix\Calendar\Sync\Google;
4
5use Bitrix\Calendar\Core;
6use Bitrix\Calendar\Core\Base\BaseException;
7use Bitrix\Calendar\Core\Event\Event;
8use Bitrix\Calendar\Sync\Dictionary;
9use Bitrix\Calendar\Sync\Connection\EventConnection;
10use Bitrix\Calendar\Sync\Entities\SyncEvent;
11use Bitrix\Calendar\Sync\Connection\SectionConnection;
12use Bitrix\Calendar\Sync\Connection\Server;
13use Bitrix\Calendar\Sync\Exceptions\ConflictException;
14use Bitrix\Calendar\Sync\Managers\EventManagerInterface;
15use Bitrix\Calendar\Sync\Util\Context;
16use Bitrix\Calendar\Sync\Util\EventContext;
17use Bitrix\Calendar\Util;
18use Bitrix\Main\ArgumentException;
19use Bitrix\Main\DI\ServiceLocator;
20use Bitrix\Main\Error;
21use Bitrix\Main\LoaderException;
22use Bitrix\Main\ObjectException;
23use Bitrix\Main\SystemException;
24use Bitrix\Main\Web\HttpClient;
25use Bitrix\Calendar\Sync\Util\Result;
26use Bitrix\Main\Web\Json;
27
29{
30 public const CREATE_PATH = '/calendars/%CALENDAR_ID%/events/';
31 public const EVENT_PATH = '/calendars/%CALENDAR_ID%/events/%EVENT_ID%';
32
42 {
43 $result = new Result();
44
45 try
46 {
47 // TODO: Remake it: move this logic to parent::request().
48 // Or, better, in separate class.
49 $converter = new EventConverter(
50 event: $event,
51 );
52 $this->httpClient->post(
54 $this->encode($converter->convertForCreate())
55 );
56
57 if ($this->isRequestSuccess())
58 {
59 $requestResult = $this->prepareResult($this->httpClient->getResult(), $event);
60
61 $result->setData($requestResult);
62 }
63 else
64 {
65 $response = Json::decode($this->httpClient->getResult());
66 if (!empty($response['error']))
67 {
68 $error = $response['error'];
69 switch ($error['code'])
70 {
71 case 409:
72 throw new ConflictException($error['message'], $error['code']);
73 case 401:
74 $this->handleUnauthorize($this->connection);
75 $result->addError(new Error($error['message'], $error['code']));
76 break;
77 default:
78 if (!empty($error['code']))
79 {
80 $result->addError(new Error($error['message'], $error['code']));
81 }
82 else
83 {
84 $result->addError(new Error('Uncknown Google API error', 400));
85 }
86 }
87 }
88 }
89 }
90 catch (ConflictException $e)
91 {
92 if ($event->getUid())
93 {
94 $event->setUid(null);
95
96 return $this->create($event, $context);
97 }
98
99 $result->addError(new Error($e->getMessage(), $e->getCode()));
100 }
101 catch (ArgumentException $e)
102 {
103 $result->addError(new Error('failed to create an event in google'));
104 }
105 catch (ObjectException $e)
106 {
107 $result->addError(new Error('failed to convert event'));
108 }
109
110 return $result;
111 }
112
123 public function update(Core\Event\Event $event, EventContext $context): Result
124 {
125 $result = new Result();
126
127 try
128 {
129 // TODO: Remake it: move this logic to parent::request().
130 // Or, better, in separate class.
131 $converter = new EventConverter(
132 event: $event,
133 eventConnection: $context->getEventConnection(),
134 );
135 $this->httpClient->query(
136 HttpClient::HTTP_PUT,
137 $this->prepareUpdateUrl($context),
138 $this->encode($converter->convertForUpdate())
139 );
140
141 if ($this->isRequestSuccess())
142 {
143 $requestResult = $this->prepareResult($this->httpClient->getResult(), $event);
144 // TODO: move it to core
145 if ($childList = ($context->sync['childList'] ?? null))
146 {
151 foreach ($childList as $eventId => $childEvent)
152 {
153 $childResult = $this->createInstance($childEvent, $context);
154 if ($childResult->isSuccess())
155 {
156 $data = $childResult->getData()['event'];
157 $mapper = new Core\Mappers\EventConnection();
159 $link = $mapper->getMap([
160 '=EVENT_ID' => $childEvent->getId(),
161 '=CONNECTION_ID' => $this->connection->getId(),
162 ])->fetch();
163 if ($link)
164 {
165 $link
166 ->setVendorEventId($data['id'])
167 ->setEntityTag($data['etag'])
168 ->setVendorVersionId($data['version'])
169 ->setRecurrenceId($requestResult['event']['id'])
170 ;
171 $mapper->update($link);
172 }
173 }
174 }
175 }
176 $result->setData($requestResult);
177 }
178 else
179 {
180 $response = Json::decode($this->httpClient->getResult());
181 if (!empty($response['error']) && $response['error']['code'] === 401)
182 {
183 $this->handleUnauthorize($this->connection);
184 $result->addError(new Error($response['error']['message'], $response['error']['code']));
185 }
186 else
187 {
188 $result->addError(new Error('error of updating event', $this->httpClient->getStatus()));
189 }
190 }
191 }
192 catch (ArgumentException $e)
193 {
194 $result->addError(new Error('failed to update an event in google'));
195 }
196 catch (ObjectException $e)
197 {
198 $result->addError(new Error('failed to convert event'));
199 }
200
201 return $result;
202 }
203
213 {
214 $result = new Result();
215
216 try
217 {
218 // TODO: Remake it: move this logic to parent::request().
219 // Or, better, in separate class.
220 $converter = new EventConverter($event);
221
222 $this->httpClient->query(
223 HttpClient::HTTP_DELETE,
225 $this->encode($converter->convertForDelete())
226 );
227
228 if ($this->isRequestDeleteSuccess())
229 {
230 if ($response = $this->httpClient->getResult())
231 {
232 $requestResult = Json::decode($response);
233 $result->setData($requestResult);
234 }
235 }
236 else
237 {
238 $response = Json::decode($this->httpClient->getResult());
239 if (!empty($response['error']) && $response['error']['code'] === 401)
240 {
241 $this->handleUnauthorize($this->connection);
242 $result->addError(new Error($response['error']['message'], $response['error']['code']));
243 }
244 else
245 {
246 $result->addError(new Error('error of deleting event'));
247 }
248 }
249
250 }
251 catch (ArgumentException $e)
252 {
253 $result->addError(new Error('failed to delete an event in google'));
254 }
255 catch (ObjectException $e)
256 {
257 $result->addError(new Error('failed to convert event'));
258 }
259
260 return $result;
261 }
262
269 {
270 $result = new Result();
271
272 $instanceContext = $this->prepareContextForInstance($event, $context);
273 if ($instanceContext === null)
274 {
275 return $result->addError(new Error('failed to create an instance in google'));
276 }
277
278 try
279 {
280 // TODO: Remake it: move this logic to parent::request().
281 // Or, better, in separate class.
282
283 $converter = new EventConverter(
284 event: $event,
285 eventConnection: $instanceContext->getEventConnection()
286 );
287 $this->httpClient->query(
288 HttpClient::HTTP_PUT,
289 $this->prepareUpdateUrl($instanceContext),
290 $this->encode($converter->convertForUpdate())
291 );
292
293 if ($this->isRequestSuccess())
294 {
295 $requestResult = $this->prepareResult($this->httpClient->getResult(), $event);
296
297 $result->setData($requestResult);
298 }
299 else
300 {
301 $response = Json::decode($this->httpClient->getResult());
302 if (!empty($response['error']) && $response['error']['code'] === 401)
303 {
304 $this->handleUnauthorize($this->connection);
305 $result->addError(new Error($response['error']['message'], $response['error']['code']));
306 }
307 else
308 {
309 $result->addError(new Error('error of creating instance'));
310 }
311 }
312 }
313 catch (ArgumentException $e)
314 {
315 $result->addError(new Error('failed to create an instance in google'));
316 }
317
318 return $result;
319 }
320
326 {
327 $eventLink = $context->sync['instanceLink'];
328
329 if ($eventLink)
330 {
331 $eventContext = (new EventContext())
332 ->setSectionConnection($context->getSectionConnection())
333 ->setEventConnection($eventLink)
334 ;
335
336 $result = $this->update($event, $eventContext);
337 if (!$result->isSuccess() && $result->getErrorCollection()->getErrorByCode(403))
338 {
339 // TODO: implement it
340 }
341
342 return $result;
343 }
344
345 return (new Result())->addError(new Error('Not found link for instance'));
346 }
347
358 {
359 $result = new Result();
360 $excludeDate = $context->sync['excludeDate'] ?? null;
361 $originalDate = $context->sync['originalDate'] ?? null;
362
363 $instance = $this->getInstanceForDay($event, $excludeDate, $originalDate);
364 $instanceContext = $this->prepareContextForInstance($instance, $context);
365
366 if ($instanceContext === null)
367 {
368 return $result->addError(new Error('failed to delete an instance in google'));
369 }
370
371 try
372 {
373 $converter = new EventConverter(
374 event: $instance,
375 eventConnection: $instanceContext->getEventConnection()
376 );
377 $this->httpClient->query(
378 HttpClient::HTTP_PUT,
379 $this->prepareUpdateUrl($instanceContext),
380 $this->encode($converter->convertForDeleteInstance())
381 );
382
383 if ($this->isRequestSuccess())
384 {
385 $requestResult = $this->prepareResult($this->httpClient->getResult(), $event);
386
387 $result->setData($requestResult);
388 }
389 else
390 {
391 $response = Json::decode($this->httpClient->getResult());
392 if (!empty($response['error']) && $response['error']['code'] === 401)
393 {
394 $this->handleUnauthorizeException();
395 }
396
397 $result->addError(new Error('error of delete instance'));
398 }
399 }
400
401 catch (ArgumentException $e)
402 {
403 $result->addError(new Error('failed to delete an instance in google'));
404 }
405
406 return $result;
407 }
408
413 public function prepareCreateUrl(EventContext $context): string
414 {
415 return Server::mapUri(
416 $this->connection->getServer()->getFullPath() . self::CREATE_PATH,
417 [
418 '%CALENDAR_ID%' => Server::getEncodePath($context->getSectionConnection()->getVendorSectionId()),
419 ]
420 );
421 }
422
428 public function prepareUpdateUrl(EventContext $context): string
429 {
430 return Server::mapUri(
431 $this->connection->getServer()->getFullPath() . self::EVENT_PATH,
432 [
433 '%CALENDAR_ID%' => Server::getEncodePath($context->getSectionConnection()->getVendorSectionId()),
434 '%EVENT_ID%' => Server::getEncodePath($context->getEventConnection()->getVendorEventId()),
435 ]
436 );
437 }
438
449 public function saveRecurrence(
450 SyncEvent $recurrenceEvent,
451 SectionConnection $sectionConnection,
453 ): Result
454 {
455 $result = new Result();
456
457 if ($recurrenceEvent->getEventConnection())
458 {
459 $masterResult = $this->updateRecurrenceEntity($recurrenceEvent, $context);
460 }
461 else
462 {
463 $masterResult = $this->createRecurrenceEntity($recurrenceEvent, $sectionConnection, $context);
464 }
465
466 if (!$masterResult->isSuccess())
467 {
468 $result->addErrors($masterResult->getErrors());
469 return $result;
470 }
471
472 if ($recurrenceEvent->getInstanceMap())
473 {
475 foreach ($recurrenceEvent->getInstanceMap()->getCollection() as $instance)
476 {
477 if ($instance->getEventConnection())
478 {
479 $instanceResult = $this->updateRecurrenceEntity($instance, $context, $recurrenceEvent->getEventConnection());
480 }
481 else
482 {
483 $instanceResult = $this->createRecurrenceEntity(
484 $instance,
485 $sectionConnection,
486 $context,
487 $recurrenceEvent->getEventConnection()
488 );
489 }
490
491 if (!$result->isSuccess())
492 {
493 $result->addErrors($instanceResult->getErrors());
494 }
495 }
496 }
497
498 return $result;
499 }
500
511 public function createRecurrence(
512 SyncEvent $recurrenceEvent,
513 SectionConnection $sectionConnection,
515 ): Result
516 {
517 return $this->saveRecurrence($recurrenceEvent, $sectionConnection, $context);
518 }
519
530 public function updateRecurrence(
531 SyncEvent $recurrenceEvent,
532 SectionConnection $sectionConnection,
534 ): Result
535 {
536 return $this->saveRecurrence($recurrenceEvent, $sectionConnection, $context);
537 }
538
539
547 {
548 if (
549 ($context->getEventConnection() === null)
550 || ($context->getSectionConnection() === null)
551 )
552 {
553 return null;
554 }
555
556 $masterVendorEventId = $context->getEventConnection()->getVendorEventId();
557
558 if ($context->getEventConnection()->getEvent()->getVersion() > $event->getVersion())
559 {
560 $event->setVersion($context->getEventConnection()->getEvent()->getVersion());
561 }
562
563 return (new EventContext())
564 ->setSectionConnection($context->getSectionConnection())
565 ->setEventConnection(
566 (new EventConnection())
567 ->setVendorEventId(
568 $this->getInstanceId($masterVendorEventId, $event)
569 )
570 ->setRecurrenceId($masterVendorEventId)
571 );
572 }
573
580 private function getInstanceId(string $masterId, Event $event): string
581 {
582 $base = $masterId . '_';
583 if ($event->isFullDayEvent())
584 {
585 return $base . $event->getOriginalDateFrom()->setTimezone(Util::prepareTimezone())->format('Ymd');
586 }
587 else
588 {
589 return $base . $event->getOriginalDateFrom()->setTimezone(Util::prepareTimezone())->format('Ymd\THis\Z');
590 }
591 }
592
599 public function getInstanceForDay(
601 Core\Base\Date $excludeDate,
602 ?Core\Base\Date $originalDate = null
603 ): Event
604 {
605 $instanceEvent = clone $event;
606
607 $instanceEvent->getStart()->getDate()->setDate(
608 $excludeDate->getYear(),
609 $excludeDate->getMonth(),
610 $excludeDate->getDay()
611 );
612 $instanceEvent->getEnd()->getDate()->setDate(
613 $excludeDate->getYear(),
614 $excludeDate->getMonth(),
615 $excludeDate->getDay()
616 );
617 $instanceEvent
618 ->setOriginalDateFrom($originalDate ?? $event->getStart())
619 ->setRecurringRule(null)
620 ;
621
622 return $instanceEvent;
623 }
624
636 private function createRecurrenceEntity(
637 SyncEvent $syncEvent,
638 SectionConnection $sectionConnection,
640 EventConnection $masterLink = null
641 ): Result
642 {
643 $eventContext = new EventContext();
644 $eventContext->merge($context);
645
646 $eventContext->setSectionConnection($sectionConnection);
647
648 if ($masterLink)
649 {
650 $eventContext->setEventConnection($masterLink);
651 $result = $this->createInstance($syncEvent->getEvent(), $eventContext);
652 }
653 else
654 {
655 $result = $this->create($syncEvent->getEvent(), $eventContext);
656 }
657
658 if ($result->isSuccess())
659 {
660 if (!$syncEvent->getEvent()->isDeleted())
661 {
662 $link = (new EventConnection())
663 ->setEvent($syncEvent->getEvent())
664 ->setConnection($sectionConnection->getConnection())
665 ->setVersion($syncEvent->getEvent()->getVersion())
666 ->setVendorEventId($result->getData()['event']['id'])
667 ->setEntityTag($result->getData()['event']['etag'])
668 ;
669 $syncEvent->setEventConnection($link);
670 }
671 else
672 {
673 $syncEvent->setAction(Dictionary::SYNC_EVENT_ACTION['delete']);
674 }
675 }
676
677 return $result;
678 }
679
689 private function updateRecurrenceEntity(
690 SyncEvent $syncEvent,
691 Context $context,
692 EventConnection $masterLink = null
693 ): Result
694 {
695 $eventContext = new EventContext();
696 $eventContext->merge($context);
697 if ($masterLink)
698 {
699 $eventContext->setEventConnection($masterLink);
700 $result = $this->updateInstance($syncEvent->getEvent(), $eventContext);
701 }
702 else
703 {
704 $eventContext->setEventConnection($syncEvent->getEventConnection());
705 $result = $this->update($syncEvent->getEvent(), $eventContext);
706 }
707 if ($result->isSuccess())
708 {
709 $syncEvent->getEventConnection()->setEntityTag($result->getData()['event']['etag']);
710 }
711
712 return $result;
713 }
714
718 private function encode(array $event)
719 {
720 return Json::encode($event, JSON_UNESCAPED_SLASHES);
721 }
722
731 private function prepareResult(string $result, Event $event): array
732 {
733 $externalEvent = Json::decode($result);
734
735 // $eventConnection = (new Sync\Google\Builders\BuilderEventConnectionFromExternalEvent($externalEvent, $event, $this->connection))->build();
736 // $syncEvent =
737 // (new Sync\Entities\SyncEvent())
738 // ->setEvent($event)
739 // ->setEventConnection($eventConnection)
740 // ;
741
742 return ['event' => [
743 'id' => $externalEvent['id'],
744 'etag' => $externalEvent['etag'],
745 'version' => $externalEvent['etag'],
746 'recurrence' => $externalEvent['recurringEventId'] ?? null,
747 ]];
748 }
749
750 private function handleUnauthorizeException()
751 {
752 $this->handleUnauthorize($this->connection);
753 }
754}
updateRecurrence(SyncEvent $recurrenceEvent, SectionConnection $sectionConnection, Context $context)
Определения eventmanager.php:530
createRecurrence(SyncEvent $recurrenceEvent, SectionConnection $sectionConnection, Context $context)
Определения eventmanager.php:511
prepareContextForInstance(Event $event, EventContext $context)
Определения eventmanager.php:546
createInstance(Core\Event\Event $event, EventContext $context)
Определения eventmanager.php:268
getInstanceForDay(Event $event, Core\Base\Date $excludeDate, ?Core\Base\Date $originalDate=null)
Определения eventmanager.php:599
prepareCreateUrl(EventContext $context)
Определения eventmanager.php:413
prepareUpdateUrl(EventContext $context)
Определения eventmanager.php:428
create(Core\Event\Event $event, EventContext $context)
Определения eventmanager.php:41
updateInstance(Event $event, EventContext $context)
Определения eventmanager.php:325
deleteInstance(Event $event, EventContext $context)
Определения eventmanager.php:357
static prepareTimezone(?string $tz=null)
Определения util.php:80
Определения error.php:15
Определения date.php:9
$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
update(Event $event, EventContext $context)
$context
Определения csv_new_setup.php:223
Определения culture.php:9
trait Error
Определения error.php:11
$event
Определения prolog_after.php:141
$instance
Определения ps_b24_final.php:14
$response
Определения result.php:21