Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
apiservice.php
1<?php
2
4
12use Bitrix\Dav\Integration\Calendar\RecurrenceEventBuilder;
14
16{
18 protected ?ApiClient $apiClient = null;
20 protected ?\CDavGroupdavClientCalendar $davClient = null;
22 protected Helper $helper;
24 protected ?array $error = null;
25
32 public function __construct(array $server = [], int $userId = null)
33 {
34 $this->helper = new Helper();
35 if ($server)
36 {
37 $this->davClient = $this->createDavInstance(
38 $server['SERVER_SCHEME'],
39 $server['SERVER_HOST'],
40 $server['SERVER_PORT'],
41 $server['SERVER_USERNAME'],
42 $server['SERVER_PASSWORD']
43 );
44
45 $this->apiClient = new ApiClient($this->davClient, $userId);
46 }
47 }
48
56 public function getPrinciples($connection, $server): ?string
57 {
58 $userId = \CCalendar::GetUserId();
59 $davClient = $this->createDavInstance(
60 $server['scheme'],
61 $server['host'],
62 $server['port'],
63 $connection['SERVER_USERNAME'],
64 $connection['SERVER_PASSWORD']
65 );
66
67 $this->apiClient = new ApiClient($davClient, $userId);
68 $principlesXml = $this->apiClient->propfind(
69 $server['path'],
70 ['current-user-principal'],
71 null,
72 0
73 );
74 if ($principlesXml)
75 {
76 return $this->getXmlStringData(
77 $principlesXml,
78 '/response/propstat/prop/current-user-principal/href'
79 );
80 }
81
82 return null;
83 }
84
92 public function getCalendarPath($connection, $server): ?string
93 {
94 $userId = \CCalendar::GetUserId();
95 $davClient = $this->createDavInstance(
96 $server['scheme'],
97 $server['host'],
98 $server['port'],
99 $connection['SERVER_USERNAME'],
100 $connection['SERVER_PASSWORD']
101 );
102
103 $this->apiClient = new ApiClient($davClient, $userId);
104 $calendarXml = $this->apiClient->propfind(
105 $server['path'],
106 [['calendar-home-set', 'urn:ietf:params:xml:ns:caldav']],
107 null,
108 0
109 );
110
111 if ($calendarXml)
112 {
113 return $this->getXmlStringData(
114 $calendarXml,
115 '/response/propstat/prop/calendar-home-set/href'
116 );
117 }
118
119 return null;
120 }
121
128 public function getCalendarList($connection, $server): ?array
129 {
130 $davClient = $this->createDavInstance(
131 $server['scheme'],
132 $server['host'],
133 $server['port'],
134 $connection['SERVER_USERNAME'],
135 $connection['SERVER_PASSWORD']
136 );
137
138 $calendars = $davClient->GetCalendarList($server['path']);
139 if (!is_array($calendars) || empty($calendars))
140 {
141 return null;
142 }
143
144 return $calendars;
145 }
146
157 public function createEvent(string $path, Event $event): ?array
158 {
160 $xmlId = $event->getUid();
161
162 return $this->editEvent($path, $xmlId, $event);
163 }
164
176 public function updateEvent(string $path, Event $event, ?array $data): ?array
177 {
178 $xmlId = $event->getUid();
179 if (!$xmlId)
180 {
181 return null;
182 }
183
184 if ($event->getExcludedDateCollection()->getCollection())
185 {
186 return $this->saveInstance($path, $event, $data);
187 }
188
189 $eventPath = $this->davClient->GetRequestEventPath($path, $xmlId);
190
191 return $this->editEvent($eventPath, $xmlId, $event, $data);
192 }
193
201 public function deleteEvent(string $path, Event $event): ?bool
202 {
203 $xmlId = $event->getUid();
204 $acceptCodes = [200, 201, 204, 404];
205
206 if (!$xmlId)
207 {
208 return null;
209 }
210
211 $eventPath = $this->davClient->GetRequestEventPath($path, $xmlId);
212
213 $result = (int)$this->apiClient->delete($eventPath);
214
215 if ($this->davClient->getError())
216 {
217 $this->addError($this->davClient->getError());
218 }
219
220 if (in_array($result, $acceptCodes))
221 {
222 return true;
223 }
224
225 return null;
226 }
227
241 public function saveInstance(string $path, Event $event, ?array $data, Date $excludeDate = null): ?array
242 {
243 $xmlId = $event->getUid();
244 if (!$xmlId)
245 {
246 return null;
247 }
248
249 $event = (new EventCloner($event))->build();
250 [$eventPath, $calendarData] = $this->prepareInstanceData($event, $path, $xmlId, $data, $excludeDate);
251
252 return $this->sendPutAction($eventPath, $calendarData);
253 }
254
265 public function saveRecurrence(string $path, SyncEvent $recurrenceEvent): ?array
266 {
267 if (!$recurrenceEvent->getEvent()->getUid())
268 {
269 $recurrenceEvent->getEvent()->setUid(VendorSyncService::generateUuid());
270 }
271 $xmlId = $recurrenceEvent->getEvent()->getUid();
272
273 [$eventPath, $calendarData] = $this->prepareRecurrenceData($recurrenceEvent, $path, $xmlId);
274
275 return $this->sendPutAction($eventPath, $calendarData);
276 }
277
285 public function createSection(string $path, Section $section): ?array
286 {
287 $content = SectionBuilder::getInstance()->getCreateSectionContent($section);
288 $result = (int)$this->apiClient->mkcol($path, $content);
289
290 if ($this->davClient->getError())
291 {
292 $this->addError($this->davClient->getError());
293 }
294
295 if ($result === 200 || $result === 201)
296 {
297 $result = $this->davClient->GetCalendarList($path);
298 if ($result && is_array($result))
299 {
300 return [
301 'XML_ID' => $result[0]['href'],
302 'MODIFICATION_LABEL' => $result[0]['getctag'],
303 ];
304 }
305 }
306
307 return null;
308 }
309
317 public function updateSection(string $path, Section $section): ?array
318 {
319 $content = SectionBuilder::getInstance()->getUpdateSectionContent($section);
320 $result = (int)$this->apiClient->proppatch($path, $content);
321
322 if ($this->davClient->getError())
323 {
324 $this->addError($this->davClient->getError());
325 }
326
327 if ($result === 207)
328 {
329 $result = $this->davClient->GetCalendarList($path);
330 if ($result && is_array($result))
331 {
332 return [
333 'XML_ID' => $result[0]['href'],
334 'MODIFICATION_LABEL' => $result[0]['getctag'],
335 ];
336 }
337 }
338 else
339 {
340 return [
341 'ERROR' => $result,
342 ];
343 }
344
345 return null;
346 }
347
354 public function deleteSection(string $path): ?bool
355 {
356 $result = (int)$this->apiClient->delete($path);
357
358 if ($this->davClient->getError())
359 {
360 $this->addError($this->davClient->getError());
361 }
362
363 $acceptCodes = [200, 201, 204, 404];
364
365 if (in_array($result, $acceptCodes))
366 {
367 return true;
368 }
369
370 return null;
371 }
372
373 public function getSectionsList($path)
374 {
375 return $this->davClient->GetCalendarList($path);
376 }
377
378 public function getEventsList($path, $syncToken): ?array
379 {
380 return $this->davClient->GetCalendarItemsBySyncToken($path, $syncToken);
381 }
382
383 public function getEventsListWithHref($path, $hrefs): ?array
384 {
385 return $this->davClient->GetCalendarItemsList($path, $hrefs, true);
386 }
387
388 public function prepareUrl(string $url): array
389 {
390 $parsed = parse_url($url);
391 if (empty($parsed['port']))
392 {
393 $parsed['port'] = ($parsed['scheme'] === 'https'
394 ? 443
395 : 80
396 );
397 }
398
399 return $parsed;
400 }
401
408 private function getXmlStringData($xml, $path): string
409 {
410 $data = '';
411 $responsePath = $xml->GetPath('/*/response');
412 foreach ($responsePath as $response)
413 {
414 if (!$data)
415 {
416 $dataXml = $response->GetPath($path);
417 if (!empty($dataXml))
418 {
419 $data = urldecode($dataXml[0]->GetContent());
420 }
421 }
422 }
423
424 return $data;
425 }
426
436 private function createDavInstance(
437 string $scheme,
438 string $host,
439 string $port,
440 string $username,
441 string $password
442 ): \CDavGroupdavClientCalendar
443 {
444 $davClient = new \CDavGroupdavClientCalendar(
445 $scheme,
446 $host,
447 $port,
448 $username,
449 $password,
450 );
451 $davClient->SetPrivateIp(false);
452
453 return $davClient;
454 }
455
462 private function getPath(string $path, ?string $xmlId): string
463 {
464 if (mb_substr($path, -mb_strlen('/' . $xmlId . '.ics')) != '/' . $xmlId . '.ics')
465 {
466 $path = rtrim($path, '/');
467 $path .= '/' . $xmlId . '.ics';
468 }
469
470 return $path;
471 }
472
485 private function editEvent(
486 string $path,
487 ?string $xmlId,
488 Event $event,
489 ?array $data = null
490 ): ?array
491 {
492 $path = $this->getPath($path, $xmlId);
493 $calendarData = EventBuilder::getInstance()->getContent($event, $data);
494 if ($calendarData)
495 {
496 $calendarData = (new \CDavICalendar($calendarData))->Render();
497 }
498
499 return $this->sendPutAction($path, $calendarData);
500 }
501
515 private function prepareInstanceData(
516 Event $event,
517 string $path,
518 string $xmlId,
519 ?array $data,
520 Date $excludeDate = null
521 ): array
522 {
523 $instancesOriginalDate = [];
524 $exDates = $event->getExcludedDateCollection();
525 $excludedInstance = $excludeDate ? $excludeDate->format('Ymd') : null;
526
527 $instances = EventTable::query()
528 ->setSelect(['*'])
529 ->where('RECURRENCE_ID', $event->getParentId())
530 ->where('DELETED', 'N')
531 ->where('OWNER_ID', $event->getOwner()->getId())
532 // ->whereNot('MEETING_STATUS', 'N')
533 ->where(Query::filter() // TODO: it's better to optimize it and don't use 'OR' logic here
534 ->logic('or')
535 ->whereNot('MEETING_STATUS', 'N')
536 ->whereNull('MEETING_STATUS')
537 )
538 ->exec()->fetchCollection()
539 ;
540
541 foreach ($instances as $instance)
542 {
543 $originalDate = $instance->getOriginalDateFrom()
544 ? $instance->getOriginalDateFrom()->format('Ymd')
545 : $instance->getDateFrom()->format('Ymd')
546 ;
547 if ($originalDate === $excludedInstance)
548 {
549 $instances->remove($instance);
550 continue;
551 }
552
553 $instancesOriginalDate[] = $originalDate;
554 }
555
556 if ($exDates)
557 {
562 foreach ($exDates->getCollection() as $key => $exDate)
563 {
564 if (in_array($exDate->format('Ymd'), $instancesOriginalDate, true))
565 {
566 $exDates->remove($key);
567 }
568 }
569 $event->setExcludedDateCollection($exDates);
570 }
571
572 $eventPath = $this->davClient->GetRequestEventPath($path, $xmlId);
573 $eventPath = $this->getPath($eventPath, $xmlId);
574 $calendarData[] = EventBuilder::getInstance()->getContent($event, $data);
575
576 foreach ($instances as $instance)
577 {
578 $instanceObject = (new EventBuilderFromEntityObject($instance))->build();
579 $instanceObject->setUid($xmlId);
580 $calendarData[] = EventBuilder::getInstance()->getContent($instanceObject, $data);
581 }
582 if ($calendarData)
583 {
584 $calendarData = (new RecurrenceEventBuilder($calendarData))->Render();
585 }
586
587 return [$eventPath, $calendarData];
588 }
589
601 private function prepareRecurrenceData(SyncEvent $recurrenceEvent, string $path, $xmlId): array
602 {
603 $instanceDates = [];
604 $exDates = $recurrenceEvent->getEvent()->getExcludedDateCollection();
605
607 foreach ($recurrenceEvent->getInstanceMap()->getCollection() as $instance)
608 {
609 $instanceDates[] = $instance->getEvent()->getOriginalDateFrom()
610 ? $instance->getEvent()->getOriginalDateFrom()->format('Ymd')
611 : $instance->getEvent()->getStart()->format('Ymd')
612 ;
613 }
614
615 if ($exDates)
616 {
621 foreach ($exDates->getCollection() as $key => $date)
622 {
623 if (in_array($date->format('Ymd'), $instanceDates, true))
624 {
625 $exDates->remove($key);
626 }
627 }
628
629 $recurrenceEvent->getEvent()->setExcludedDateCollection($exDates);
630 }
631
632 $eventPath = $this->davClient->GetRequestEventPath($path, $xmlId);
633 $eventPath = $this->getPath($eventPath, $xmlId);
634 $calendarData[] = EventBuilder::getInstance()->getContent($recurrenceEvent->getEvent());
635
636 foreach ($recurrenceEvent->getInstanceMap()->getCollection() as $instance)
637 {
638 $instance->getEvent()->setUid($xmlId);
639 $calendarData[] = EventBuilder::getInstance()->getContent($instance->getEvent());
640 }
641
642 if ($calendarData)
643 {
644 $calendarData = (new RecurrenceEventBuilder($calendarData))->Render();
645 }
646
647 return [$eventPath, $calendarData];
648 }
649
657 private function sendPutAction(string $path, $calendarData): ?array
658 {
659 $result = (int)$this->apiClient->put($path, $calendarData);
660
661 if ($this->davClient->getError())
662 {
663 $this->addError($this->davClient->getError());
664 }
665
666 if ($result === 201 || $result === 204)
667 {
668 $result = $this->davClient->GetCalendarItemsList(
669 $path,
670 null,
671 false,
672 2
673 );
674
675 if ($result && is_array($result))
676 {
677 return [
678 'XML_ID' => $this->davClient::getBasenameWithoutExtension($result[0]['href']),
679 'MODIFICATION_LABEL' => $result[0]['getetag'],
680 ];
681 }
682 }
683
684 return null;
685 }
686
691 private function addError(array $error)
692 {
693 $this->error = $error;
694 }
695
699 public function getError(): ?array
700 {
701 return $this->error;
702 }
703}
updateSection(string $path, Section $section)
saveInstance(string $path, Event $event, ?array $data, Date $excludeDate=null)
createEvent(string $path, Event $event)
deleteEvent(string $path, Event $event)
__construct(array $server=[], int $userId=null)
getPrinciples($connection, $server)
updateEvent(string $path, Event $event, ?array $data)
createSection(string $path, Section $section)
CDavGroupdavClientCalendar $davClient
getCalendarList($connection, $server)
saveRecurrence(string $path, SyncEvent $recurrenceEvent)
getCalendarPath($connection, $server)