Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
calendarfilter.php
1<?php
2
4
8use Bitrix\Main\Entity\ReferenceField;
12
14{
15 private const PRESET_INVITED = 'filter_calendar_meeting_status_q';
16 private const PRESET_HOST = 'filter_calendar_host';
17 private const PRESET_ATTENDEE = 'filter_calendar_attendee';
18 private const PRESET_DECLINED = 'filter_calendar_declined';
19
20 protected static $filterId = '';
21
22 protected static array $filters;
23
28 protected static function getAvailableFields(): array
29 {
30 return [
31 'CREATED_BY',
32 'ATTENDEES',
33 'IS_MEETING',
34 'IS_RECURSIVE',
35 'MEETING_STATUS',
36 'MEETING_HOST',
37 'DATE_FROM',
38 'DATE_TO',
39 'SECTION_ID',
40 'FROM_LIMIT',
41 'TO_LIMIT',
42 ];
43 }
44
52 public static function getFilterId($type, $ownerId, $userId): string
53 {
54 static::$filterId = 'calendar-filter';
55 if ($type === 'user' && (int)$ownerId === (int)$userId)
56 {
57 static::$filterId = 'calendar-filter-personal';
58 }
59 else if (
60 $type === 'company_calendar'
61 || $type === 'calendar_company'
62 || $type === 'company'
63 )
64 {
65 static::$filterId = 'calendar-filter-company';
66 }
67 else if ($type === 'group')
68 {
69 static::$filterId = 'calendar-filter-group';
70 }
71
72 return static::$filterId;
73 }
74
78 public static function setFilterId($filterId)
79 {
80 static::$filterId = $filterId;
81 }
82
88 public static function getPresets($type): array
89 {
90 $presets = [];
91 if ($type === 'user')
92 {
93 $presets[self::PRESET_INVITED] = [
94 'id' => self::PRESET_INVITED,
95 'name' => Loc::getMessage('CALENDAR_PRESET_MEETING_STATUS_Q'),
96 'default' => false,
97 'fields' => [
98 'IS_MEETING' => 'Y',
99 'MEETING_STATUS' => 'Q',
100 ]
101 ];
102 }
103
104 $presets[self::PRESET_HOST] = [
105 'id' => self::PRESET_HOST,
106 'name' => Loc::getMessage('CALENDAR_PRESET_I_AM_HOST'),
107 'default' => false,
108 'fields' => [
109 'MEETING_STATUS' => 'H',
110 ]
111 ];
112
113 $presets[self::PRESET_ATTENDEE] = [
114 'id' => self::PRESET_ATTENDEE,
115 'name' => Loc::getMessage('CALENDAR_PRESET_I_AM_ATTENDEE'),
116 'default' => false,
117 'fields' => [
118 'IS_MEETING' => 'Y',
119 'MEETING_STATUS' => 'Y',
120 ]
121 ];
122
123 $presets[self::PRESET_DECLINED] = [
124 'id' => self::PRESET_DECLINED,
125 'name' => Loc::getMessage('CALENDAR_PRESET_I_DECLINED'),
126 'default' => false,
127 'fields' => [
128 'IS_MEETING' => 'Y',
129 'MEETING_STATUS' => 'N',
130 ]
131 ];
132
133 return $presets;
134 }
135
141 public static function resolveFilterFields(string $filterId): array
142 {
143 $filterOptions = new \Bitrix\Main\UI\Filter\Options($filterId);
144 $fields = $filterOptions->getFilter();
145
146 $preset = $fields['PRESET_ID'] ?? null;
147 $meetingStatus = $fields['MEETING_STATUS'] ?? null;
148 if ($meetingStatus === 'Q')
149 {
150 $preset = self::PRESET_INVITED;
151 }
152 if ($meetingStatus === 'N')
153 {
154 $preset = self::PRESET_DECLINED;
155 }
156
157 $result = [
158 'search' => $filterOptions->getSearchString(),
159 'presetId' => $preset,
160 'fields' => []
161 ];
162 $connection = Application::getConnection();
163 $sqlHelper = $connection->getSqlHelper();
164
165 $fieldNames = self::getAvailableFields();
166 foreach ($fields as $key => $value)
167 {
168 if ($key === 'DATE_from')
169 {
170 $result['fields']['DATE_FROM'] = $value;
171 }
172 else if ($key === 'DATE_to')
173 {
174 $result['fields']['DATE_TO'] = $value;
175 }
176 else if ($key === 'ATTENDEES' || $key === 'CREATED_BY' || $key === 'SECTION_ID')
177 {
178 $valueList = [];
179 foreach ($value as $code)
180 {
181 $valueList[] = (int)$code;
182 }
183 $result['fields'][$key] = $valueList;
184 }
185 else if ($key === 'MEETING_STATUS')
186 {
187 $result['fields']['MEETING_STATUS'] = $sqlHelper->forSql($value);
188 }
189 else if (in_array($key, $fieldNames, true))
190 {
191 $result['fields'][$key] = $value;
192 }
193 }
194
195 return $result;
196 }
197
201 public static function getFilters(): array
202 {
203 if (empty(static::$filters))
204 {
205 static::$filters['CREATED_BY'] = [
206 'id' => 'CREATED_BY',
207 'name' => Loc::getMessage('CALENDAR_FILTER_CREATED_BY'),
208 'type' => 'entity_selector',
209 'partial' => true,
210 'params' => [
211 'multiple' => 'Y',
212 'dialogOptions' => [
213 'height' => 240,
214 'context' => 'filter',
215 'entities' => [
216 [
217 'id' => 'user',
218 'options' => [
219 'inviteEmployeeLink' => false
220 ],
221 ]
222 ]
223 ],
224 ],
225 ];
226
227 static::$filters['ATTENDEES'] = [
228 'id' => 'ATTENDEES',
229 'name' => Loc::getMessage('CALENDAR_FILTER_ATTENDEES'),
230 'type' => 'entity_selector',
231 'partial' => true,
232 'params' => [
233 'multiple' => 'Y',
234 'dialogOptions' => [
235 'height' => 270,
236 'context' => 'filter',
237 'entities' => [
238 [
239 'id' => 'user',
240 'options' => [
241 'inviteEmployeeLink' => false
242 ],
243 ],
244 ]
245 ],
246 ],
247 ];
248
249 static::$filters['MEETING_STATUS'] = [
250 'id' => 'MEETING_STATUS',
251 'name' => Loc::getMessage('CALENDAR_FILTER_MEETING_STATUS_ME'),
252 'type' => 'list',
253 'params' => [
254 'multiple' => 'N'
255 ],
256 'items' => [
257 'H' => Loc::getMessage('CALENDAR_FILTER_MEETING_STATUS_H'),
258 'Q' => Loc::getMessage('CALENDAR_FILTER_MEETING_STATUS_Q'),
259 'Y' => Loc::getMessage('CALENDAR_FILTER_MEETING_STATUS_Y'),
260 'N' => Loc::getMessage('CALENDAR_FILTER_MEETING_STATUS_N'),
261 ]
262 ];
263
264 static::$filters['DATE'] = [
265 'id' => 'DATE',
266 'name' => Loc::getMessage('CALENDAR_FILTER_DATE'),
267 'type' => 'date',
268 'default' => true,
269 ];
270 }
271
272 return static::$filters;
273 }
274
275 private static function getSectionsForFilter(string $type, ?string $preset, ?int $ownerId, ?int $userId): array
276 {
277 $result = [];
278
279 $sectionList = \CCalendar::getSectionList([
280 'CAL_TYPE' => $type,
281 'OWNER_ID' => $ownerId,
282 'checkPermissions' => true,
283 'getPermissions' => true,
284 ]);
285 $isPersonalCalendarContext = ($type === 'user' && $userId === $ownerId);
286
287 $hiddenSections = [];
288 if ($preset !== self::PRESET_INVITED)
289 {
290 $hiddenSections = UserSettings::getHiddenSections(
291 $userId,
292 [
293 'type' => $type,
294 'ownerId' => $ownerId,
295 'isPersonalCalendarContext' => $isPersonalCalendarContext,
296 ]
297 );
298 $hiddenSections = array_map(static function($sectionId) {
299 return (int)$sectionId;
300 }, $hiddenSections);
301 }
302
303 foreach ($sectionList as $section)
304 {
305 if (in_array((int)$section['ID'], $hiddenSections, true))
306 {
307 continue;
308 }
309
310 $result[] = (int)$section['ID'];
311 }
312
313 return $result;
314 }
315
324 public static function getFilterData(array $params): array
325 {
326 $connection = Application::getConnection();
327 $sqlHelper = $connection->getSqlHelper();
328 $userId = (int)$params['userId'];
329 $ownerId = (int)$params['ownerId'];
330 $type = $sqlHelper->forSql($params['type']);
331
333 self::getFilterId($type, $ownerId, $userId)
334 );
335 $fields['fields']['SECTION_ID'] = self::getSectionsForFilter(
336 $params['type'],
337 $fields['presetId'],
338 $params['ownerId'],
339 $params['userId'],
340 );
341
342 if (
343 $type === 'company_calendar'
344 || $type === 'calendar_company'
345 || $type === 'company'
346 || $type === 'group'
347 )
348 {
349 return self::getFilterCompanyData($type, $userId, $ownerId, $fields);
350 }
351
352 return self::getFilterUserData($type, $userId, $ownerId, $fields);
353 }
354
366 public static function getFilterUserData(string $type, int $userId, int $ownerId, $fields): array
367 {
368 $counters = false;
369 $entries = [];
370 $filter = [
371 'OWNER_ID' => $ownerId,
372 'CAL_TYPE' => $type,
373 'ACTIVE_SECTION' => 'Y',
374 ];
375
376 if (isset($fields['fields']['IS_MEETING']))
377 {
378 $filter['IS_MEETING'] = $fields['fields']['IS_MEETING'] === 'Y';
379 }
380
381 if (isset($fields['fields']['MEETING_STATUS']))
382 {
383 $filter['MEETING_STATUS'] = $fields['fields']['MEETING_STATUS'];
384 if ($filter['MEETING_STATUS'] === 'H')
385 {
386 unset($filter['MEETING_STATUS']);
387 $filter['MEETING_HOST'] = $userId;
388 }
389 else
390 {
391 $filter['IS_MEETING'] = true;
392 }
393
394 if ($fields['presetId'] === self::PRESET_INVITED)
395 {
396 $filter['FROM_LIMIT'] = \CCalendar::Date(time(), false);
397 $filter['TO_LIMIT'] = \CCalendar::Date(time() + \CCalendar::DAY_LENGTH * 90, false);
398 \CCalendar::UpdateCounter([$ownerId]);
399 $counters = CountersManager::getValues((int)$filter['OWNER_ID']);
400 }
401 }
402
403 if (isset($fields['fields']['CREATED_BY']))
404 {
405 unset($filter['OWNER_ID'], $filter['CAL_TYPE']);
406 $filter['MEETING_HOST'] = $fields['fields']['CREATED_BY'];
407 // mantis: 93743
408 $filter['CREATED_BY'] = $userId;
409 }
410
411 if (!empty($fields['fields']['SECTION_ID']))
412 {
413 $filter['SECTION'] = $fields['fields']['SECTION_ID'];
414 }
415 else
416 {
417 return [
418 'result' => true,
419 'entries' => $entries,
420 'counters' => $counters
421 ];
422 }
423
424 if (isset($fields['fields']['ATTENDEES']))
425 {
426 $query = EventTable::query()
427 ->setSelect(['ID'])
428 ->registerRuntimeField(
429 'EVENT_SECOND',
430 new ReferenceField(
431 'EVENT_SECOND',
432 EventTable::getEntity(),
433 Join::on('ref.PARENT_ID', 'this.PARENT_ID'),
434 ['join_type' => Join::TYPE_LEFT]
435 )
436 )
437 ->where('DELETED', 'N')
438 ->where('EVENT_SECOND.DELETED', 'N')
439 ->where('CAL_TYPE', $type)
440 ->where('CREATED_BY', $userId)
441 ->whereIn('EVENT_SECOND.CREATED_BY', $fields['fields']['ATTENDEES'])
442 ->exec()
443 ;
444
445 while ($event = $query->fetch())
446 {
447 $filter['ID'][] = (int)$event['ID'];
448 }
449
450 if ($filter['ID'] ?? false)
451 {
452 $filter['ID'] = array_unique($filter['ID']);
453 }
454 else
455 {
456 $filter['ID'] = [0];
457 }
458
459 $filter['IS_MEETING'] = true;
460 }
461
462 [$filter, $parseRecursion] = self::filterByDate($fields, $filter);
463
464 if (isset($fields['search']) && $fields['search'])
465 {
466 $filter[(\CCalendarEvent::isFullTextIndexEnabled() ? '*' : '*%').'SEARCHABLE_CONTENT'] = \CCalendarEvent::prepareToken(Emoji::encode($fields['search']));
467 }
468
469 $entries = \CCalendarEvent::GetList(
470 [
471 'arFilter' => $filter,
472 'fetchAttendees' => true,
473 'parseRecursion' => $parseRecursion,
474 'maxInstanceCount' => 50,
475 'preciseLimits' => $parseRecursion,
476 'userId' => $userId,
477 'fetchMeetings' => true,
478 'fetchSection' => true,
479 'setDefaultLimit' => false
480 ]
481 );
482 if ($fields['presetId'] !== self::PRESET_DECLINED)
483 {
484 $entries = self::filterByShowDeclined($entries);
485 }
486
487 return [
488 'result' => true,
489 'entries' => $entries,
490 'counters' => $counters
491 ];
492 }
493
505 private static function getFilterCompanyData(string $type, int $userId, int $ownerId, $fields): array
506 {
507 $filter = [
508 'CAL_TYPE' => $type,
509 'ACTIVE_SECTION' => 'Y',
510 ];
511 $entries = [];
512
513 $query = EventTable::query()
514 ->setSelect(['PARENT_ID'])
515 ->registerRuntimeField(
516 'EVENT_SECOND',
517 new ReferenceField(
518 'EVENT_SECOND',
519 EventTable::getEntity(),
520 Join::on('ref.PARENT_ID', 'this.ID'),
521 ['join_type' => Join::TYPE_LEFT]
522 )
523 )
524 ->where('CAL_TYPE', $type)
525 ->where('DELETED', 'N')
526 ->where('EVENT_SECOND.DELETED', 'N')
527 ;
528
529 if (isset($fields['fields']['IS_MEETING']) && $fields['fields']['IS_MEETING'])
530 {
531 $filter['IS_MEETING'] = $fields['fields']['IS_MEETING'] === 'Y';
532 }
533
534 if (isset($fields['fields']['MEETING_STATUS']) && $fields['fields']['MEETING_STATUS'])
535 {
536 $query->where('EVENT_SECOND.CREATED_BY', $userId);
537 if (
538 $fields['fields']['MEETING_STATUS'] === 'H'
539 && !isset($fields['fields']['CREATED_BY'])
540 )
541 {
542 unset($filter['IS_MEETING']);
543 $query->where('EVENT_SECOND.MEETING_HOST', $userId);
544 }
545 else
546 {
547 $query->where('EVENT_SECOND.MEETING_STATUS', $fields['fields']['MEETING_STATUS']);
548 $filter['IS_MEETING'] = true;
549 }
550 }
551
552 if (isset($fields['fields']['CREATED_BY']) && is_array($fields['fields']['CREATED_BY']))
553 {
554 $query->whereIn('EVENT_SECOND.MEETING_HOST', $fields['fields']['CREATED_BY']);
555 }
556
557 if (isset($fields['fields']['SECTION_ID']) && is_array($fields['fields']['SECTION_ID']))
558 {
559 $query->whereIn('SECTION_ID', $fields['fields']['SECTION_ID']);
560 }
561
562 if (isset($fields['fields']['ATTENDEES']) && is_array($fields['fields']['ATTENDEES']))
563 {
564 if (isset($fields['fields']['MEETING_STATUS']))
565 {
566 $query
567 ->registerRuntimeField(
568 'EVENT_THIRD',
569 new ReferenceField(
570 'EVENT_THIRD',
571 EventTable::getEntity(),
572 Join::on('ref.PARENT_ID', 'this.ID'),
573 ['join_type' => Join::TYPE_LEFT]
574 )
575 )
576 ->whereIn('EVENT_THIRD.CREATED_BY', $fields['fields']['ATTENDEES'])
577 ;
578 }
579 else
580 {
581 $query->whereIn('EVENT_SECOND.CREATED_BY', $fields['fields']['ATTENDEES']);
582 }
583 $filter['IS_MEETING'] = true;
584 }
585
586 if (isset($fields['search']) && $fields['search'])
587 {
588 $filter[(\CCalendarEvent::isFullTextIndexEnabled() ? '*' : '*%').'SEARCHABLE_CONTENT'] = \CCalendarEvent::prepareToken($fields['search']);
589 }
590
591 [$filter, $parseRecursion] = self::filterByDate($fields, $filter);
592
593 $eventsFromQuery = $query->exec();
594
595 while ($event = $eventsFromQuery->Fetch())
596 {
597 $filter['ID'][] = (int)$event['PARENT_ID'];
598 }
599
600 if (isset($filter['ID']))
601 {
602 $filter['ID'] = array_unique($filter['ID']);
603
604 $entries = \CCalendarEvent::GetList(
605 [
606 'arFilter' => $filter,
607 'fetchAttendees' => true,
608 'parseRecursion' => $parseRecursion,
609 'maxInstanceCount' => 50,
610 'preciseLimits' => $parseRecursion,
611 'userId' => $userId,
612 'fetchMeetings' => true,
613 'fetchSection' => true,
614 'setDefaultLimit' => false
615 ]
616 );
617 }
618 $entries = self::applyAccessRestrictions($entries);
619 $entries = self::filterByShowDeclined($entries);
620
621 return [
622 'result' => true,
623 'entries' => $entries,
624 'counters' => false
625 ];
626 }
627
633 private static function filterByDate($fields, array $filter): array
634 {
635 $parseRecursion = false;
636 $fromTs = 0;
637 $toTs = 0;
638 if (isset($fields['fields']['DATE_FROM']))
639 {
640 $fromTs = \CCalendar::Timestamp($fields['fields']['DATE_FROM'], true, false);
641 $filter['FROM_LIMIT'] = \CCalendar::Date($fromTs, false);
642 }
643 else if (!($filter['FROM_LIMIT'] ?? null))
644 {
645 $filter['FROM_LIMIT'] = \CCalendar::Date(time() - 31 * 12 * 24 * 3600, false);
646 }
647
648 if (isset($fields['fields']['DATE_TO']))
649 {
650 $toTs = \CCalendar::Timestamp($fields['fields']['DATE_TO'], true, false);
651 $filter['TO_LIMIT'] = \CCalendar::Date($toTs, false);
652 if ($fromTs && $toTs < $fromTs)
653 {
654 $filter['TO_LIMIT'] = $filter['FROM_LIMIT'];
655 }
656 }
657
658 if ($fromTs && $toTs && $fromTs <= $toTs)
659 {
660 $parseRecursion = true;
661 }
662
663 return [
664 $filter,
665 $parseRecursion
666 ];
667 }
668
673 private static function applyAccessRestrictions(array $events): array
674 {
675 foreach ($events as $i => $event)
676 {
677 if (
678 isset($event['IS_ACCESSIBLE_TO_USER'])
679 && $event['IS_ACCESSIBLE_TO_USER'] === false
680 )
681 {
682 unset($events[$i]);
683 }
684 }
685
686 return array_values($events);
687 }
688
689 public static function filterByShowDeclined(array $entries): array
690 {
691 $settings = UserSettings::get();
692 $optionShowDeclined = $settings['showDeclined'];
693
694 return array_values(array_filter($entries, static function($entry) use ($optionShowDeclined) {
695 $hideDeclinedEntry = (!$optionShowDeclined || (int)$entry['CREATED_BY'] !== \CCalendar::GetUserId());
696 return !($hideDeclinedEntry && $entry['MEETING_STATUS'] === 'N');
697 }));
698 }
699}
static getFilterData(array $params)
static getFilterId($type, $ownerId, $userId)
static getFilterUserData(string $type, int $userId, int $ownerId, $fields)
static filterByShowDeclined(array $entries)
static resolveFilterFields(string $filterId)
static get($userId=null)
static getHiddenSections($userId=false, $options=[])
static getConnection($name="")
static getMessage($code, $replace=null, $language=null)
Definition loc.php:29