PageRenderTime 36ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/calendar/lib/update/eventwithlocationupdate.php

https://gitlab.com/alexprowars/bitrix
PHP | 421 lines | 324 code | 48 blank | 49 comment | 26 complexity | 794f9f39591f913c91775f99471c187d MD5 | raw file
  1. <?php
  2. namespace Bitrix\Calendar\Update;
  3. use Bitrix\Calendar\Rooms;
  4. use Bitrix\Main\Application;
  5. use Bitrix\Main\Config\Option;
  6. use Bitrix\Main\Loader;
  7. use Bitrix\Main\Localization\Loc;
  8. use Bitrix\Main\Update\Stepper;
  9. use CCalendar;
  10. use CCalendarEvent;
  11. final class EventWithLocationUpdate extends Stepper
  12. {
  13. const PORTION = 100;
  14. const TIMESLICE = 5200000;
  15. protected static $moduleId = 'calendar';
  16. public static function className(): string
  17. {
  18. return get_called_class();
  19. }
  20. public function execute(array &$result)
  21. {
  22. $connection = Application::getConnection();
  23. $sqlHelper = $connection->getSqlHelper();
  24. if (Loader::includeModule("calendar")
  25. && (Option::get('calendar', 'eventWithLocationConverted', 'N') === 'Y')
  26. )
  27. {
  28. Rooms\Manager::createInstance()->clearCache();
  29. return self::FINISH_EXECUTION;
  30. }
  31. $status = $this->loadCurrentStatus();
  32. $newStatus = [
  33. 'count' => $status['count'],
  34. 'steps' => $status['steps'],
  35. 'newFinished' => $status['newFinished'],
  36. 'lastEventId' => $status['lastEventId']
  37. ];
  38. // Update calendar room events
  39. if (!$status['newFinished'])
  40. {
  41. $res = $this->getLocationEvent($newStatus['lastEventId']);
  42. while ($event = $res->Fetch())
  43. {
  44. $eventId = (int)$event['ID'];
  45. $newStatus['lastEventId'] = $eventId;
  46. $parentRes = $this->getLocationParentEvent($eventId);
  47. if ($parentEvent = $parentRes->Fetch())
  48. {
  49. $ownerName = $sqlHelper->forSql(CCalendar::GetUserName($parentEvent['CREATED_BY']));
  50. $parentId = (int)$parentEvent['ID'];
  51. $this->updateLocationEvent($parentId, $ownerName, $eventId);
  52. }
  53. else
  54. {
  55. $this->deleteEvent($eventId);
  56. }
  57. $newStatus['steps']++;
  58. }
  59. if (isset($newStatus['lastEventId']) && $res->SelectedRowsCount() !== 0)
  60. {
  61. Option::set('calendar', 'eventWithLocationConvertedStatus', serialize($newStatus));
  62. $result = [
  63. 'title' => Loc::getMessage("CALENDAR_UPDATE_EVENT_WITH_LOCATION"),
  64. 'count' => $newStatus['count'],
  65. 'steps' => $newStatus['steps'],
  66. 'lastEventId' => $newStatus['lastEventId'],
  67. 'newFinished' => $newStatus['newFinished']
  68. ];
  69. return self::CONTINUE_EXECUTION;
  70. }
  71. $newStatus['newFinished'] = true;
  72. $newStatus['lastEventId'] = PHP_INT_MAX;
  73. }
  74. //update IBlock room events
  75. $meetingRoomArray = $this->getMeetingRoomArray();
  76. if ($meetingRoomArray !== null)
  77. {
  78. $res = $this->getIBlockEvent($newStatus['lastEventId']);
  79. while ($event = $res->Fetch())
  80. {
  81. $eventId = (int)$event['ID'];
  82. $newStatus['lastEventId'] = $eventId;
  83. $phrases = $this->prepareLocationEvent($event, $meetingRoomArray);
  84. if ($phrases !== null && isset($phrases['child']) && isset($phrases['parent']))
  85. {
  86. $this->updateLocationValue($phrases['parent'], $eventId);
  87. if ($event['IS_MEETING'])
  88. {
  89. $this->updateLocationValueForChildEvents($phrases['child'], $eventId);
  90. }
  91. Rooms\Manager::setEventIdForLocation($eventId);
  92. }
  93. $newStatus['steps']++;
  94. }
  95. if (isset($newStatus['lastEventId']) && $res->SelectedRowsCount() !== 0)
  96. {
  97. Option::set('calendar', 'eventWithLocationConvertedStatus', serialize($newStatus));
  98. $result = [
  99. 'title' => Loc::getMessage("CALENDAR_UPDATE_EVENT_WITH_LOCATION"),
  100. 'count' => $newStatus['count'],
  101. 'steps' => $newStatus['steps'],
  102. 'lastEventId' => $newStatus['lastEventId'],
  103. 'newFinished' => $newStatus['newFinished']
  104. ];
  105. return self::CONTINUE_EXECUTION;
  106. }
  107. }
  108. Option::set('calendar', 'eventWithLocationConverted', 'Y');
  109. Option::delete('calendar', ['name' => 'eventWithLocationConvertedStatus']);
  110. Rooms\Manager::createInstance()->clearCache();
  111. return self::FINISH_EXECUTION;
  112. }
  113. /**
  114. * @return array|mixed
  115. */
  116. private function loadCurrentStatus()
  117. {
  118. $status = Option::get('calendar', 'eventWithLocationConvertedStatus', 'default');
  119. $status = ($status !== 'default' ? @unserialize($status, ['allowed_classes' => false]) : []);
  120. $status = (is_array($status) ? $status : []);
  121. if (empty($status))
  122. {
  123. $status = [
  124. 'count' => $this->getTotalCount(),
  125. 'steps' => 0,
  126. 'lastEventId' => PHP_INT_MAX,
  127. 'newFinished' => false
  128. ];
  129. }
  130. return $status;
  131. }
  132. /**
  133. * @return int
  134. */
  135. private function getTotalCount(): int
  136. {
  137. return $this->getTotalCountLocation() + $this->getTotalCountIBlock();
  138. }
  139. /**
  140. * @return int
  141. */
  142. private function getTotalCountLocation(): int
  143. {
  144. global $DB;
  145. $count = 0;
  146. $result = $DB->Query("
  147. SELECT COUNT(*) AS cnt
  148. FROM b_calendar_event
  149. WHERE ID = PARENT_ID
  150. AND CAL_TYPE = 'location'
  151. AND DELETED = 'N';"
  152. );
  153. if ($res = $result->Fetch())
  154. {
  155. $count = (int)$res['cnt'];
  156. }
  157. return $count;
  158. }
  159. /**
  160. * @return int
  161. */
  162. private function getTotalCountIBlock(): int
  163. {
  164. global $DB;
  165. $timestamp = time() - self::TIMESLICE;
  166. $count = 0;
  167. $result = $DB->Query("
  168. SELECT COUNT(*) AS cnt
  169. FROM b_calendar_event
  170. WHERE DELETED = 'N'
  171. AND DATE_TO_TS_UTC > " . $timestamp . "
  172. AND PARENT_ID = ID
  173. AND LOCATION LIKE 'ECMR%'"
  174. );
  175. if ($res = $result->Fetch())
  176. {
  177. $count = (int)$res['cnt'];
  178. }
  179. return $count;
  180. }
  181. /**
  182. * @return mixed
  183. */
  184. private function getLocationEvent(int $lastEventId)
  185. {
  186. global $DB;
  187. return $DB->Query("
  188. SELECT ID, PARENT_ID, CAL_TYPE
  189. FROM b_calendar_event
  190. WHERE ID = PARENT_ID
  191. AND CAL_TYPE = 'location'
  192. AND DELETED = 'N'
  193. AND ID < ".$lastEventId."
  194. ORDER BY ID DESC
  195. LIMIT ".self::PORTION.";"
  196. );
  197. }
  198. /**
  199. * @param int $eventId
  200. * @return mixed
  201. */
  202. private function getLocationParentEvent(int $eventId)
  203. {
  204. global $DB;
  205. return $DB->Query("
  206. SELECT ID, CREATED_BY, LOCATION
  207. FROM b_calendar_event
  208. WHERE LOCATION LIKE 'calendar_%_".$eventId."'
  209. AND DELETED = 'N'
  210. LIMIT 1"
  211. );
  212. }
  213. /**
  214. * @param $DB
  215. * @param int $parentId
  216. * @param string $ownerName
  217. * @param int $id
  218. */
  219. private function updateLocationEvent(int $parentId, string $ownerName, int $eventId): void
  220. {
  221. global $DB;
  222. $DB->Query("
  223. UPDATE b_calendar_event
  224. SET PARENT_ID = " . $parentId . ", NAME = '" . $ownerName . "'
  225. WHERE ID = " . $eventId . ";"
  226. );
  227. }
  228. /**
  229. * @return mixed|null
  230. */
  231. private function getMeetingRoomArray()
  232. {
  233. $newMeetingRooms = Option::get('calendar', 'converted_meeting_rooms');
  234. $newMeetingRooms = json_decode($newMeetingRooms, true);
  235. if (!empty($newMeetingRooms) && is_array($newMeetingRooms))
  236. {
  237. return $newMeetingRooms;
  238. }
  239. return null;
  240. }
  241. /**
  242. * @return mixed
  243. */
  244. private function getIBlockEvent(int $lastEventId)
  245. {
  246. global $DB;
  247. $timestamp = time() - self::TIMESLICE;
  248. return $DB->Query("
  249. SELECT ID, PARENT_ID, DATE_FROM,
  250. DATE_TO, TZ_FROM, TZ_TO, IS_MEETING,
  251. RRULE, EXDATE, CREATED_BY, DT_SKIP_TIME
  252. FROM b_calendar_event
  253. WHERE DELETED = 'N'
  254. AND DATE_TO_TS_UTC > " . $timestamp . "
  255. AND LOCATION LIKE 'ECMR%'
  256. AND PARENT_ID = ID
  257. AND ID < ".$lastEventId."
  258. ORDER BY ID DESC
  259. LIMIT " . self::PORTION . ";"
  260. );
  261. }
  262. /**
  263. * @param $event
  264. * @param $meetingRoomArray
  265. * @return array|null phrases for updating the location value
  266. */
  267. private function prepareLocationEvent($event, $meetingRoomArray): ?array
  268. {
  269. global $DB;
  270. $id = (int)$event['ID'];
  271. $dateToRaw = strtotime($event['DATE_TO']);
  272. $dateFromRaw = strtotime($event['DATE_FROM']);
  273. $dateTo = CCalendar::Date($dateToRaw);
  274. $dateFrom = CCalendar::Date($dateFromRaw);
  275. $RRule = CCalendarEvent::ParseRRULE($event['RRULE']);
  276. if (isset($RRule['~UNTIL']))
  277. {
  278. unset($RRule['~UNTIL']);
  279. }
  280. if ($RRule['FREQ'] === 'WEEKLY' && !isset($RRule['BYDAY']))
  281. {
  282. return null;
  283. }
  284. $skipTime = $event['DT_SKIP_TIME'] === 'Y';
  285. $phraseLocationParent = 'calendar_#ROOMID#_#EVENTID#';
  286. $phraseLocationChild = 'calendar_#ROOMID#';
  287. $result = [];
  288. $res = $DB->Query("
  289. SELECT LOCATION
  290. FROM b_calendar_event
  291. WHERE ID = " . $id . ";"
  292. );
  293. if ($location = $res->Fetch())
  294. {
  295. $location = explode("_", $location['LOCATION']);
  296. $mrId = $location[1];
  297. $roomId = $meetingRoomArray[$mrId];
  298. $locationEventId = Rooms\Manager::reserveRoom([
  299. 'parentParams' => [
  300. 'arFields' => [
  301. 'DATE_FROM' => $dateFrom,
  302. 'DATE_TO' => $dateTo,
  303. 'TZ_FROM' => $event['TZ_FROM'],
  304. 'TZ_TO' => $event['TZ_TO'],
  305. 'SKIP_TIME' => $skipTime,
  306. 'RRULE' => $RRule,
  307. 'EXDATE' => $event['EXDATE'],
  308. 'CREATED_BY' => (int)$event['CREATED_BY']
  309. ],
  310. 'userId' => (int)$event['CREATED_BY']
  311. ],
  312. 'room_event_id' => false,
  313. 'room_id' => (int)$roomId
  314. ]);
  315. if ($locationEventId && $roomId)
  316. {
  317. $result['parent'] = str_replace(
  318. ['#ROOMID#', '#EVENTID#'],
  319. [$roomId, $locationEventId],
  320. $phraseLocationParent
  321. );
  322. $result['child'] = str_replace(
  323. ['#ROOMID#'],
  324. [$roomId],
  325. $phraseLocationChild
  326. );
  327. return $result;
  328. }
  329. }
  330. return null;
  331. }
  332. /**
  333. * @param string $phraseLocation
  334. * @param int $id
  335. */
  336. private function updateLocationValue(string $phraseLocation, int $id) : void
  337. {
  338. global $DB;
  339. $DB->Query("
  340. UPDATE b_calendar_event
  341. SET LOCATION = '" . $phraseLocation . "'
  342. WHERE ID = ".$id.";"
  343. );
  344. }
  345. /**
  346. * @param string $phraseLocation
  347. * @param int $id
  348. */
  349. private function updateLocationValueForChildEvents(string $phraseLocation, int $id) : void
  350. {
  351. global $DB;
  352. $DB->Query("
  353. UPDATE b_calendar_event
  354. SET LOCATION = '" . $phraseLocation . "'
  355. WHERE PARENT_ID = " . $id. "
  356. AND PARENT_ID <> ID
  357. AND CAL_TYPE <> 'location'
  358. AND DELETED = 'N';"
  359. );
  360. }
  361. /**
  362. * @param int $id
  363. */
  364. private function deleteEvent(int $id)
  365. {
  366. global $DB;
  367. $DB->Query("
  368. UPDATE b_calendar_event
  369. SET DELETED = 'Y'
  370. WHERE ID = " . $id . ";"
  371. );
  372. }
  373. }