Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
googletonewsync.php
1<?php
2
4
5use Bitrix\Calendar\Internals\EO_Event;
6use Bitrix\Calendar\Internals\EO_Event_Collection;
7use Bitrix\Calendar\Internals\EO_SectionConnection;
13use Bitrix\Main\Entity\ReferenceField;
21use CCalendar;
22use Exception;
23
24final class GoogleToNewSync extends Stepper
25{
26 const PORTION = 100;
27 const STATUS_SUCCESS = 'success';
28 const OPTION_CONVERTED = 'googleToNewSyncConverted';
29 const OPTION_STATUS = 'googleToNewSyncStatus';
30
31 protected static $moduleId = 'calendar';
32
33 public static function className(): string
34 {
35 return __CLASS__;
36 }
37
45 public function execute(array &$option): bool
46 {
47 if (!Loader::includeModule(self::$moduleId) || !Loader::includeModule('dav'))
48 {
50 }
51 if (Option::get(self::$moduleId, self::OPTION_CONVERTED, 'N') === 'Y')
52 {
53 CCalendar::ClearCache();
54
56 }
57
58 $status = $this->loadCurrentStatus();
59 $events = $this->getGoogleEvents();
60 $eventIds = [];
61 if ($events->count())
62 {
63 foreach ($events as $event)
64 {
65 $status['lastEventId'] = $event->getId();
67 $connection = $event->get('SECTION_CONNECTION');
68 if ($connection && $connectionId = $connection->getConnectionId())
69 {
70 $eventIds[] = $this->createEventConnection($event, $connectionId);
71 }
72 else
73 {
74 $eventIds[] = $event->getId();
75 }
76 }
77
78 if ($eventIds)
79 {
80 $this->cleanExtraEventInfo($eventIds);
81 $status['steps'] += $events->count();
82 }
83
84 Option::set(self::$moduleId, self::OPTION_STATUS, serialize($status));
85 $option = [
86 'count' => $status['count'],
87 'steps' => $status['steps'],
88 'lastEventId' => $status['lastEventId'],
89 ];
90
92 }
93
94 $this->deDuplicate();
95
96 Option::set(self::$moduleId, self::OPTION_CONVERTED, 'Y');
97 Option::delete(self::$moduleId, ['name' => self::OPTION_STATUS]);
98 $this->unblockAllPushChannels();
99 CCalendar::ClearCache();
100
102 }
103
104 private function loadCurrentStatus(): array
105 {
106 $status = Option::get(self::$moduleId, self::OPTION_STATUS, 'default');
107 $status = $status !== 'default' ? @unserialize($status, ['allowed_classes' => false]) : [];
108 $status = is_array($status) ? $status : [];
109
110 if (empty($status))
111 {
112 $status = [
113 'steps' => 0,
114 'count' => $this->getTotalCountEvents(),
115 'lastEventId' => 0,
116 ];
117 }
118
119 return $status;
120 }
121
125 private function getTotalCountEvents(): int
126 {
127 global $DB;
128 $count = 0;
129 $result = $DB->Query("
130 SELECT COUNT(*) AS cnt
131 FROM b_calendar_event
132 WHERE G_EVENT_ID IS NOT NULL
133 AND DELETED = 'N'
134 ");
135 if ($res = $result->Fetch())
136 {
137 $count = (int)$res['cnt'];
138 }
139
140 return $count;
141 }
142
149 private function getGoogleEvents(): EO_Event_Collection
150 {
151 return EventTable::query()
152 ->setSelect([
153 'ID',
154 'ORIGINAL_DATE_FROM',
155 'RECURRENCE_ID',
156 'DAV_XML_ID',
157 'G_EVENT_ID',
158 'CAL_DAV_LABEL',
159 'VERSION',
160 'SYNC_STATUS',
161 'SECTION_CONNECTION.CONNECTION_ID',
162 ])
163 ->whereNotNull('G_EVENT_ID')
164 ->where('DELETED', 'N')
165 ->setLimit(self::PORTION)
166 ->setOrder(['ID' => 'DESC'])
167 ->registerRuntimeField(
168 'SECTION_CONNECTION',
169 new ReferenceField(
170 'LINK',
171 SectionConnectionTable::getEntity(),
172 Join::on('ref.SECTION_ID', 'this.SECTION_ID'),
173 ['join_type' => Join::TYPE_LEFT]
174 )
175 )
176 ->exec()->fetchCollection()
177 ;
178 }
179
185 private function cleanExtraEventInfo(array $eventIds): void
186 {
187 global $DB;
188 $DB->Query("
189 UPDATE b_calendar_event
190 SET G_EVENT_ID = null,
191 CAL_DAV_LABEL = null,
192 SYNC_STATUS = null
193 WHERE ID IN (" . implode(',', $eventIds) . ");
194 ");
195 }
196
204 private function createEventConnection(EO_Event $event, int $connectionId): int
205 {
206 $recId = ($event->getOriginalDateFrom() && $event->getRecurrenceId())
207 ? $event->getDavXmlId()
208 : null
209 ;
210 EventConnectionTable::add([
211 'EVENT_ID' => $event->getId(),
212 'CONNECTION_ID' => $connectionId,
213 'VENDOR_EVENT_ID' => $event->getGEventId(),
214 'SYNC_STATUS' => self::STATUS_SUCCESS,
215 'ENTITY_TAG' => $event->getCalDavLabel(),
216 'VERSION' => $event->getVersion(),
217 'VENDOR_VERSION_ID' => $event->getVersion(),
218 'RECURRENCE_ID' => $recId,
219 ]);
220
221 return $event->getId();
222 }
223
227 private function unblockAllPushChannels(): void
228 {
229 global $DB;
230 $DB->Query("
231 UPDATE b_calendar_push
232 SET NOT_PROCESSED = 'N'
233 WHERE 1;
234 ");
235 }
236
244 private function deDuplicate()
245 {
246 $this->deDuplicateEvents();
247 $this->deDuplicateSections();
248 }
249
257 private function deDuplicateEvents()
258 {
259 global $DB;
260 $sql = "SELECT GROUP_CONCAT(link.ID) as ids
261 FROM b_calendar_event_connection link
262 GROUP BY link.CONNECTION_ID , link.EVENT_ID
263 HAVING count(*) > 1
264 ;";
265 $duplicateGroups = $DB->Query($sql);
266 while ($row = $duplicateGroups->Fetch())
267 {
268 $ids = explode(',', $row['ids']);
269 $this->processEventDubles($ids);
270 }
271 }
272
280 private function deDuplicateSections()
281 {
282 global $DB;
283 $sql = "SELECT GROUP_CONCAT(link.ID) as ids
284 FROM b_calendar_section_connection link
285 GROUP BY link.CONNECTION_ID , link.SECTION_ID
286 HAVING count(*) > 1
287 ;";
288 $duplicateGroups = $DB->Query($sql);
289 while ($row = $duplicateGroups->Fetch())
290 {
291 $ids = explode(',', $row['ids']);
292 $this->processSectionDubles($ids);
293 }
294 }
295
305 private function processEventDubles(array $linkIds)
306 {
307 $this->processDubles(
308 $linkIds,
309 new EventConnectionTable(),
310 'VENDOR_EVENT_ID'
311 );
312 }
313
323 private function processSectionDubles(array $linkIds)
324 {
325 $this->processDubles(
326 $linkIds,
327 new SectionConnectionTable(),
328 'VENDOR_SECTION_ID'
329 );
330 }
331
344 private function processDubles(array $linkIds, DataManager $table, string $validFieldName)
345 {
346 $validRow = $table->query()
347 ->setSelect(['ID'])
348 ->addFilter("!$validFieldName", false)
349 ->whereIn('ID', $linkIds)
350 ->fetch();
351
352 if (!empty($validRow))
353 {
354 foreach ($linkIds as $index => $linkId)
355 {
356 if ($linkId == $validRow['ID'])
357 {
358 unset($linkIds[$index]);
359 break;
360 }
361 }
362 }
363
364 foreach ($linkIds as $linkId)
365 {
366 $table->delete($linkId);
367 }
368 }
369}
execute(array &$option)