24 private const CALENDAR_LIST_URL_CALENDAR_ID =
'/users/me/calendarList/%CALENDAR_ID%';
25 private const EVENT_LIST_URL_CALENDAR_ID =
'/calendars/%CALENDAR_ID%/events';
26 private const CALENDAR_LIST_URL =
'/users/me/calendarList';
27 private const CALENDAR_PRIMARY_ID =
'primary';
29 private const SYNC_EVENTS_LIMIT = 50;
70 $this->httpClient->query(
72 $this->prepareCalendarListUrlWithId(self::CALENDAR_PRIMARY_ID)
77 $externalResult = $this->parseResponse($this->httpClient->getResult());
81 return $result->addError(
new Error($e->getMessage()));
84 if ($this->isRequestSuccess())
86 $requestResult = $this->parseResponse($this->httpClient->getResult());
88 return $result->setData([
'id' => $requestResult[
'id']]);
92 if ($helper->isNotValidSyncTokenError($this->prepareError($externalResult)))
94 $this->connection->setToken(
null);
95 $result->addError(
new Error(
'Auth error on getting connection Id', 410));
99 if ($helper->isMissingRequiredAuthCredential($this->prepareError($externalResult)))
101 $this->handleUnauthorize($this->connection);
102 $result->addError(
new Error(
'Auth error on getting sections', 401));
107 return $result->addError(
new Error(
'Do not sync sections'));
111 return $result->addError(
new Error(
'Failed to get connection name'));
126 $this->httpClient->query(
128 $this->prepareCalendarListUrl()
133 $externalResult = $this->parseResponse($this->httpClient->getResult());
137 return $result->addError(
new Error($e->getMessage()));
140 if ($this->isRequestSuccess())
142 $this->connection->setToken($externalResult[
'nextSyncToken']);
143 $this->etag = $externalResult[
'etag'];
144 $this->connection->setStatus(
'[200] OK')
145 ->setLastSyncTime(
new Date())
149 if (!empty($externalResult[
'items']) && is_array($externalResult[
'items']))
151 foreach ($externalResult[
'items'] as $item)
160 return $result->setData([
'externalSyncSectionMap' => $map]);
165 if ($helper->isNotValidSyncTokenError($this->prepareError($externalResult)))
167 $this->connection->setToken(
null);
172 if ($helper->isMissingRequiredAuthCredential($this->prepareError($externalResult)))
174 $this->handleUnauthorize($this->connection);
175 $result->addError(
new Error(
'Auth error on getting sections', 401));
180 $result->addError(
new Error(
'Do not sync sections'));
184 $result->addError(
new Error(
'Failed to get sections'));
197 $result = (
new Result())->setData([
198 'externalSyncEventMap' => $map,
206 $this->httpClient->query(
208 $this->prepareEventListUrl(
209 $this->syncSectionConnection->getVendorSectionId(),
210 $this->prepareRequestParams($this->syncSectionConnection)
216 $externalResult = $this->parseResponse($this->httpClient->getResult());
218 catch (\Exception $e)
220 return $result->addError(
new Error($e->getMessage()));
224 if ($this->isRequestSuccess())
226 $impatientInstanceListByUid = [];
228 $this->etag = $externalResult[
'etag'];
229 $this->syncToken = $externalResult[
'nextSyncToken'] ??
null;
230 $this->pageToken = $externalResult[
'nextPageToken'] ??
null;
233 $this->handleSuccessBehavior($externalResult);
235 if (!empty($externalResult[
'items']) && is_array($externalResult[
'items']))
237 foreach ($externalResult[
'items'] as $item)
239 $syncEvent = (
new BuilderSyncEventFromExternalData($item, $this->connection, $syncSection))
242 if ($syncEvent->isInstance() || $syncEvent->getVendorRecurrenceId())
245 $masterEvent = $map->has($syncEvent->getVendorRecurrenceId())
246 ? $map->getItem($syncEvent->getVendorRecurrenceId())
252 $impatientInstanceListByUid[$syncEvent->getVendorRecurrenceId()][] = $syncEvent;
256 $masterEvent->addInstance($syncEvent);
260 if ($syncEvent->isRecurrence()
261 && ($instanceList = ($impatientInstanceListByUid[$syncEvent->getUid()] ??
null))
264 $syncEvent->addInstanceList($instanceList);
265 unset($impatientInstanceListByUid[$syncEvent->getUid()]);
268 $map->add($syncEvent, $syncEvent->getVendorEventId());
273 foreach ($impatientInstanceListByUid as $syncEventList)
275 foreach($syncEventList as $syncEvent)
277 $map->add($syncEvent, $syncEvent->getVendorEventId());
284 $helper =
new Helper();
286 if ($helper->isNotValidSyncTokenError($this->prepareError($externalResult)))
293 if ($helper->isMissingRequiredAuthCredential($this->prepareError($externalResult)))
295 $this->handleUnauthorize($this->connection);
296 $result->addError(
new Error(
'Auth error on getting events', 401));
301 $this->handleErroneousBehavior($syncSection);
303 catch (BaseException $e)
305 $result->addError(
new Error($e->getMessage()));
333 'connection' => $this->connection,
382 private function prepareSectionResult(
string $result)
384 return Json::decode($result);
390 private function prepareCalendarListUrl(): string
394 if ($token = $this->connection->getToken())
396 $requestParams =
'?' . http_build_query([
397 'showDeleted' =>
'true',
398 'showHidden' =>
'true',
399 'syncToken' => $token,
401 $requestParams = preg_replace(
'/(%3D)/',
'=', $requestParams);
404 return $this->connection->getVendor()->getServer()->getFullPath()
405 . self::CALENDAR_LIST_URL
414 private function prepareCalendarListUrlWithId(
string $calendarId): string
416 return Server::mapUri(
417 $this->connection->getVendor()->getServer()->getFullPath() . self::CALENDAR_LIST_URL_CALENDAR_ID,
419 '%CALENDAR_ID%' => $calendarId,
429 private function prepareEventListUrl(
string $calendarId, array $requestParams = []): string
431 $url = Server::mapUri(
432 $this->connection->getVendor()->getServer()->getFullPath() . self::EVENT_LIST_URL_CALENDAR_ID,
434 '%CALENDAR_ID%' => urlencode($calendarId),
438 if (!empty($requestParams))
440 $url .=
'?' . preg_replace(
'/(%3D)/',
'=', http_build_query($requestParams));
451 private function parseResponse(
string $result)
453 return Json::decode($result);
460 private function handleErroneousBehavior(SyncSection $syncSection): void
462 $sectionConnection = $syncSection->getSectionConnection();
463 if ($sectionConnection)
465 $this->syncToken = $sectionConnection->getSyncToken();
466 $this->pageToken = $sectionConnection->getPageToken();
467 $this->etag = $sectionConnection->getVersionId();
468 $this->modified = $sectionConnection->getLastSyncDate();
477 private function handleSuccessBehavior($result): void
479 $this->syncSectionConnection->setSyncToken($result[
'nextSyncToken'] ??
null);
480 $this->syncSectionConnection->setPageToken($result[
'nextPageToken'] ??
null);
483 $this->syncSectionConnection->setVersionId($result[
'etag'] ??
null);
484 $this->defaultRemind = $result[
'defaultReminders'][0] ??
null;
485 $this->modified = ($result[
'updated'] ??
null)
490 $status = $this->httpClient->getStatus();
498 private function getRequestParamsWithSyncToken(SectionConnection $sectionConnection): array
501 'pageToken' => $sectionConnection->getPageToken(),
502 'syncToken' => $sectionConnection->getSyncToken(),
503 'showDeleted' =>
'true',
511 private function getRequestParamsForFirstSync(SectionConnection $sectionConnection): array
514 'pageToken' => $sectionConnection->getPageToken(),
515 'showDeleted' =>
'true',
516 'maxResults' => self::SYNC_EVENTS_LIMIT,
529 isset($error[
'error'][
'code'], $error[
'error'][
'message'])
534 . $error[
'error'][
'code']
537 . $error[
'error'][
'message']
547 private function prepareRequestParams(
SectionConnection $sectionConnection): array
549 return array_filter($sectionConnection->getSyncToken()
550 ? $this->getRequestParamsWithSyncToken($sectionConnection)
551 : $this->getRequestParamsForFirstSync($sectionConnection)