Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
filtermanager.php
1<?php
2
4
7use Bitrix\Main\Entity\Query;
15use Bitrix\Tasks\Internals\Counter as TasksCounter;
16
18{
19 public $runtimeFieldsManager = null;
20
24 private $fieldsList;
25
29 private $gridFilter;
30 private Query $query;
31 private int $currentUserId;
32 private int $contextUserId;
33 private string $mode;
37 private array $numericFieldsList;
41 private array $integerFieldsList;
45 private array $stringFieldsList;
49 private array $booleanFieldsList;
53 private array $dateFieldsList;
54 private bool $hasAccessToTasksCounters;
55
56 public function __construct(Query $query, RuntimeFieldsManager $runtimeFieldsManager, array $params = [])
57 {
58 $this->fieldsList = ($params['fieldsList'] ?? []);
59 $this->gridFilter = ($params['gridFilter'] ?? []);
60 $this->currentUserId = (int)($params['currentUserId'] ?? 0);
61 $this->contextUserId = (int)($params['contextUserId'] ?? 0);
62 $this->mode = (string)($params['mode'] ?? '');
63 $this->query = $query;
64 $this->hasAccessToTasksCounters = (boolean)($params['hasAccessToTasksCounters'] ?? false);
65 $this->runtimeFieldsManager = $runtimeFieldsManager;
66 }
67
68 public function getFilter(): array
69 {
70 $filter = [
71 '=ACTIVE' => 'Y',
72 '=SITE.SITE_ID' => SITE_ID,
73 ];
74
75 if ($this->query === null)
76 {
77 return $filter;
78 }
79
80 if (
81 !empty($this->gridFilter['EXTRANET'])
82 && $this->gridFilter['EXTRANET'] === 'Y'
84 )
85 {
86 $this->query->registerRuntimeField(
87 new Reference(
88 'SITE_EXTRANET',
89 WorkgroupSiteTable::class,
90 Join::on('this.ID', 'ref.GROUP_ID')->where('ref.SITE_ID', static::getExtranetSiteId()),
91 ['join_type' => 'INNER']
92 )
93 );
94 }
95
96 if (
97 !empty($this->gridFilter['FAVORITES'])
98 && $this->gridFilter['FAVORITES'] === 'Y'
99 && $this->currentUserId > 0
100 )
101 {
102 $filter['=FAVORITES.USER_ID'] = $this->currentUserId;
103 }
104
105 if ($this->runtimeFieldsManager->has('SCRUM'))
106 {
107 if ($this->mode === WorkgroupList::MODE_TASKS_SCRUM)
108 {
109 $filter['=PROJECT'] = 'Y';
110 $filter['=SCRUM'] = 'Y';
111 }
112 elseif ($this->mode === WorkgroupList::MODE_TASKS_PROJECT)
113 {
114 $filter['=SCRUM'] = 'N';
115 }
116 }
117
118 $this->initFilterFieldsData();
119
120 $filter = $this->processNumericFields($filter);
121 $filter = $this->processIntegerFields($filter);
122 $filter = $this->processStringFields($filter);
123 $filter = $this->processBooleanFields($filter);
124 $filter = $this->processDateFields($filter);
125 $filter = $this->processFind($filter);
126
127 if ($this->hasAccessToTasksCounters)
128 {
129 $filter = $this->processTasksCounterFilter($filter);
130 }
131 else
132 {
133 $filter = $this->processCommonCounterFilter($filter);
134 }
135
136 $filter = $this->processProjectDateFilter($filter);
137
138 return $filter;
139 }
140
141 private function initFilterFieldsData(): void
142 {
143 $this->numericFieldsList = [
144 [
145 'FILTER_FIELD_NAME' => 'ID',
146 'FIELD_NAME' => 'ID',
147 'VALUE_FROM' => ($this->gridFilter['ID_from'] ?? false),
148 'VALUE_TO' => ($this->gridFilter['ID_to'] ?? false)
149 ],
150 ];
151
152 $this->integerFieldsList = [
153 [
154 'FILTER_FIELD_NAME' => 'OWNER',
155 'FIELD_NAME' => 'OWNER_ID',
156 'OPERATION' => '=',
157 'VALUE' => preg_replace('/^U(\d+)$/', '$1', ($this->gridFilter['OWNER'] ?? '')),
158 ],
159 [
160 'FILTER_FIELD_NAME' => 'MEMBER',
161 'FIELD_NAME' => 'MEMBER_ID',
162 'OPERATION' => '=',
163 'VALUE' => preg_replace('/^U(\d+)$/', '$1', ($this->gridFilter['MEMBER'] ?? '')),
164 ],
165 ];
166
167 $this->stringFieldsList = [
168 [
169 'FILTER_FIELD_NAME' => 'NAME',
170 'FIELD_NAME' => 'NAME',
171 'OPERATION' => '%=',
172 'VALUE' => ($this->gridFilter['NAME'] ?? '') . '%',
173 ],
174 [
175 'FILTER_FIELD_NAME' => 'TAG',
176 'FIELD_NAME' => 'TAG',
177 'OPERATION' => '%=',
178 'VALUE' => ($this->gridFilter['TAG'] ?? '') . '%',
179 ],
180 ];
181
182 $this->booleanFieldsList = [
183 [
184 'FILTER_FIELD_NAME' => 'CLOSED',
185 'FIELD_NAME' => 'CLOSED',
186 'OPERATION' => '=',
187 'VALUE' => ($this->gridFilter['CLOSED'] ?? ''),
188 ],
189 [
190 'FILTER_FIELD_NAME' => 'VISIBLE',
191 'FIELD_NAME' => 'VISIBLE',
192 'OPERATION' => '=',
193 'VALUE' => ($this->gridFilter['VISIBLE'] ?? ''),
194 ],
195 [
196 'FILTER_FIELD_NAME' => 'OPENED',
197 'FIELD_NAME' => 'OPENED',
198 'OPERATION' => '=',
199 'VALUE' => ($this->gridFilter['OPENED'] ?? ''),
200 ],
201 [
202 'FILTER_FIELD_NAME' => 'PROJECT',
203 'FIELD_NAME' => 'PROJECT',
204 'OPERATION' => '=',
205 'VALUE' => ($this->gridFilter['PROJECT'] ?? ''),
206 ],
207 [
208 'FILTER_FIELD_NAME' => 'SCRUM',
209 'FIELD_NAME' => 'SCRUM',
210 'OPERATION' => '=',
211 'VALUE' => ($this->gridFilter['SCRUM'] ?? ''),
212 ],
213 [
214 'FILTER_FIELD_NAME' => 'LANDING',
215 'FIELD_NAME' => 'LANDING',
216 'OPERATION' => '=',
217 'VALUE' => ($this->gridFilter['LANDING'] ?? ''),
218 ],
219 ];
220
221 $this->dateFieldsList = [
222 [
223 'FILTER_FIELD_NAME' => 'PROJECT_DATE_START',
224 'FIELD_NAME' => 'PROJECT_DATE_START',
225 'VALUE_FROM' => ($this->gridFilter['PROJECT_DATE_START_from'] ?? false),
226 'VALUE_TO' => ($this->gridFilter['PROJECT_DATE_START_to'] ?? false)
227 ],
228 [
229 'FILTER_FIELD_NAME' => 'PROJECT_DATE_FINISH',
230 'FIELD_NAME' => 'PROJECT_DATE_FINISH',
231 'VALUE_FROM' => ($this->gridFilter['PROJECT_DATE_FINISH_from'] ?? false),
232 'VALUE_TO' => ($this->gridFilter['PROJECT_DATE_FINISH_to'] ?? false)
233 ],
234 ];
235
236 }
237
238 protected function processIntegerFields($filter): array
239 {
240 foreach ($this->integerFieldsList as $field)
241 {
242 $value = false;
243
244 if (
245 is_array($field['VALUE'])
246 && !empty($field['VALUE'])
247 )
248 {
249 $value = $field['VALUE'];
250 }
251 elseif (
252 !is_array($field['VALUE'])
253 && (string)$field['VALUE'] !== ''
254 )
255 {
256 $value = (int)$field['VALUE'];
257 }
258
259 if ($value !== false)
260 {
261 $filter = $this->addFilterInteger($filter, [
262 'FILTER_FIELD_NAME' => $field['FILTER_FIELD_NAME'],
263 'FIELD_NAME' => $field['FIELD_NAME'],
264 'OPERATION' => ($field['OPERATION'] ?? '='),
265 'VALUE' => $value,
266 ]);
267 }
268 }
269
270 return $filter;
271 }
272
273 protected function processNumericFields($filter): array
274 {
275 foreach ($this->numericFieldsList as $field)
276 {
277 if (
278 empty($field['VALUE_FROM'])
279 && empty($field['VALUE_TO'])
280 )
281 {
282 return $filter;
283 }
284
285 if (
286 !empty($field['VALUE_FROM'])
287 && !empty($field['VALUE_TO'])
288 && $field['VALUE_FROM'] === $field['VALUE_TO'])
289 {
290 $filter['=' . $field['FIELD_NAME']] = $field['VALUE_FROM'];
291 }
292 else
293 {
294 if (!empty($field['VALUE_FROM']))
295 {
296 $filter['>=' . $field['FIELD_NAME']] = $field['VALUE_FROM'];
297 }
298
299 if (!empty($field['VALUE_TO']))
300 {
301 $filter['<=' . $field['FIELD_NAME']] = $field['VALUE_TO'];
302 }
303 }
304 }
305
306 return $filter;
307 }
308
309 protected function processStringFields(array $filter): array
310 {
311 foreach ($this->stringFieldsList as $field)
312 {
313 if ($field['VALUE'] !== '')
314 {
315 $filter = $this->addFilterString($filter, [
316 'FILTER_FIELD_NAME' => $field['FILTER_FIELD_NAME'],
317 'FIELD_NAME' => $field['FIELD_NAME'],
318 'OPERATION' => ($field['OPERATION'] ?? '%='),
319 'VALUE' => $field['VALUE'],
320 ]);
321 }
322 }
323
324 return $filter;
325 }
326
327 protected function processBooleanFields(array $filter): array
328 {
329 foreach ($this->booleanFieldsList as $field)
330 {
331 if (in_array($field['VALUE'], ['Y', 'N'], true))
332 {
333 $filter = $this->addFilterString($filter, [
334 'FILTER_FIELD_NAME' => $field['FILTER_FIELD_NAME'],
335 'FIELD_NAME' => $field['FIELD_NAME'],
336 'OPERATION' => '=',
337 'VALUE' => $field['VALUE'],
338 ]);
339 }
340 }
341
342 return $filter;
343 }
344
345 protected function processDateFields(array $filter): array
346 {
347 foreach ($this->dateFieldsList as $field)
348 {
349 if (
350 !empty($field['VALUE_FROM'])
351 || !empty($field['VALUE_TO'])
352 )
353 {
354 $filter = $this->addFilterDateTime($filter, [
355 'FILTER_FIELD_NAME' => $field['FILTER_FIELD_NAME'],
356 'FIELD_NAME' => $field['FIELD_NAME'],
357 'VALUE_FROM' => ($field['VALUE_FROM'] ?? $this->gridFilter[$field['FILTER_FIELD_NAME']]),
358 'VALUE_TO' => ($field['VALUE_TO'] ?? $this->gridFilter[$field['FILTER_FIELD_NAME']]),
359 ]);
360 }
361 }
362
363 return $filter;
364 }
365
366 protected function processFind(array $filter): array
367 {
368
369 if (
370 isset($this->gridFilter['FIND'])
371 && $this->gridFilter['FIND']
372 )
373 {
374 $findFilter = $this->getFindFilter($this->gridFilter['FIND']);
375 if (!empty($findFilter))
376 {
377 $filter = array_merge($filter, $findFilter);
378 }
379 }
380
381 return $filter;
382 }
383
384 protected function processTasksCounterFilter(array $filter, string $gridFilterField = 'COUNTERS'): array
385 {
386 if (
387 !in_array($gridFilterField, [ 'COUNTERS', 'COMMON_COUNTERS' ], true)
388 || empty($this->gridFilter[$gridFilterField])
389 || !Loader::includeModule('tasks')
390 )
391 {
392 return $filter;
393 }
394
395 $this->query->setDistinct(true);
396
397 $this->query->registerRuntimeField(
398 new Reference(
399 'TASKS_COUNTER',
400 TasksCounter\CounterTable::class,
401 Join::on('this.ID', 'ref.GROUP_ID')->where('ref.USER_ID', $this->contextUserId),
402 ['join_type' => 'INNER']
403 )
404 );
405 $this->runtimeFieldsManager->add('TASKS_COUNTER');
406
407 if ($gridFilterField === 'COUNTERS')
408 {
409 $typesMap = [
410 'EXPIRED' => [
411 'INCLUDE' => TasksCounter\CounterDictionary::MAP_EXPIRED,
412 'EXCLUDE' => null,
413 ],
414 'NEW_COMMENTS' => [
415 'INCLUDE' => TasksCounter\CounterDictionary::MAP_COMMENTS,
416 'EXCLUDE' => null,
417 ],
418 'PROJECT_EXPIRED' => [
419 'INCLUDE' => array_merge(
420 [ TasksCounter\CounterDictionary::COUNTER_GROUP_EXPIRED ],
421 TasksCounter\CounterDictionary::MAP_MUTED_EXPIRED,
422 ),
423 'EXCLUDE' => TasksCounter\CounterDictionary::MAP_EXPIRED,
424 ],
425 'PROJECT_NEW_COMMENTS' => [
426 'INCLUDE' => array_merge(
427 [ TasksCounter\CounterDictionary::COUNTER_GROUP_COMMENTS ],
428 TasksCounter\CounterDictionary::MAP_MUTED_COMMENTS,
429 ),
430 'EXCLUDE' => TasksCounter\CounterDictionary::MAP_COMMENTS,
431 ],
432 ];
433 $type = $typesMap[$this->gridFilter[$gridFilterField]];
434 }
435 elseif ($gridFilterField === 'COMMON_COUNTERS')
436 {
437 $type = [
438 'INCLUDE' => array_merge(
439 array_values(TasksCounter\CounterDictionary::MAP_EXPIRED),
440 array_values(TasksCounter\CounterDictionary::MAP_COMMENTS),
441 ),
442 'EXCLUDE' => null,
443 ];
444 }
445
446 $filter['INCLUDED_COUNTER'] = $type['INCLUDE'];
447
448 if ($type['EXCLUDE'])
449 {
450 $this->query->registerRuntimeField(
451 'EXCLUDED_COUNTER_EXISTS',
452 new ExpressionField(
453 'EXCLUDED_COUNTER_EXISTS',
454 "(
455 SELECT 1
456 FROM b_tasks_scorer
457 WHERE
458 GROUP_ID = %s
459 AND TASK_ID = %s
460 AND USER_ID = " . $this->contextUserId . "
461 AND TYPE IN ('" . implode("','", $type['EXCLUDE']) . "')
462 LIMIT 1
463 )",
464 [ 'ID', 'TASKS_COUNTER.TASK_ID' ]
465 )
466 );
467 $this->runtimeFieldsManager->add('EXCLUDED_COUNTER_EXISTS');
468 }
469
470 return $filter;
471 }
472
473 protected function processCommonCounterFilter(array $filter): array
474 {
475 if (empty($this->gridFilter['COMMON_COUNTERS']))
476 {
477 return $filter;
478 }
479
480 if ($this->gridFilter['COMMON_COUNTERS'] === CounterFilter::VALUE_LIVEFEED)
481 {
482 // todo oh
483 }
484 elseif ($this->gridFilter['COMMON_COUNTERS'] === CounterFilter::VALUE_TASKS)
485 {
486 $filter = $this->processTasksCounterFilter($filter, 'COMMON_COUNTERS');
487 }
488
489 return $filter;
490 }
491
492 protected function processProjectDateFilter(array $filter): array
493 {
494 if (
495 empty($this->gridFilter['PROJECT_DATE_from'])
496 && empty($this->gridFilter['PROJECT_DATE_to'])
497 )
498 {
499 return $filter;
500 }
501
502 if (!empty($this->gridFilter['PROJECT_DATE_from']))
503 {
504 $filter['>=PROJECT_DATE_START'] = $this->gridFilter['PROJECT_DATE_from'];
505 }
506
507 if (!empty($this->gridFilter['PROJECT_DATE_to']))
508 {
509 $filter['<=PROJECT_DATE_FINISH'] = $this->gridFilter['PROJECT_DATE_to'];
510 }
511
512 return $filter;
513 }
514
515 protected function addFilterInteger(array $filter = [], array $params = []): array
516 {
517 $filterFieldName = ($params['FILTER_FIELD_NAME'] ?? '');
518 $value = ($params['VALUE'] ?? '');
519
520 if (
521 $filterFieldName === ''
522 || (int)$value <= 0
523 )
524 {
525 return $filter;
526 }
527
528 $fieldName = (
529 isset($params['FIELD_NAME'])
530 && $params['FIELD_NAME'] !== ''
531 ? $params['FIELD_NAME']
532 : $filterFieldName
533 );
534 $operation = ($params['OPERATION'] ?? '=');
535
536 if (in_array($fieldName, $this->fieldsList, true))
537 {
538 $filter[$operation . $fieldName] = $value;
539 }
540
541 return $filter;
542 }
543
544 protected function addFilterString(array $filter = [], array $params = []): array
545 {
546 $filterFieldName = ($params['FILTER_FIELD_NAME'] ?? '');
547 $value = ($params['VALUE'] ?? '');
548
549 if ($filterFieldName === '')
550 {
551 return $filter;
552 }
553 if (
554 !is_array($value)
555 && trim($value, '%') === ''
556 )
557 {
558 return $filter;
559 }
560
561 if (
562 is_array($value)
563 && empty(array_filter($value, static function ($item) {
564 return trim($item, '%') !== '';
565 }))
566 )
567 {
568 return $filter;
569 }
570
571 $fieldName = (
572 isset($params['FIELD_NAME'])
573 && $params['FIELD_NAME'] !== ''
574 ? $params['FIELD_NAME']
575 : $filterFieldName
576 );
577 $operation = ($params['OPERATION'] ?? '%=');
578
579 if (in_array($fieldName, $this->fieldsList, true))
580 {
581 $filter[$operation . $fieldName] = $value;
582 }
583
584 return $filter;
585 }
586
587 protected function addFilterDateTime(array $filter = [], array $params = []): array
588 {
589 $filterFieldName = ($params['FILTER_FIELD_NAME'] ?? '');
590 $valueFrom = ($params['VALUE_FROM'] ?? '');
591 $valueTo = ($params['VALUE_TO'] ?? '');
592
593 if (
594 $filterFieldName === ''
595 || (
596 $valueFrom === ''
597 && $valueTo === ''
598 )
599 )
600 {
601 return $filter;
602 }
603
604 $fieldName = (
605 isset($params['FIELD_NAME'])
606 && $params['FIELD_NAME'] !== ''
607 ? $params['FIELD_NAME']
608 : $filterFieldName
609 );
610
611 if (in_array($fieldName, $this->fieldsList, true))
612 {
613 if ($valueFrom !== '')
614 {
615 $filter['>=' . $fieldName] = $valueFrom;
616 }
617 if ($valueTo !== '')
618 {
619 $filter['<=' . $fieldName] = $valueTo;
620 }
621 }
622
623 return $filter;
624 }
625
630 protected function getFindFilter(string $value): array
631 {
632 $result = [];
633
634 $value = trim($value);
635
636 $value = (
637 Search\Content::isIntegerToken($value)
638 ? Search\Content::prepareIntegerToken($value)
639 : Search\Content::prepareStringToken($value)
640 );
641
642 if (Search\Content::canUseFulltextSearch($value, Search\Content::TYPE_MIXED))
643 {
644 $result['*SEARCH_INDEX'] = $value;
645 }
646
647 return $result;
648 }
649
650 private static function getExtranetSiteId(): string
651 {
652 static $result = null;
653
654 if ($result === null)
655 {
656 $result = (
657 Loader::includeModule('extranet')
658 ? \CExtranet::getExtranetSiteId()
659 : ''
660 );
661 }
662
663 return $result;
664 }
665}
static canUseFulltextSearch($token, $type=self::TYPE_STRING)
Definition content.php:50
__construct(Query $query, RuntimeFieldsManager $runtimeFieldsManager, array $params=[])
processTasksCounterFilter(array $filter, string $gridFilterField='COUNTERS')