Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
entity.php
1<?php
3
8
9abstract class Entity extends \CBitrixComponent implements Main\Engine\Contract\Controllerable, Main\Errorable
10{
12 const RESULT_ACTION_TYPE_EVENT = 'event';
13 const RESULT_ACTION_TYPE_CALLBACK = 'callback';
15 const RESULT_ACTION_TYPE_SLIDER = 'slider';
16
17 const RESULT_DATA_TYPE_NONE = 'none';
18 const RESULT_DATA_TYPE_SET = 'set';
19 const RESULT_DATA_TYPE_FILTER = 'filter';
20
21 const MODE_PAGE = 'page';
22 const MODE_DIALOG = 'dialog';
23 const MODE_SLIDER = 'slider';
24
25 const STORAGE_GRID = 'GRID';
26 const STORAGE_GRID_FILTER = 'GRID_FILTER';
27 const STORAGE_ENTITY_IBLOCK = 'IBLOCK_SETTINGS';
28
29 protected $useMode = self::MODE_PAGE;
30
32 protected $errorCollection = null;
33
35 protected $gridConfig = null;
36
37 protected $storage = [];
38
39 protected $defaultSettings = [];
40
41 protected $rows = [];
42
44 protected $navigation = null;
45
46 protected $navigationString = '';
47
48 protected $implicitPageNavigation = false;
49
51 protected $useGridFilter = true;
52
54 protected $gridFilterConfig = null;
55
56 protected $resultAction = [
57 'TYPE' => self::RESULT_ACTION_TYPE_NONE,
58 'NAME' => '',
59 'DATA_TYPE' => self::RESULT_DATA_TYPE_NONE,
60 'DATA_SET' => []
61 ];
62
63 protected $resultActionMap = [
64 self::MODE_PAGE => [
65 self::RESULT_ACTION_TYPE_EVENT,
66 self::RESULT_ACTION_TYPE_CALLBACK,
67 self::RESULT_ACTION_TYPE_CLASS_METHOD
68 ],
69 self::MODE_DIALOG => [
70 self::RESULT_ACTION_TYPE_EVENT,
71 self::RESULT_ACTION_TYPE_CALLBACK,
72 self::RESULT_ACTION_TYPE_CLASS_METHOD
73 ],
74 self::MODE_SLIDER => [
75 self::RESULT_ACTION_TYPE_EVENT,
76 self::RESULT_ACTION_TYPE_CALLBACK,
77 self::RESULT_ACTION_TYPE_CLASS_METHOD,
78 self::RESULT_ACTION_TYPE_SLIDER
79 ]
80 ];
81
86 public function __construct($component = null)
87 {
88 parent::__construct($component);
89 $this->errorCollection = new Main\ErrorCollection();
90 }
91
95 public function onIncludeComponentLang()
96 {
97 Loc::loadMessages(__FILE__);
98 }
99
104 public function onPrepareComponentParams($params)
105 {
106 if (!is_array($params))
107 {
108 $params = [];
109 }
110
111 $this->prepareNodeIds($params);
112
113 $params['MULTIPLE_SELECT'] = (isset($params['MULTIPLE_SELECT']) && $params['MULTIPLE_SELECT'] === 'Y');
114
115 $params['BASE_LINK'] = (isset($params['BASE_LINK']) ? $params['BASE_LINK'] : '');
116
117 $params['IBLOCK_ID'] = (isset($params['IBLOCK_ID']) ? (int)$params['IBLOCK_ID'] : 0);
118 if ($params['IBLOCK_ID'] < 0)
119 $params['IBLOCK_ID'] = 0;
120
121 $params['USE_MODE'] = (isset($params['USE_MODE']) && is_string($params['USE_MODE'])
122 ? trim($params['USE_MODE'])
123 : self::MODE_PAGE
124 );
125
126 $params['RESULT_ACTION_TYPE'] = (isset($params['RESULT_ACTION_TYPE']) && is_string($params['RESULT_ACTION_TYPE'])
127 ? trim($params['RESULT_ACTION_TYPE'])
128 : self::RESULT_ACTION_TYPE_NONE
129 );
130
131 if (!isset($params['RESULT_ACTION_NAME']))
132 $params['RESULT_ACTION_NAME'] = '';
133 if (!is_string($params['RESULT_ACTION_NAME']) && !is_array($params['RESULT_ACTION_NAME']))
134 $params['RESULT_ACTION_NAME'] = '';
135 $params['RESULT_ACTION_NAME'] = preg_replace('/[^a-zA-Z0-9]/', '', $params['RESULT_ACTION_NAME']);
136 if (empty($params['RESULT_ACTION_NAME']))
137 $params['RESULT_ACTION_TYPE'] = self::RESULT_ACTION_TYPE_NONE;
138
139 $params['RESULT_DATA_TYPE'] = (isset($params['RESULT_DATA_TYPE']) && is_string($params['RESULT_DATA_TYPE'])
140 ? $params['RESULT_DATA_TYPE']
141 : self::RESULT_DATA_TYPE_NONE
142 );
143 if ($params['RESULT_DATA_TYPE'] == self::RESULT_DATA_TYPE_SET)
144 $params['MULTIPLE_SELECT'] = false;
145
146 $params['RESULT_DATA_SET_LIST'] = (isset($params['RESULT_DATA_SET_LIST']) && is_array($params['RESULT_DATA_SET_LIST'])
147 ? $params['RESULT_DATA_SET_LIST']
148 : []
149 );
150
151 $params['PAGETITLE_FILTER'] = (isset($params['PAGETITLE_FILTER']) && $params['PAGETITLE_FILTER'] === 'Y' ? 'Y' : 'N');
152
153 return $params;
154 }
155
159 public function executeComponent()
160 {
161 $this->checkModules();
162 $this->prepareRequest();
163 $this->initDefaultSettings();
164 $this->initSettings();
165 $this->prepareResult();
166 $this->includeComponentTemplate();
167 }
168
172 public function configureActions()
173 {
174 return [];
175 }
176
181 public function getErrorByCode($code)
182 {
183 return $this->errorCollection->getErrorByCode($code);
184 }
185
189 public function getErrors()
190 {
191 return $this->errorCollection->toArray();
192 }
193
198 protected function prepareNodeIds(array &$params): void
199 {
200 static::validateListParameters(
201 $params,
202 [
203 'GRID_ID',
204 'FILTER_ID',
205 'NAVIGATION_ID'
206 ]
207 );
208
209 if (!empty($params['GRID_ID']))
210 {
211 if (empty($params['FILTER_ID']))
212 {
213 $params['FILTER_ID'] = static::createFilterId($params['GRID_ID']);
214 }
215 if (empty($params['NAVIGATION_ID']))
216 {
217 $params['NAVIGATION_ID'] = static::createNavigationId($params['GRID_ID']);
218 }
219 }
220 }
221
225 protected function useImplicitPageNavigation()
226 {
227 $this->implicitPageNavigation = true;
228 }
229
233 protected function isUsedImplicitPageNavigation()
234 {
235 return $this->implicitPageNavigation;
236 }
237
241 protected function disableGridFilter()
242 {
243 $this->useGridFilter = false;
244 }
245
249 protected function isUsedGridFilter()
250 {
251 return $this->useGridFilter;
252 }
253
258 protected function setUseMode($mode)
259 {
260 if (!isset($this->resultActionMap[$mode]))
261 return;
262 $this->useMode = $mode;
263 }
264
268 protected function getUseMode()
269 {
270 return $this->useMode;
271 }
272
276 protected function isPageMode()
277 {
278 return ($this->useMode == self::MODE_PAGE);
279 }
280
284 protected function isDialogWindowMode()
285 {
286 return ($this->useMode == self::MODE_DIALOG);
287 }
288
292 protected function isSliderMode()
293 {
294 return ($this->useMode == self::MODE_SLIDER);
295 }
296
300 protected function initResultDescription()
301 {
302 $mode = $this->getUseMode();
303 $resultAction = $this->arParams['RESULT_ACTION_TYPE'];
304 if (!in_array($resultAction, $this->resultActionMap[$mode]))
305 $resultAction = self::RESULT_ACTION_TYPE_NONE;
306 $dataType = $this->arParams['RESULT_DATA_TYPE'];
307 if (
308 $dataType != self::RESULT_DATA_TYPE_SET
309 && $dataType != self::RESULT_DATA_TYPE_FILTER
310 )
311 $dataType = self::RESULT_DATA_TYPE_NONE;
312 switch ($dataType)
313 {
314 case self::RESULT_DATA_TYPE_SET:
315 if (empty($this->arParams['RESULT_DATA_SET_LIST']))
316 {
317 $dataType = self::RESULT_DATA_TYPE_NONE;
318 }
319 break;
320 case self::RESULT_DATA_TYPE_FILTER:
321 if (!$this->isUsedGridFilter())
322 {
323 $dataType = self::RESULT_DATA_TYPE_NONE;
324 }
325 break;
326 }
327
328 $this->resultAction['TYPE'] = $resultAction;
329 $this->resultAction['NAME'] = $this->arParams['RESULT_ACTION_NAME'];
330 $this->resultAction['DATA_TYPE'] = $dataType;
331 if ($dataType == self::RESULT_DATA_TYPE_SET)
332 $this->resultAction['DATA_SET'] = $this->arParams['RESULT_DATA_SET_LIST'];
333 }
334
338 protected function isUsedSliderFilter()
339 {
340 return (
341 $this->isSliderMode()
342 && $this->resultAction['TYPE'] == self::RESULT_ACTION_TYPE_SLIDER
343 && $this->resultAction['DATA_TYPE'] == self::RESULT_DATA_TYPE_FILTER
344 );
345 }
346
350 protected function initEntitySettings()
351 {
352 $description = [
353 'IBLOCK_ID' => null,
354 'IBLOCK_NAME' => null,
355 'IBLOCK_TYPE_ID' => null,
356 'IBLOCK_SECTIONS' => 'N',
357 'IBLOCK_SECTIONS_NAME' => null,
358 'IBLOCK_ELEMENTS_NAME' => null,
359 'SHOW_XML_ID' => (string)Main\Config\Option::get('iblock', 'show_xml_id') === 'Y',
360 'FILTER_ALL' => Loc::getMessage('ENTITY_SELECTOR_SLIDER_FILTER_EMPTY')
361 ];
362 if ($this->arParams['IBLOCK_ID'] > 0)
363 {
364 $iterator = Iblock\IblockTable::getList([
365 'select' => ['ID', 'IBLOCK_TYPE_ID', 'NAME'],
366 'filter' => ['=ID' => $this->arParams['IBLOCK_ID'], '=ACTIVE' => 'Y']
367 ]);
368 $iblock = $iterator->fetch();
369 unset($iterator);
370 if (!empty($iblock))
371 {
372 $description['IBLOCK_ID'] = $this->arParams['IBLOCK_ID'];
373 $description['NAME'] = $iblock['NAME'];
374 $iterator = Iblock\TypeTable::getList([
375 'select' => ['ID', 'SECTIONS'],
376 'filter' => ['=ID' => $iblock['IBLOCK_TYPE_ID']]
377 ]);
378 $type = $iterator->fetch();
379 unset($iterator);
380 if (!empty($type))
381 {
382 $description['IBLOCK_TYPE_ID'] = $iblock['IBLOCK_TYPE_ID'];
383 $description['IBLOCK_SECTIONS'] = $type['SECTIONS'];
384
385 $iterator = Iblock\TypeLanguageTable::getList([
386 'select' => ['IBLOCK_TYPE_ID', 'SECTIONS_NAME', 'ELEMENTS_NAME'],
387 'filter' => ['=IBLOCK_TYPE_ID' => $iblock['IBLOCK_TYPE_ID'], '=LANGUAGE_ID' => LANGUAGE_ID]
388 ]);
389 $messages = $iterator->fetch();
390 unset($iterator);
391 if (!empty($messages))
392 {
393 $description['IBLOCK_SECTIONS_NAME'] = $messages['SECTIONS_NAME'];
394 $description['IBLOCK_ELEMENTS_NAME'] = $messages['ELEMENTS_NAME'];
395 }
396 unset($messages);
397 }
398 unset($type);
399 $description['FILTER_ALL'] = Loc::getMessage('ENTITY_SELECTOR_SLIDER_FILTER_ALL_ELEMENTS');
400 }
401 unset($iblock);
402 }
403 $this->fillStorageNode(self::STORAGE_ENTITY_IBLOCK, $description);
404 unset($description);
405 }
406
410 protected function checkModules() {}
411
415 protected function prepareRequest() {}
416
420 protected function initDefaultSettings()
421 {
422 $this->defaultSettings = [
423 'GRID_ID' => $this->getDefaultGridId()
424 ];
425 $this->defaultSettings['FILTER_ID'] = static::createFilterId($this->defaultSettings['GRID_ID']);
426 $this->defaultSettings['NAVIGATION_ID'] = static::createNavigationId($this->defaultSettings['GRID_ID']);
427 $this->defaultSettings['PAGE_SIZES'] = [5, 10, 20, 50, 100];
428 }
429
433 protected function getDefaultGridId()
434 {
435 return preg_replace('/[^a-zA-Z0-9_:\\[\\]]/', '', get_called_class());
436 }
437
442 protected static function createFilterId($gridId)
443 {
444 return $gridId.'_FILTER';
445 }
446
451 protected static function createNavigationId($gridId)
452 {
453 return $gridId.'_NAVIGATION';
454 }
455
459 protected function initSettings()
460 {
461 $this->setUseMode($this->arParams['USE_MODE']);
462 $this->initResultDescription();
463
464 $this->initEntitySettings();
465
466 $paramsList = [
467 self::STORAGE_GRID => [
468 'GRID_ID', 'NAVIGATION_ID', 'PAGE_SIZES'
469 ],
470 self::STORAGE_GRID_FILTER => [
471 'FILTER_ID'
472 ]
473 ];
474 foreach ($paramsList as $entity => $list)
475 {
476 foreach ($list as $param)
477 {
478 $value = (!empty($this->arParams[$param])
479 ? $this->arParams[$param]
480 : $this->defaultSettings[$param]
481 );
482 $this->setStorageItem($entity, $param, $value);
483 }
484 }
485 unset($param, $list, $entity, $paramsList);
486
487 $this->initGrid();
488 $this->initGridFilter();
489 }
490
494 protected function prepareResult()
495 {
496 $this->initClientScope();
497
498 $this->getData();
499
500 $filter = [];
501 if ($this->isUsedGridFilter())
502 {
503 $entityFilter = Main\Filter\Factory::createEntityFilter(
504 Iblock\Filter\EntityList::ELEMENT,
505 [
506 'ID' => $this->getFilterId(),
507 'IBLOCK_ID' => $this->getStorageItem(self::STORAGE_ENTITY_IBLOCK, 'IBLOCK_ID')
508 ]
509 );
510
511 $usedFields = $this->gridFilterConfig->getUsedFields();
512 if(empty($usedFields))
513 {
514 $usedFields = $entityFilter->getDefaultFieldIDs();
515 }
516
517 $filter = [
518 'FILTER_ID' => $this->getFilterId(),
519 'GRID_ID' => $this->getGridId(),
520 'FILTER' => $entityFilter->getFieldArrays($usedFields),
521 'FILTER_PRESETS' => [],
522 'DISABLE_SEARCH' => $this->getQuickSearchField() === null,
523 'ENABLE_LABEL' => true,
524 'ENABLE_LIVE_SEARCH' => true,
525 'LAZY_LOAD' => [
526 'CONTROLLER' => [
527 'getList' => 'iblock.filter.element.getlist',
528 'getField' => 'iblock.filter.element.getfield',
529 'componentName' => $this->getName(),
530 'signedParameters' => \Bitrix\Main\Component\ParameterSigner::signParameters(
531 $this->getName(),
532 [
533 'IBLOCK_ID' => $this->getStorageItem(self::STORAGE_ENTITY_IBLOCK, 'IBLOCK_ID')
534 ]
535 )
536 ]
537 ]
538 ];
539 }
540
541 $grid = [
542 'GRID_ID' => $this->getGridId(),
543 'COLUMNS' => array_values($this->getColumns()),
544
545 'NAV_OBJECT' => $this->navigation,
546 '~NAV_PARAMS' => ['SHOW_ALWAYS' => false],
547 'SHOW_ROW_CHECKBOXES' => $this->arParams['MULTIPLE_SELECT'],
548 'SHOW_GRID_SETTINGS_MENU' => true,
549 'SHOW_PAGINATION' => true,
550 'SHOW_PAGESIZE' => true,
551 'SHOW_SELECTED_COUNTER' => $this->arParams['MULTIPLE_SELECT'],
552 'SHOW_TOTAL_COUNTER' => true,
553 //'ACTION_PANEL' => $controlPanel,
554 "TOTAL_ROWS_COUNT" => $this->navigation->getRecordCount(),
555
556 'ALLOW_COLUMNS_SORT' => true,
557 'ALLOW_COLUMNS_RESIZE' => true,
558 'ALLOW_SORT' => true,
559 'AJAX_MODE' => 'Y',
560 'AJAX_OPTION_JUMP' => 'N',
561 'AJAX_OPTION_STYLE' => 'N',
562 'AJAX_OPTION_HISTORY' => 'N'
563 ];
564 if ($this->isUsedImplicitPageNavigation())
565 $grid['NAV_STRING'] = $this->navigationString;
566
567 $grid['PAGE_SIZES'] = [];
568 foreach ($this->getPageSizes() as $size)
569 {
570 $grid['PAGE_SIZES'][] = [
571 'NAME' => (string)$size,
572 'VALUE' => $size
573 ];
574 }
575 unset($size);
576
577 $grid['SORT'] = $this->getStorageItem(self::STORAGE_GRID, 'GRID_ORDER');
578 $grid['SORT_VARS'] = $this->getStorageItem(self::STORAGE_GRID, 'GRID_ORDER_VARS');
579
580 $grid['ROWS'] = $this->getGridRows();
581
582 $settings = [
583 'USE_MODE' => $this->getUseMode(),
584 'RESULT_ACTION' => $this->resultAction,
585 'FILTER' => [
586 'PAGETITLE' => $this->arParams['PAGETITLE_FILTER']
587 ]
588 ];
589
590 $this->arResult = [
591 'FILTER' => $filter,
592 'GRID' => $grid,
593 'SETTINGS' => $settings
594 ];
595 unset($grid, $filter);
596 }
597
598 /* Client library, styles, etc tools */
599
603 protected function initClientScope()
604 {
605 global $APPLICATION;
606
607 UI\Extension::load($this->getClientExtensions());
608
609 foreach ($this->getClientStyles() as $styleList)
610 {
611 $APPLICATION->SetAdditionalCSS($styleList);
612 }
613 }
614
618 protected function getClientExtensions()
619 {
620 return [];
621 }
622
626 protected function getClientStyles()
627 {
628 return [
629 '/bitrix/css/main/grid/webform-button.css'
630 ];
631 }
632
633 /* Client library, styles, etc tools finish */
634
635 /* Storage tools */
636
642 protected function fillStorageNode($node, array $nodeValues)
643 {
644 $node = (string)$node;
645 if ($node === '' || empty($nodeValues))
646 return;
647 if (!isset($this->storage[$node]))
648 $this->storage[$node] = [];
649 $this->storage[$node] = array_merge($this->storage[$node], $nodeValues);
650 }
651
656 protected function getStorageNode($node)
657 {
658 if (isset($this->storage[$node]))
659 return $this->storage[$node];
660 return null;
661 }
662
669 protected function setStorageItem($node, $item, $value)
670 {
671 $this->fillStorageNode($node, [$item => $value]);
672 }
673
679 protected function getStorageItem($node, $item)
680 {
681 if (isset($this->storage[$node][$item]))
682 return $this->storage[$node][$item];
683 return null;
684 }
685
689 protected function getShowXmlId()
690 {
691 return $this->getStorageItem(self::STORAGE_ENTITY_IBLOCK, 'SHOW_XML_ID');
692 }
693
697 protected function getGridId()
698 {
699 return $this->getStorageItem(self::STORAGE_GRID, 'GRID_ID');
700 }
701
705 protected function getFilterId()
706 {
707 return $this->getStorageItem(self::STORAGE_GRID_FILTER, 'FILTER_ID');
708 }
709
713 protected function getNavigationId()
714 {
715 return $this->getStorageItem(self::STORAGE_GRID, 'NAVIGATION_ID');
716 }
717
721 protected function getPageSizes()
722 {
723 return $this->getStorageItem(self::STORAGE_GRID, 'PAGE_SIZES');
724 }
725
726 /* Storage tools finish */
727
731 protected function initGrid()
732 {
733 $this->initGridConfig();
734 $this->initGridColumns();
735 $this->initGridPageNavigation();
736 $this->initGridOrder();
737 }
738
742 protected function initGridConfig()
743 {
744 $this->gridConfig = new Main\Grid\Options($this->getGridId());
745 }
746
750 protected function initGridColumns()
751 {
752 $visibleColumns = [];
753 $visibleColumnsMap = [];
754
755 $defaultList = true;
756 $userColumnsIndex = [];
757 $userColumns = $this->getUserGridColumnIds();
758 if (!empty($userColumns))
759 {
760 $defaultList = false;
761 $userColumnsIndex = array_fill_keys($userColumns, true);
762 }
763
764 $columns = $this->getGridColumnsDescription();
765 foreach (array_keys($columns) as $index)
766 {
767 if (
768 $defaultList
769 || isset($userColumnsIndex[$index])
770 )
771 {
772 $visibleColumnsMap[$index] = true;
773 $visibleColumns[$index] = $columns[$index];
774 }
775 }
776 unset($index);
777
778 unset($userColumns, $userColumnsIndex, $defaultList);
779
780 $this->fillStorageNode(
781 self::STORAGE_GRID,
782 [
783 'COLUMNS' => $columns,
784 'VISIBLE_COLUMNS' => $visibleColumns,
785 'VISIBLE_COLUMNS_MAP' => $visibleColumnsMap
786 ]
787 );
788
789 unset($visibleColumnsMap, $visibleColumns, $columns);
790 }
791
795 protected function initGridPageNavigation()
796 {
797 $naviParams = $this->getGridNavigationParams();
798 $this->navigation = new UI\PageNavigation($this->getNavigationId());
799 $this->navigation->setPageSizes($this->getPageSizes());
800 $this->navigation->allowAllRecords(false);
801 $this->navigation->setPageSize($naviParams['nPageSize']);
802 if (!$this->isUsedImplicitPageNavigation())
803 $this->navigation->initFromUri();
804 unset($naviParams);
805 }
806
810 protected function getGridNavigationParams()
811 {
812 return $this->gridConfig->getNavParams(['nPageSize' => 20]);
813 }
814
818 protected function getGridFilterDefinition() //TODO: remove this method
819 {
820 $result = [];
821 $result['NAME'] = [
822 'id' => 'NAME',
823 'type' => 'string',
824 'name' => Loc::getMessage('ENTITY_SELECTOR_FILTER_FIELD_NAME'),
825 'quickSearch' => true,
826 'operators' => [
827 'default' => '%',
828 'quickSearch' => '?'
829 ],
830 'default' => true
831 ];
832 $result['ID'] = [
833 'id' => 'ID',
834 'name' => Loc::getMessage('ENTITY_SELECTOR_FILTER_FIELD_ID'),
835 'type' => 'number',
836 'operators' => [
837 'default' => '=',
838 'exact' => '=',
839 'range' => '><',
840 'more' => '>',
841 'less' => '<'
842 ],
843 'default' => true
844 ];
845 $result['ACTIVE'] = [
846 'id' => 'ACTIVE',
847 'name' => Loc::getMessage('ENTITY_SELECTOR_FILTER_FIELD_ACTIVE'),
848 'type' => 'list',
849 'items' => $this->getBinaryDictionary(),
850 'operators' => [
851 'default' => '=',
852 'exact' => '='
853 ],
854 'default' => false
855 ];
856 if ($this->getShowXmlId())
857 {
858 $result['XML_ID'] = [
859 'id' => 'XML_ID',
860 'name' => Loc::getMessage('ENTITY_SELECTOR_FILTER_FIELD_XML_ID_MSGVER_1'),
861 'type' => 'string',
862 'operators' => [
863 'default' => '='
864 ],
865 'default' => false
866 ];
867 }
868 $result['CODE'] = [
869 'id' => 'CODE',
870 'name' => Loc::getMessage('ENTITY_SELECTOR_FILTER_FIELD_CODE'),
871 'type' => 'string',
872 'operators' => [
873 'default' => '='
874 ],
875 'default' => false
876 ];
877
878 return $result;
879 }
880
884 protected function getQuickSearchField()
885 {
886 return $this->getStorageItem(self::STORAGE_GRID_FILTER, 'QUICK_SEARCH_FIELD');
887 }
888
892 protected function getQuickSearchDescription()
893 {
894 return $this->getStorageItem(self::STORAGE_GRID_FILTER, 'QUICK_SEARCH_DESCRIPTION');
895 }
896
900 protected function getGridColumnsDescription()
901 {
902 $result = [];
903
904 $result['ID'] = [
905 'id' => 'ID',
906 'name' => 'ID',
907 'sort' => 'ID',
908 'default' => true
909 ];
910 $result['NAME'] = [
911 'id' => 'NAME',
912 'name' => Loc::getMessage('ENTITY_SELECTOR_GRID_COLUMN_NAME'),
913 'sort' => 'NAME',
914 'default' => true
915 ];
916 $result['ACTIVE'] = [
917 'id' => 'ACTIVE',
918 'name' => Loc::getMessage('ENTITY_SELECTOR_GRID_COLUMN_ACTIVE'),
919 'title' => Loc::getMessage('ENTITY_SELECTOR_GRID_COLUMN_TITLE_ACTIVE'),
920 'sort' => 'ACTIVE',
921 'default' => true
922 ];
923 if ($this->getShowXmlId())
924 {
925 $result['XML_ID'] = [
926 'id' => 'XML_ID',
927 'name' => Loc::getMessage('ENTITY_SELECTOR_GRID_COLUMN_XML_ID_MSGVER_1'),
928 'sort' => 'XML_ID',
929 'default' => false
930 ];
931 }
932 $result['CODE'] = [
933 'id' => 'CODE',
934 'name' => Loc::getMessage('ENTITY_SELECTOR_GRID_COLUMN_CODE'),
935 'sort' => 'CODE',
936 'default' => false
937 ];
938 $result['SORT'] = [
939 'id' => 'SORT',
940 'name' => Loc::getMessage('ENTITY_SELECTOR_GRID_COLUMN_SORT'),
941 'title' => Loc::getMessage('ENTITY_SELECTOR_GRID_COLUMN_TITLE_SORT'),
942 'sort' => 'SORT',
943 'default' => false
944 ];
945
946 return $result;
947 }
948
952 protected function getUserGridColumnIds()
953 {
954 $result = $this->gridConfig->GetVisibleColumns();
955 if (empty($result))
956 {
957 $oldOptions = \CUserOptions::GetOption('list', $this->getGridId(), []);
958 if (!empty($oldOptions['columns']))
959 {
960 $oldGridColumns = [];
961 $rawColumns = explode(',', $oldOptions['columns']);
962 foreach ($rawColumns as $id)
963 {
964 $id = trim($id);
965 if ($id !== '')
966 $oldGridColumns[] = $id;
967 }
968 unset($id, $rawColumns);
969 if (!empty($oldGridColumns))
970 $result = $oldGridColumns;
971 unset($oldGridColumns);
972 }
973 unset($oldOptions);
974
975 if (!empty($result))
976 $this->gridConfig->SetVisibleColumns($result);
977 }
978 if (!empty($result) && !in_array('ID', $result))
979 array_unshift($result, 'ID');
980 return $result;
981 }
982
986 protected function getColumns()
987 {
988 return $this->getStorageItem(self::STORAGE_GRID, 'COLUMNS');
989 }
990
994 protected function getVisibleColumns()
995 {
996 return $this->getStorageItem(self::STORAGE_GRID, 'VISIBLE_COLUMNS');
997 }
998
1002 protected function initGridOrder()
1003 {
1004 $result = ['ID' => 'DESC'];
1005
1006 $sorting = $this->gridConfig->getSorting(['sort' => $result]);
1007
1008 $order = mb_strtolower(reset($sorting['sort']));
1009 if ($order !== 'asc')
1010 $order = 'desc';
1011 $field = key($sorting['sort']);
1012 $found = false;
1013
1014 foreach ($this->getVisibleColumns() as $column)
1015 {
1016 if (!isset($column['sort']))
1017 continue;
1018 if ($column['sort'] == $field)
1019 {
1020 $found = true;
1021 break;
1022 }
1023 }
1024 unset($column);
1025
1026 if ($found)
1027 $result = [$field => $order];
1028
1029 $this->fillStorageNode(
1030 self::STORAGE_GRID,
1031 [
1032 'GRID_ORDER' => $this->modifyGridOrder($result),
1033 'GRID_ORDER_VARS' => $sorting['vars']
1034 ]
1035 );
1036
1037 unset($found, $field, $order, $sorting, $result);
1038 }
1039
1044 protected function modifyGridOrder(array $order)
1045 {
1046 return $order;
1047 }
1048
1052 protected function initGridFilter()
1053 {
1054 if (!$this->isUsedGridFilter())
1055 return;
1056 $this->initGridFilterConfig();
1057 $this->initGridFilterSettings();
1059 }
1060
1064 protected function initGridFilterConfig()
1065 {
1066 $this->gridFilterConfig = new UI\Filter\Options($this->getFilterId());
1067 }
1068
1072 protected function initGridFilterSettings()
1073 {
1074 if (!$this->isUsedGridFilter())
1075 return;
1076 $result = [
1077 'QUICK_SEARCH_FIELD' => null,
1078 'QUICK_SEARCH_DESCRIPTION' => [
1079 'FIELD' => null,
1080 'NAME' => null
1081 ]
1082 ];
1083 $fields = $this->getGridFilterDefinition();
1084 if (!empty($fields))
1085 {
1086 foreach (array_keys($fields) as $index)
1087 {
1088 $row = $fields[$index];
1089 if (
1090 (!isset($row['quickSearch']) && !isset($row['quickSearchOnly']))
1091 || (isset($row['entity']) && $row['entity'] != 'master')
1092 )
1093 continue;
1094
1095 $result['QUICK_SEARCH_FIELD'] = $row['id'];
1096 $result['QUICK_SEARCH_DESCRIPTION']['FIELD'] = $row['id'];
1097 $result['QUICK_SEARCH_DESCRIPTION']['NAME'] = $row['name'];
1098 }
1099 unset($index, $row);
1100 }
1101 unset($fields);
1102 $this->fillStorageNode(self::STORAGE_GRID_FILTER, $result);
1103 unset($fields, $result);
1104 }
1105
1109 protected function initGridFilterCurrentPreset()
1110 {
1111 if (!$this->isUsedGridFilter())
1112 return;
1113
1114 $preset = $this->prepareGridFilterCurrentPreset();
1115 if (!empty($preset))
1116 {
1117 $this->gridFilterConfig->setFilterSettings(
1118 UI\Filter\Options::TMP_FILTER,
1119 [
1120 'name' => '',
1121 'fields' => $preset
1122 ],
1123 true,
1124 false
1125 );
1126 $this->gridFilterConfig->save();
1127 }
1128 unset($preset);
1129 }
1130
1135 {
1136 return [];
1137 }
1138
1142 protected function getDataOrder()
1143 {
1144 return $this->getStorageItem(self::STORAGE_GRID, 'GRID_ORDER');
1145 }
1146
1150 protected function getDataFields()
1151 {
1152 $fields = $this->getStorageItem(self::STORAGE_GRID, 'VISIBLE_COLUMNS_MAP');
1153 $titleField = $this->getDataTitleField();
1154 if ($titleField !== '')
1155 $fields[$titleField] = true;
1156 unset($titleField);
1157 return array_keys($fields);
1158 }
1159
1163 protected function getDataFilter()
1164 {
1165 $result = $this->getInternalFilter();
1166
1167 $userFilter = $this->getUserFilter();
1168 if (!empty($userFilter))
1169 $result = array_merge($userFilter, $result);
1170 unset($userFilter);
1171
1172 return $result;
1173 }
1174
1178 protected function getDataTitleField()
1179 {
1180 return 'NAME';
1181 }
1182
1186 protected function getInternalFilter()
1187 {
1188 $result = [];
1189 $iblockId = (int)$this->getStorageItem(self::STORAGE_ENTITY_IBLOCK, 'IBLOCK_ID');
1190 if ($iblockId > 0)
1191 $result['IBLOCK_ID'] = $iblockId;
1192
1193 return $result;
1194 }
1195
1199 protected function getUserFilter()
1200 {
1201 if (!$this->isUsedGridFilter())
1202 return [];
1203
1204 $result = $this->prepareUserFilter();
1205 return $this->compileUserFilter($result);
1206 }
1207
1211 protected function prepareUserFilter()
1212 {
1213 if (!$this->isUsedGridFilter())
1214 return [];
1215
1216 $fields = $this->getGridFilterDefinition();
1217 $filterValues = $this->gridFilterConfig->getFilter($fields);
1218 $filterRows = UI\Filter\Options::getRowsFromFields($filterValues);
1219
1220 if (empty($filterRows))
1221 return [];
1222
1223 $result = [];
1224 $quickSearchField = $this->getQuickSearchField();
1225 $checkQuickSearch = (
1226 $quickSearchField !== null
1227 && isset($filterValues['FIND'])
1228 && is_string($filterValues['FIND'])
1229 && trim($filterValues['FIND']) != ''
1230 );
1231
1232 if ($checkQuickSearch)
1233 {
1234 $this->addFilterQuickSearchValue($result, $filterValues, $quickSearchField, $fields[$quickSearchField]);
1235 }
1236
1237 foreach ($filterRows as $id)
1238 {
1239 if (!isset($fields[$id]))
1240 continue;
1241
1242 if ($checkQuickSearch && $id == $quickSearchField)
1243 continue;
1244
1245 switch ($fields[$id]['type'])
1246 {
1247 case "number":
1248 $this->addFilterNumberValue($result, $filterValues, $id, $fields[$id]);
1249 break;
1250 case "date":
1251 $this->addFilterDateValue($result, $filterValues, $id, $fields[$id]);
1252 break;
1253 case "list":
1254 $this->addFilterListValue($result, $filterValues, $id, $fields[$id]);
1255 break;
1256 case "custom_entity":
1257 case "custom":
1258 break;
1259 case "checkbox":
1260 $this->addFilterCheckboxValue($result, $filterValues, $id, $fields[$id]);
1261 break;
1262 case "dest_selector":
1263 $this->addFilterDestSelectorValue($result, $filterValues, $id, $fields[$id]);
1264 break;
1265 /* case "custom_date":
1266 break; */
1267 case "string":
1268 default:
1269 $this->addFilterStringValue($result, $filterValues, $id, $fields[$id]);
1270 break;
1271 }
1272 }
1273 unset($id);
1274 unset($checkQuickSearch, $quickSearchField);
1275 unset($filterRows, $filterValues, $fields);
1276
1277 return $result;
1278 }
1279
1284 protected function compileUserFilter(array $filter)
1285 {
1286 return (isset($filter['master']) ? $filter['master'] : []);
1287 }
1288
1294 private function getFilterOperator(array $field, $operator)
1295 {
1296 $result = '';
1297 if ($operator === '')
1298 $operator = 'default';
1299 if (!empty($field['operators']) && is_array($field['operators']))
1300 {
1301 if (isset($field['operators'][$operator]))
1302 $result = $field['operators'][$operator];
1303 elseif (isset($field['operators']['default']))
1304 $result = $field['operators']['default'];
1305 }
1306 return $result;
1307 }
1308
1315 private function addFilterItems(array &$result, array $items, array $field)
1316 {
1317 if (empty($items))
1318 return;
1319
1320 $entity = (isset($field['entity']) ? $field['entity'] : 'master');
1321 if ($entity !== '')
1322 {
1323 if (!isset($result[$entity]))
1324 $result[$entity] = [];
1325 $result[$entity] = array_merge($result[$entity], $items);
1326 }
1327 unset($entity);
1328 }
1329
1337 private function addFilterQuickSearchValue(array &$result, array $filter, $fieldId, array $field)
1338 {
1339 $findValue = trim($filter['FIND']);
1340 $operator = $this->getFilterOperator($field, 'quickSearch');
1341 if (is_string($operator))
1342 $fieldId = $operator.$fieldId;
1343 unset($operator);
1344 $this->addFilterItems($result, [$fieldId => $findValue], $field);
1345 }
1346
1354 private function addFilterNumberValue(array &$result, array $filter, $fieldId, array $field)
1355 {
1356 $valueTypeIndex = $fieldId.'_numsel';
1357
1358 if (isset($filter[$valueTypeIndex]) && is_string($filter[$valueTypeIndex]))
1359 {
1360 $items = [];
1361
1362 $minIndex = $fieldId.'_from';
1363 $maxIndex = $fieldId.'_to';
1364
1365 $minValue = (isset($filter[$minIndex]) && is_string($filter[$minIndex]) ? trim($filter[$minIndex]) : '');
1366 $maxValue = (isset($filter[$maxIndex]) && is_string($filter[$maxIndex]) ? trim($filter[$maxIndex]) : '');
1367
1368 switch ($filter[$valueTypeIndex])
1369 {
1370 case 'exact':
1371 if ($minValue !== '')
1372 {
1373 $operator = $this->getFilterOperator($field, 'exact');
1374 if (is_string($operator))
1375 $fieldId = $operator.$fieldId;
1376 unset($operator);
1377 $items[$fieldId] = $minValue;
1378 }
1379 break;
1380 case 'range':
1381 if ($minValue !== '' && $maxValue !== '')
1382 {
1383 $operator = $this->getFilterOperator($field, 'range');
1384 if (is_string($operator))
1385 $fieldId = $operator.$fieldId;
1386 unset($operator);
1387 $items[$fieldId] = [$minValue, $maxValue];
1388 }
1389 break;
1390 case 'more':
1391 if ($minValue !== '')
1392 {
1393 $operator = $this->getFilterOperator($field, 'more');
1394 if (is_string($operator))
1395 $fieldId = $operator.$fieldId;
1396 unset($operator);
1397 $items[$fieldId] = $minValue;
1398 }
1399 break;
1400 case 'less':
1401 if ($maxValue !== '')
1402 {
1403 $operator = $this->getFilterOperator($field, 'less');
1404 if (is_string($operator))
1405 $fieldId = $operator.$fieldId;
1406 unset($operator);
1407 $items[$fieldId] = $maxValue;
1408 }
1409 break;
1410 }
1411 unset($maxValue, $minValue, $maxIndex, $minIndex);
1412
1413 $this->addFilterItems($result, $items, $field);
1414 unset($items);
1415 }
1416 unset($valueTypeIndex);
1417 }
1418
1426 private function addFilterDateValue(array &$result, array $filter, $fieldId, array $field)
1427 {
1428 $valueTypeIndex = $fieldId.'_datesel';
1429
1430 if (isset($filter[$valueTypeIndex]) && is_string($filter[$valueTypeIndex]))
1431 {
1432 $items = [];
1433
1434 $minIndex = $fieldId.'_from';
1435 $maxIndex = $fieldId.'_to';
1436
1437 $minValue = (isset($filter[$minIndex]) && is_string($filter[$minIndex]) ? trim($filter[$minIndex]) : '');
1438 $maxValue = (isset($filter[$maxIndex]) && is_string($filter[$maxIndex]) ? trim($filter[$maxIndex]) : '');
1439
1440 switch ($filter[$valueTypeIndex])
1441 {
1442 case 'EXACT':
1443 if ($minValue !== '')
1444 {
1445 $operator = $this->getFilterOperator($field, 'default');
1446 if (is_string($operator))
1447 $fieldId = $operator.$fieldId;
1448 unset($operator);
1449 $items[$fieldId] = $minValue;
1450 }
1451 break;
1452 case 'RANGE':
1453 default:
1454 if ($minValue !== '' && $maxValue !== '')
1455 {
1456 $operator = $this->getFilterOperator($field, 'range');
1457 if (is_string($operator))
1458 $fieldId = $operator.$fieldId;
1459 unset($operator);
1460 $items[$fieldId] = [$minValue, $maxValue];
1461 }
1462 break;
1463 }
1464 unset($maxValue, $minValue, $maxIndex, $minIndex);
1465
1466 $this->addFilterItems($result, $items, $field);
1467 unset($items);
1468 }
1469 }
1470
1478 private function addFilterListValue(array &$result, array $filter, $fieldId, array $field)
1479 {
1480 $multiple = isset($field['params']['multiple']) && $field['params']['multiple'] == 'Y';
1481 if (isset($filter[$fieldId]))
1482 {
1483 if ($multiple)
1484 $validRawValue = !empty($filter[$fieldId]) && is_array($filter[$fieldId]);
1485 else
1486 $validRawValue = is_string($filter[$fieldId]) || is_int($filter[$fieldId]);
1487 if ($validRawValue)
1488 {
1489
1490 if ($multiple)
1491 {
1492 $value = [];
1493 foreach ($filter[$fieldId] as $item)
1494 {
1495 if (isset($field['items'][$item]))
1496 $value[] = $item;
1497 }
1498 unset($item);
1499 $check = !empty($value);
1500 }
1501 else
1502 {
1503 $value = $filter[$fieldId];
1504 $check = isset($field['items'][$value]);
1505 }
1506 if ($check)
1507 {
1508 $operator = $this->getFilterOperator($field, ($multiple ? 'enum' : 'exact'));
1509 if (is_string($operator))
1510 $fieldId = $operator.$fieldId;
1511 unset($operator);
1512 $this->addFilterItems($result, [$fieldId => $value], $field);
1513 }
1514 unset($check, $value);
1515 }
1516 unset($validRawValue);
1517 }
1518 }
1519
1527 private function addFilterCheckboxValue(array &$result, array $filter, $fieldId, array $field)
1528 {
1529 if (isset($filter[$fieldId]))
1530 {
1531 $value = $filter[$fieldId];
1532 if ($value === 'Y' || $value === 'N')
1533 {
1534 $operator = $this->getFilterOperator($field, 'exact');
1535 if (is_string($operator))
1536 $fieldId = $operator.$fieldId;
1537 unset($operator);
1538 $this->addFilterItems($result, [$fieldId => $value], $field);
1539 }
1540 unset($value);
1541 }
1542 }
1543
1551 private function addFilterDestSelectorValue(array &$result, array $filter, $fieldId, array $field)
1552 {
1553 if (isset($filter[$fieldId]))
1554 {
1555 $multiple = isset($field['params']['multiple']) && $field['params']['multiple'] == 'Y';
1556 if ($multiple)
1557 $validRawValue = !empty($filter[$fieldId]) && is_array($filter[$fieldId]);
1558 else
1559 $validRawValue = is_string($filter[$fieldId]) && ($filter[$fieldId] !== '');
1560 if ($validRawValue)
1561 {
1562 $operator = $this->getFilterOperator($field, ($multiple ? 'enum' : 'exact'));
1563 if (is_string($operator))
1564 $fieldId = $operator.$fieldId;
1565 unset($operator);
1566 $this->addFilterItems($result, [$fieldId => $filter[$fieldId]], $field);
1567 }
1568 unset($validRawValue);
1569 }
1570 }
1571
1579 private function addFilterStringValue(array &$result, array $filter, $fieldId, array $field)
1580 {
1581 if (isset($filter[$fieldId]) && is_string($filter[$fieldId]))
1582 {
1583 $value = trim($filter[$fieldId]);
1584 if ($value !== '')
1585 {
1586 $operator = $this->getFilterOperator($field, 'default');
1587 if (is_string($operator))
1588 $fieldId = $operator.$fieldId;
1589 unset($operator);
1590 $this->addFilterItems($result, [$fieldId => $value], $field);
1591 }
1592 unset($value);
1593 }
1594 }
1598 protected function getData() {}
1599
1604 protected function setImplicitNavigationData(\CDBResult $iterator)
1605 {
1606 if (!$this->isUsedImplicitPageNavigation())
1607 return;
1608
1609 $navComponentObject = null;
1610 $navComponentParameters = [];
1611 if ($this->arParams['BASE_LINK'] !== '')
1612 {
1613 $navComponentParameters["BASE_LINK"] = \CHTTP::urlAddParams(
1614 $this->arParams['BASE_LINK'],
1615 [],
1616 ['encode' => true]
1617 );
1618 }
1619 $this->navigationString = $iterator->GetPageNavStringEx(
1620 $navComponentObject,
1621 $this->getNavigationTitle(),
1622 'grid',
1623 true,
1624 null,
1625 $navComponentParameters
1626 );
1627 $this->navigation->setRecordCount($iterator->NavRecordCount);
1628 unset($navComponentParameters, $navComponentObject);
1629 }
1630
1634 protected function getNavigationTitle()
1635 {
1636 return '';
1637 }
1638
1642 protected function getGridRows()
1643 {
1644 if (!empty($this->rows))
1645 {
1646 $returnDataSet = ($this->resultAction['DATA_TYPE'] == self::RESULT_DATA_TYPE_SET);
1647
1648 $editable = array_fill_keys(array_keys($this->getColumns()), false);
1649
1650 foreach (array_keys($this->rows) as $index)
1651 {
1652 $rawItem = $this->rows[$index];
1653
1654 $item = [
1655 'id' => $rawItem['ID'],
1656 'columns' => $rawItem,
1657 'editableColumns' => $editable
1658 ];
1659 if ($returnDataSet)
1660 {
1661 $action = $this->getRowAction($rawItem);
1662 if (!empty($action))
1663 {
1664 $item['actions'] = [
1665 [
1666 'DEFAULT' => true,
1667 'TEXT' => Loc::getMessage('ENTITY_SELECTOR_GRID_ACTION_SELECT'),
1668 'ONCLICK' => $action
1669 ]
1670 ];
1671 }
1672 unset($action);
1673 }
1674
1675 $this->rows[$index] = $item;
1676 }
1677 unset($item, $rawItem, $index);
1678
1679 unset($editable, $returnDataSet);
1680 }
1681 return $this->rows;
1682 }
1683
1687 protected function getBinaryDictionary()
1688 {
1689 return [
1690 'Y' => Loc::getMessage('ENTITY_SELECTOR_SELECT_YES'),
1691 'N' => Loc::getMessage('ENTITY_SELECTOR_SELECT_NO')
1692 ];
1693 }
1694
1699 protected function getRowAction(array $row)
1700 {
1701 $result = null;
1702 if ($this->resultAction['DATA_TYPE'] != self::RESULT_DATA_TYPE_SET)
1703 return $result;
1704 switch ($this->resultAction['TYPE'])
1705 {
1706 case self::RESULT_ACTION_TYPE_EVENT:
1707 break;
1708 case self::RESULT_ACTION_TYPE_CALLBACK:
1709 break;
1710 case self::RESULT_ACTION_TYPE_CLASS_METHOD:
1711 break;
1712 case self::RESULT_ACTION_TYPE_SLIDER:
1713 $set = $this->getSliderResultDataSet($row);
1714 if (!empty($set))
1715 {
1716 $convertedSet = \CUtil::PhpToJSObject($set, false, true, false);
1717 $result = 'top.BX.SidePanel.Instance.postMessageTop(window, \''.$this->resultAction['NAME'].'\', {filter: '.$convertedSet.'}); top.BX.SidePanel.Instance.getTopSlider().close(true);';
1718 unset($convertedSet);
1719 }
1720 break;
1721 }
1722 return $result;
1723 }
1724
1729 protected function getSliderResultDataSet(array $row)
1730 {
1731 return [];
1732 }
1733
1738 protected static function isGridFilterRow(array $row)
1739 {
1740 return (!isset($row['quickSearchOnly']));
1741 }
1742
1749 protected static function clearStringValue(string $value): string
1750 {
1751 return preg_replace('/[^a-zA-Z0-9_:\\[\\]]/', '', $value);
1752 }
1753
1761 protected static function validateSingleParameter(array &$params, string $field): void
1762 {
1763 $value = '';
1764 if (isset($params[$field]) && is_string($params[$field]))
1765 {
1766 $value = static::clearStringValue($params[$field]);
1767 }
1768 $params[$field] = $value;
1769 unset($value);
1770 }
1771
1779 protected static function validateListParameters(array &$params, array $list): void
1780 {
1781 foreach ($list as $field)
1782 {
1783 static::validateSingleParameter($params, $field);
1784 }
1785 unset($field);
1786 }
1787}
setStorageItem($node, $item, $value)
Definition entity.php:669
setImplicitNavigationData(\CDBResult $iterator)
Definition entity.php:1604
fillStorageNode($node, array $nodeValues)
Definition entity.php:642
static loadMessages($file)
Definition loc.php:64
static getMessage($code, $replace=null, $language=null)
Definition loc.php:29