Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
selector.php
1<?php
3
10
12{
13 /* default path to open the selector in the slider */
14 const SOURCE_PATH = '/bitrix/tools/landing/source.php';
15
16 /* default event id for get sources */
17 const EVENT_BUILD_SOURCE_LIST = 'OnBuildSourceList';
18
19 /* site mode for sources */
20 const SITE_MODE_UNKNOWN = 'UNKNOWN';
21 const SITE_MODE_SYSTEM = 'SYSTEM';
22 const SITE_MODE_PAGE = 'PAGE';
23 const SITE_MODE_STORE = 'STORE';
24 const SITE_MODE_KNOWLEDGE = 'KNOWLEDGE';
25
26 /* selector type */
27 const SOURCE_TYPE_COMPONENT = 'C'; // component selector
28 const SOURCE_TYPE_PRESET = 'P'; // without selector - fixed preset
29
30 /* transfer type source filter after selecting items to display */
31 const ACTION_TYPE_EVENT = 'event'; // use javascript event directly
32 const ACTION_TYPE_SLIDER = 'slider'; // use standart slider method BX.SidePanel.Instance.postMessageTop
33
34 const ACTION_NAME = 'save'; // default event name for Selector::ACTION_TYPE_SLIDER
35
36 /* config for current landing */
37 protected $config = [
38 'SOURCE_EVENT_ID' => self::EVENT_BUILD_SOURCE_LIST, // Event ID for a list of sources
39 'SOURCE_PATH' => self::SOURCE_PATH, // path for open source filter (component, include page, etc)
40 'RESULT_ACTION_TYPE' => self::ACTION_TYPE_SLIDER, //
41 'RESULT_ACTION_NAME' => self::ACTION_NAME
42 ];
43
46
48 protected $restrictions = null;
49
51 protected $sourceList = null;
52
61 public function __construct(array $config = [])
62 {
63 $this->setConfig($config);
64 $this->initSiteMode();
65 $this->initRestrictions();
66 }
67
74 protected function initSourceList()
75 {
76 if ($this->sourceList !== null)
77 {
78 return;
79 }
80 $this->sourceList = [];
81
82 $event = new Main\Event(
83 'landing',
84 $this->config['SOURCE_EVENT_ID'],
85 [
86 'SELECTOR' => $this,
87 'RESTRICTIONS' => $this->restrictions // TODO: remove this key after stable socialnetwork update
88 ]
89 );
90 $event->send();
91 $resultList = $event->getResults();
92 if (!empty($resultList))
93 {
94 foreach ($resultList as $eventResult)
95 {
96 if ($eventResult->getType() != Main\EventResult::SUCCESS)
97 {
98 continue;
99 }
100 $module = (string)$eventResult->getModuleId();
101 $list = $eventResult->getParameters();
102 if (empty($list) || !is_array($list))
103 {
104 continue;
105 }
106 foreach ($list as $row)
107 {
108 $source = $this->prepareSourceParameters(
109 $module,
110 $row
111 );
112 if (empty($source))
113 {
114 continue;
115 }
116 $this->sourceList[$source['INDEX']] = $source;
117 }
118 }
119 unset($source, $row, $list, $module);
120 unset($eventResult, $resultList);
121
122 if (!empty($this->sourceList))
123 {
124 Main\Type\Collection::sortByColumn(
125 $this->sourceList,
126 ['TYPE' => SORT_ASC, 'TITLE' => SORT_ASC],
127 '',
128 null,
129 true
130 );
131 }
132 }
133 unset($event);
134 }
135
143 public function getSourceFilterBaseUri($module, $sourceId)
144 {
145 $uri = new Main\Web\Uri($this->config['SOURCE_PATH']);
146 $uri->addParams($this->getBaseUrlParams(static::getSourceIndex($module, $sourceId)));
147 return $uri;
148 }
149
155 public function getSourcesDescription()
156 {
157 $result = [];
158 $this->initSourceList();
159 if (empty($this->sourceList))
160 {
161 return $result;
162 }
163 $uri = new Main\Web\Uri($this->config['SOURCE_PATH']);
164 foreach ($this->sourceList as $source)
165 {
166 $systemSettings = [
167 'detailPage' => $source['SYSTEM_SETTINGS']['DETAIL_PAGE']
168 ];
169
170 $uri->addParams($this->getBaseUrlParams($source['INDEX']));
171 $row = [
172 'id' => $source['INDEX'],
173 'name' => $source['TITLE'],
174 'sort' => $source['DATA_SETTINGS']['ORDER'],
175 'references' => $source['DATA_SETTINGS']['FIELDS'],
176 'settings' => $systemSettings
177 ];
178 switch ($source['TYPE'])
179 {
181 $row['url'] = [
182 'filter' => $uri->getUri()
183 ];
184 break;
186 $row['filter'] = $source['SETTINGS']['FILTER'];
187 break;
188 }
189 $result[$source['INDEX']] = $row;
190 }
191 unset($row, $source);
192 unset($uri);
193
194 return $result;
195 }
196
204 public function findSource($index)
205 {
206 if (!is_string($index) || $index === '')
207 {
208 return null;
209 }
210 $this->initSourceList();
211 return isset($this->sourceList[$index]) ? $this->sourceList[$index] : null;
212 }
213
220 public function showSourceFilter($index)
221 {
222 global $APPLICATION;
223
224 $source = $this->findSource($index);
225 if (empty($source))
226 {
227 return;
228 }
229
230 switch ($source['TYPE'])
231 {
233 $APPLICATION->IncludeComponent(
234 'bitrix:ui.sidepanel.wrapper',
235 '.default',
236 [
237 'POPUP_COMPONENT_NAME' => $source['SETTINGS']['COMPONENT_NAME'],
238 'POPUP_COMPONENT_TEMPLATE_NAME' => $source['SETTINGS']['COMPONENT_TEMPLATE_NAME'],
239 'POPUP_COMPONENT_PARAMS' => $source['SETTINGS']['COMPONENT_PARAMS'],
240 ] + $source['SETTINGS']['WRAPPER']
241 );
242 break;
243 }
244 }
245
252 {
253 $request = Main\Context::getCurrent()->getRequest();
254 $sourceIndex = (string)$request->get('SOURCE_ID');
255 unset($request);
256 if ($sourceIndex === '')
257 {
258 return;
259 }
260 $this->showSourceFilter($sourceIndex);
261 }
262
269 public function getDataLoader($index, array $parameters, array $options = [])
270 {
271 $source = $this->findSource($index);
272 if (empty($source))
273 {
274 return null;
275 }
276
277 $parameters['internal_filter'] = $source['SOURCE_FILTER'];
278
280 $result = new $source['DATA_LOADER'];
281 $result->setConfig($parameters);
282 $result->setOptions($options);
283
284 return $result;
285 }
286
293 public static function getSources(array $config = [])
294 {
295 $selector = new static($config);
296 return $selector->getSourcesDescription();
297 }
298
305 public static function getSourceNames(array $config = [])
306 {
307 $result = [];
308 $selector = new static($config);
309 $selector->initSourceList();
310 foreach ($selector->sourceList as $source)
311 {
312 $result[$source['INDEX']] = $source['TITLE'];
313 }
314 unset($source);
315
316 return $result;
317 }
318
324 public function getSiteMode()
325 {
326 return $this->siteMode;
327 }
328
333 public function checkSiteMode(array $modeList)
334 {
335 return (
336 $this->siteMode === self::SITE_MODE_SYSTEM
337 || in_array($this->siteMode, $modeList, true)
338 );
339 }
340
347 public function getModuleRestrictions($module)
348 {
349 $module = (string)$module;
350 if ($module === '')
351 {
352 return null;
353 }
354 if (isset($this->restrictions[$module]))
355 {
356 return $this->restrictions[$module];
357 }
358 if (isset($this->restrictions['all']))
359 {
360 return $this->restrictions['all'];
361 }
362 return null;
363 }
364
365 /* Public tools */
366
372 public static function getSourceIndex($module, $sourceId)
373 {
374 return (string)$module.':'.(string)$sourceId;
375 }
376
380 public function getResultAction()
381 {
382 return [
383 'TYPE' => $this->config['RESULT_ACTION_TYPE'],
384 'NAME' => $this->config['RESULT_ACTION_NAME']
385 ];
386 }
387
391 public function getDefaultLinkActions()
392 {
393 return [
394 [
395 'type' => 'detail',
396 'name' => Loc::getMessage('LANDING_SOURCE_ACTION_TITLE_DETAIL')
397 ],
398 [
399 'type' => 'link',
400 'name' => Loc::getMessage('LANDING_SOURCE_ACTION_TITLE_LINK')
401 ]
402 ];
403 }
404
405 /* Public tools end */
406
413 protected function setConfig(array $config)
414 {
415 $config = $this->prepareConfig($config);
416 if (!empty($config))
417 {
418 $this->config = array_merge($this->config, $config);
419 }
420 }
421
428 protected function prepareConfig(array $config)
429 {
430 $result = [];
431 $config = array_filter($config, [__CLASS__, 'clearFilter']);
432 $config = array_intersect_key($config, $this->config);
433 if (!empty($config))
434 {
435 foreach ($config as $field => $value)
436 {
437 $checked = true;
438 switch ($field)
439 {
440 case 'ID':
441 if (is_string($value))
442 {
443 $value = preg_replace('/[^a-zA-Z0-9_:\\[\\]]/', '', trim($value));
444 }
445 $checked = (is_string($value) && $value !== '');
446 break;
447 case 'SOURCE_EVENT_ID':
448 if (is_string($value))
449 {
450 $value = preg_replace('/[^a-zA-Z0-9]/', '', trim($value));
451 }
452 $checked = (is_string($value) && $value !== '');
453 break;
454 case 'RESULT_ACTION_TYPE':
455 case 'RESULT_ACTION_NAME':
456 if (is_string($value))
457 {
458 $value = preg_replace('/[^a-zA-Z0-9_]/', '', trim($value));
459 }
460 $checked = (is_string($value) && $value !== '');
461 break;
462 case 'SOURCE_PATH':
463 if (is_string($value))
464 {
465 $value = trim($value);
466 }
467 //TODO: add check relative real path
468 $checked = (is_string($value) && $value !== '');
469 break;
470 }
471 if ($checked)
472 {
473 $result[$field] = $value;
474 }
475 }
476 }
477
478 if (!isset($result['ID']))
479 {
480 $result['ID'] = preg_replace('/[^a-zA-Z0-9_:\\[\\]]/', '', get_called_class());
481 }
482
483 return $result;
484 }
485
492 protected function clearFilter($value)
493 {
494 return ($value !== null);
495 }
496
502 protected function initSiteMode()
503 {
504 $siteType = Landing::getSiteType();
505 if ($siteType === '')
506 {
507 $this->siteMode = self::SITE_MODE_SYSTEM;
508 }
509 else
510 {
511 switch ($siteType)
512 {
513 case 'PAGE':
514 $this->siteMode = self::SITE_MODE_PAGE;
515 break;
516 case 'STORE':
517 $this->siteMode = self::SITE_MODE_STORE;
518 break;
519 case 'KNOWLEDGE':
520 $this->siteMode = self::SITE_MODE_KNOWLEDGE;
521 break;
522 }
523 }
524 unset($siteType);
525 }
526
532 protected function initRestrictions()
533 {
534 $this->restrictions = [];
535 /* all */
536 $siteId = (defined('SITE_ID') ? SITE_ID : null);
537 if (!empty($siteId))
538 {
539 $this->restrictions['all'] = ['SITE_ID' => $siteId];
540 $this->restrictions['iblock'] = $this->restrictions['all'];
541 $this->restrictions['socialnetwork'] = $this->restrictions['all'];
542 }
543 /* iblock */
544 $iblockId = (string)Manager::getOption('source_iblocks');
545 if ($iblockId !== '')
546 {
547 $iblockId = explode(',', $iblockId);
548 }
549 else
550 {
551 $iblockId = [
552 Hook\Page\Settings::getDataForSite()['IBLOCK_ID']
553 ];
554 }
555 $this->restrictions['iblock']['IBLOCK_ID'] = $iblockId;
556 }
557
565 protected function prepareSourceParameters($module, $parameters)
566 {
567 if (empty($parameters) || !is_array($parameters))
568 {
569 return null;
570 }
571
572 if (!isset($parameters['SOURCE_ID']))
573 {
574 return null;
575 }
576 $parameters['SOURCE_ID'] = (string)$parameters['SOURCE_ID'];
577 if ($parameters['SOURCE_ID'] === '')
578 {
579 return null;
580 }
581
582 if (!isset($parameters['TITLE']))
583 {
584 return null;
585 }
586 $parameters['TITLE'] = trim((string)$parameters['TITLE']);
587 if ($parameters['TITLE'] === '')
588 {
589 return null;
590 }
591
592 $index = self::getSourceIndex($module, $parameters['SOURCE_ID']);
593 $prepared = [];
594 if (!preg_match('/^[a-z][a-z.]+:[A-Za-z][A-Za-z0-9]*$/', $index, $prepared))
595 {
596 return null;
597 }
598
599 $result = [
600 'INDEX' => $index,
601 'MODULE' => $module,
602 'SOURCE_ID' => $parameters['SOURCE_ID'],
603 'TITLE' => $parameters['TITLE']
604 ];
605
606 if (!isset($parameters['TYPE']))
607 {
608 $parameters['TYPE'] = self::SOURCE_TYPE_COMPONENT;
609 }
610 $parameters['TYPE'] = (string)$parameters['TYPE'];
611 if (
612 $parameters['TYPE'] !== self::SOURCE_TYPE_COMPONENT
613 && $parameters['TYPE'] !== self::SOURCE_TYPE_PRESET
614 )
615 {
616 return null;
617 }
618
619 $result['TYPE'] = $parameters['TYPE'];
620
621 if (empty($parameters['SETTINGS']) || !is_array($parameters['SETTINGS']))
622 {
623 return null;
624 }
625
626 $result['SYSTEM_SETTINGS'] = $this->checkSystemSettings($parameters['SETTINGS']);
627
628 $result['SETTINGS'] = [];
629
630 $settings = null;
631 switch ($parameters['TYPE'])
632 {
634 $settings = $this->checkComponentSettings($parameters['SETTINGS']);
635 break;
637 $settings = $this->checkPresetSettings($parameters['SETTINGS']);
638 break;
639 }
640 if ($settings === null)
641 {
642 return null;
643 }
644 $result['SETTINGS'] = $settings;
645 unset($settings);
646
647 if (empty($parameters['DATA_SETTINGS']) || !is_array($parameters['DATA_SETTINGS']))
648 {
649 return null;
650 }
651 $settings = $this->checkDataSettings($parameters['DATA_SETTINGS']);
652 if ($settings === null)
653 {
654 return null;
655 }
656 $result['DATA_SETTINGS'] = $settings;
657 unset($settings);
658
659 if (empty($parameters['DATA_LOADER']))
660 {
661 return null;
662 }
663 if (!is_string($parameters['DATA_LOADER'])
664 || !is_subclass_of($parameters['DATA_LOADER'], '\Bitrix\Landing\Source\DataLoader'))
665 {
666 return null;
667 }
668 $result['DATA_LOADER'] = $parameters['DATA_LOADER'];
669
670 $result['SOURCE_FILTER'] = [];
671 if (!empty($parameters['SOURCE_FILTER']) && is_array($parameters['SOURCE_FILTER']))
672 {
673 $result['SOURCE_FILTER'] = $parameters['SOURCE_FILTER'];
674 }
675
676 return $result;
677 }
678
685 protected function checkSystemSettings(array $settings)
686 {
687 $result = [
688 'DETAIL_PAGE' => true
689 ];
690
691 if (isset($settings['DETAIL_PAGE']) && is_bool($settings['DETAIL_PAGE']))
692 {
693 $result['DETAIL_PAGE'] = $settings['DETAIL_PAGE'];
694 }
695
696 return $result;
697 }
698
705 protected function checkComponentSettings(array $settings)
706 {
707 if (!isset($settings['COMPONENT_NAME']))
708 {
709 return null;
710 }
711 $settings['COMPONENT_NAME'] = (string)$settings['COMPONENT_NAME'];
712 if ($settings['COMPONENT_NAME'] === '')
713 {
714 return null;
715 }
716
717 if (!isset($settings['COMPONENT_TEMPLATE_NAME']))
718 {
719 return null;
720 }
721 $settings['COMPONENT_TEMPLATE_NAME'] = (string)$settings['COMPONENT_TEMPLATE_NAME'];
722
723 if (!isset($settings['COMPONENT_PARAMS']) || !is_array($settings['COMPONENT_PARAMS']))
724 {
725 return null;
726 }
727
728 $settings['WRAPPER'] = $this->checkWrapperSettings($settings);
729
730 return array_intersect_key(
731 $settings,
732 [
733 'COMPONENT_NAME' => true,
734 'COMPONENT_TEMPLATE_NAME' => true,
735 'COMPONENT_PARAMS' => true,
736 'WRAPPER' => true
737 ]
738 );
739 }
740
747 protected function checkPresetSettings(array $settings)
748 {
749 if (empty($settings['FILTER']) || !is_array($settings['FILTER']))
750 {
751 return null;
752 }
753
754 $preset = array_filter($settings['FILTER'], ['\Bitrix\Landing\Source\BlockFilter', 'checkPreparedRow']);
755 if (empty($preset))
756 {
757 return null;
758 }
759
760 return [
761 'FILTER' => $preset
762 ];
763 }
764
771 protected function checkWrapperSettings(array $settings)
772 {
773 $result = [
774 'USE_PADDING' => false,
775 'PLAIN_VIEW' => false,
776 'USE_UI_TOOLBAR' => 'N'
777 ];
778
779 if (isset($settings['WRAPPER']) && is_array($settings['WRAPPER']))
780 {
781 $rawData = $settings['WRAPPER'];
782 if (isset($rawData['USE_PADDING']) && is_bool($rawData['USE_PADDING']))
783 {
784 $result['USE_PADDING'] = $rawData['USE_PADDING'];
785 }
786 if (isset($rawData['PLAIN_VIEW']) && is_bool($rawData['PLAIN_VIEW']))
787 {
788 $result['PLAIN_VIEW'] = $rawData['PLAIN_VIEW'];
789 }
790 if (
791 isset($rawData['USE_UI_TOOLBAR'])
792 && ($rawData['USE_UI_TOOLBAR'] === 'Y' || $rawData['USE_UI_TOOLBAR'] === 'N')
793 )
794 {
795 $result['USE_UI_TOOLBAR'] = $rawData['USE_UI_TOOLBAR'];
796 }
797 unset($rawData);
798 }
799 else
800 {
801 // TODO: remove this branch after stable update socialnetwork
802 if (
803 isset($settings['USE_UI_TOOLBAR'])
804 && ($settings['USE_UI_TOOLBAR'] === 'Y' || $settings['USE_UI_TOOLBAR'] === 'N')
805 )
806 {
807 $result['USE_UI_TOOLBAR'] = $settings['USE_UI_TOOLBAR'];
808 }
809 }
810
811 return $result;
812 }
813
820 protected function checkDataSettings(array $settings)
821 {
822 if (empty($settings))
823 {
824 return null;
825 }
826
827 $result = [];
828
829 if (!is_array($settings['ORDER']))
830 {
831 return null;
832 }
833 $settings['ORDER'] = array_filter($settings['ORDER'], [__CLASS__, 'isNotEmptyField']);
834 if (empty($settings['ORDER']))
835 {
836 return null;
837 }
838 $list = [];
839 foreach ($settings['ORDER'] as $row)
840 {
841 $row = $this->prepareOrderField($row);
842 if (empty($row))
843 {
844 continue;
845 }
846 $list[] = $row;
847 }
848 unset($row);
849 if (empty($list))
850 {
851 return null;
852 }
853 $result['ORDER'] = $list;
854 unset($list);
855
856 if (!is_array($settings['FIELDS']))
857 {
858 return null;
859 }
860 $settings['FIELDS'] = array_filter($settings['FIELDS'], [__CLASS__, 'isNotEmptyField']);
861 if (empty($settings['FIELDS']))
862 {
863 return null;
864 }
865 $list = [];
866 foreach ($settings['FIELDS'] as $row)
867 {
868 $row = Node::prepareFieldDefinition($row);
869 if (empty($row))
870 {
871 continue;
872 }
873
874 $list[] = $row;
875 }
876 if (empty($list))
877 {
878 return null;
879 }
880 $result['FIELDS'] = $list;
881 unset($list);
882
883 return $result;
884 }
885
892 protected function getBaseUrlParams($index)
893 {
894 return array_merge(
895 [
896 'SOURCE_ID' => $index
897 ],
898 $this->getUrlSystemParams()
899 );
900 }
901
907 protected function getUrlSystemParams()
908 {
909 $result = [
910 'lang' => LANGUAGE_ID
911 ];
912 if (defined('SITE_ID'))
913 {
914 $result['site'] = SITE_ID;
915 }
916 if (defined('SITE_TEMPLATE_ID'))
917 {
918 $result['template'] = SITE_TEMPLATE_ID;
919 }
920 $request = Main\Context::getCurrent()->getRequest();
921 if ($request->isAdminSection())
922 {
923 $result['admin_section'] = 'Y';
924 }
925 unset($request);
926 return $result;
927 }
928
933 protected static function isNotEmptyField($item)
934 {
935 return (!empty($item) && is_array($item));
936 }
937
942 protected function prepareOrderField(array $field)
943 {
944 $field = array_change_key_case($field, CASE_LOWER);
945
946 $field['id'] = $this->prepareStringValue($field, 'id');
947 $field['name'] = $this->prepareStringValue($field, 'name');
948 if (empty($field['id']) || empty($field['name']))
949 {
950 return null;
951 }
952
953 return [
954 'id' => $field['id'],
955 'name' => $field['name']
956 ];
957 }
958
964 protected function prepareStringValue(array $row, $name)
965 {
966 if (empty($row[$name]) || !is_string($row[$name]))
967 {
968 return null;
969 }
970 $row[$name] = trim($row[$name]);
971 if ($row[$name] === '')
972 {
973 return null;
974 }
975 return $row[$name];
976 }
977}
static getOption($code, $default=null)
Definition manager.php:160
checkSystemSettings(array $settings)
Definition selector.php:685
checkComponentSettings(array $settings)
Definition selector.php:705
prepareStringValue(array $row, $name)
Definition selector.php:964
checkWrapperSettings(array $settings)
Definition selector.php:771
static getSourceNames(array $config=[])
Definition selector.php:305
checkSiteMode(array $modeList)
Definition selector.php:333
static getSourceIndex($module, $sourceId)
Definition selector.php:372
getSourceFilterBaseUri($module, $sourceId)
Definition selector.php:143
checkDataSettings(array $settings)
Definition selector.php:820
checkPresetSettings(array $settings)
Definition selector.php:747
prepareSourceParameters($module, $parameters)
Definition selector.php:565
__construct(array $config=[])
Definition selector.php:61
static getSources(array $config=[])
Definition selector.php:293
static getMessage($code, $replace=null, $language=null)
Definition loc.php:29