Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
elementlist.php
1<?php
2
4
13
19abstract class ElementList extends Base
20{
21 private $multiIblockMode = false;
22 private $paginationMode = false;
23 protected $navigation = false;
24 protected $pagerParameters = array();
25
33 protected function setMultiIblockMode($state)
34 {
35 $this->multiIblockMode = (bool)$state;
36
37 return $this;
38 }
39
45 public function isMultiIblockMode()
46 {
47 return (bool)$this->multiIblockMode;
48 }
49
57 protected function setPaginationMode($state)
58 {
59 $this->paginationMode = (bool)$state;
60
61 return $this;
62 }
63
69 public function isPaginationMode()
70 {
71 return (bool)$this->paginationMode;
72 }
73
74 public function onPrepareComponentParams($params)
75 {
76 if (!is_array($params))
77 {
78 $params = [];
79 }
80 $params = parent::onPrepareComponentParams($params);
81 $this->makeMagicWithPageNavigation();
82
83 // compatibility with 'ELEMENT_COUNT' components
84 if (isset($params['ELEMENT_COUNT']))
85 {
86 $params['PAGE_ELEMENT_COUNT'] = $params['ELEMENT_COUNT'];
87 }
88
89 // PREDICT_ELEMENT_COUNT - hidden parameter to get elements count from "PRODUCT_ROW_VARIANTS" instead of "PAGE_ELEMENT_COUNT"
90 if (isset($params['PREDICT_ELEMENT_COUNT']) && $params['PREDICT_ELEMENT_COUNT'] === 'Y' && !empty($params['PRODUCT_ROW_VARIANTS']))
91 {
92 $isBigData = $this->request->get('bigData') === 'Y';
93 $params['PRODUCT_ROW_VARIANTS'] = static::parseJsonParameter($params['PRODUCT_ROW_VARIANTS']);
94 $params['PAGE_ELEMENT_COUNT'] = static::predictElementCountByVariants($params['PRODUCT_ROW_VARIANTS'], $isBigData);
95 }
96
97 $params['PAGE_ELEMENT_COUNT'] = (int)($params['PAGE_ELEMENT_COUNT'] ?? 0);
98 $params['ELEMENT_COUNT'] = (int)($params['ELEMENT_COUNT'] ?? 0);
99 $params['LINE_ELEMENT_COUNT'] = (int)($params['LINE_ELEMENT_COUNT'] ?? 3);
100
101 $params['INCLUDE_SUBSECTIONS'] ??= '';
102 if (!in_array(
103 $params['INCLUDE_SUBSECTIONS'],
104 [
105 'Y',
106 'A',
107 'N',
108 ]
109 ))
110 {
111 $params['INCLUDE_SUBSECTIONS'] = 'Y';
112 }
113
114 $params['HIDE_NOT_AVAILABLE'] ??= '';
115 if ($params['HIDE_NOT_AVAILABLE'] !== 'Y' && $params['HIDE_NOT_AVAILABLE'] !== 'L')
116 {
117 $params['HIDE_NOT_AVAILABLE'] = 'N';
118 }
119
120 $params['HIDE_NOT_AVAILABLE_OFFERS'] ??= '';
121 if ($params['HIDE_NOT_AVAILABLE_OFFERS'] !== 'Y' && $params['HIDE_NOT_AVAILABLE_OFFERS'] !== 'L')
122 {
123 $params['HIDE_NOT_AVAILABLE_OFFERS'] = 'N';
124 }
125
126 $params['FILTER_NAME'] = trim((string)($params['FILTER_NAME'] ?? ''));
127 // ajax request doesn't have access to page $GLOBALS
128 if (isset($params['GLOBAL_FILTER']))
129 {
130 $this->globalFilter = $params['GLOBAL_FILTER'];
131 }
132 else
133 {
134 if (
135 $params['FILTER_NAME'] !== ''
136 && preg_match(self::PARAM_TITLE_MASK, $params['FILTER_NAME'])
137 && isset($GLOBALS[$params['FILTER_NAME']])
138 && is_array($GLOBALS[$params['FILTER_NAME']])
139 )
140 {
141 $this->globalFilter = $GLOBALS[$params['FILTER_NAME']];
142 }
143
144 if (isset($this->globalFilter['FACET_OPTIONS']) && count($this->globalFilter) == 1)
145 {
146 unset($this->globalFilter['FACET_OPTIONS']);
147 }
148
149 // save global filter for ajax request params
150 $this->arResult['ORIGINAL_PARAMETERS']['GLOBAL_FILTER'] = $this->globalFilter;
151 }
152
153 $productMappingFilter = [];
154 if (
155 Loader::includeModule('catalog')
156 && Catalog\Product\SystemField\ProductMapping::isAllowed()
157 )
158 {
159 $productMappingFilter = Catalog\Product\SystemField\ProductMapping::getExtendedFilterByArea(
160 [],
161 Catalog\Product\SystemField\ProductMapping::MAP_LANDING
162 );
163 }
164 $params['CACHE_FILTER'] = isset($params['CACHE_FILTER']) && $params['CACHE_FILTER'] === 'Y';
165 if (
166 !$params['CACHE_FILTER']
167 && !empty($this->globalFilter)
168 && array_diff_assoc($this->globalFilter, $productMappingFilter)
169 )
170 {
171 $params['CACHE_TIME'] = 0;
172 }
173
174 $params = $this->prepareElementSortRow(
175 $params,
176 ['ORDER' => 'ELEMENT_SORT_FIELD', 'DIRECTION' => 'ELEMENT_SORT_ORDER'],
177 ['ORDER' => 'SORT', 'DIRECTION' => 'asc']
178 );
179
180 $params = $this->prepareElementSortRow(
181 $params,
182 ['ORDER' => 'ELEMENT_SORT_FIELD2', 'DIRECTION' => 'ELEMENT_SORT_ORDER2'],
183 ['ORDER' => 'ID', 'DIRECTION' => 'desc']
184 );
185
186 $params['PAGER_BASE_LINK_ENABLE'] = (string)($params['PAGER_BASE_LINK_ENABLE'] ?? '');
187 $params['PAGER_TITLE'] = (string)($params['PAGER_TITLE'] ?? '');
188 $params['PAGER_TEMPLATE'] = (string)($params['PAGER_TEMPLATE'] ?? '');
189 $params['PAGER_PARAMS_NAME'] = trim((string)($params['PAGER_PARAMS_NAME'] ?? ''));
190 if (
191 $params['PAGER_PARAMS_NAME'] !== ''
192 && preg_match(self::PARAM_TITLE_MASK, $params['PAGER_PARAMS_NAME'])
193 )
194 {
195 $this->pagerParameters = $GLOBALS[$params['PAGER_PARAMS_NAME']] ?? [];
196
197 if (!is_array($this->pagerParameters))
198 {
199 $this->pagerParameters = [];
200 }
201 }
202
203 if (Loader::includeModule('catalog') && isset($params['CUSTOM_FILTER']) && is_string($params['CUSTOM_FILTER']))
204 {
205 try
206 {
207 $params['CUSTOM_FILTER'] = $this->parseCondition(Json::decode($params['CUSTOM_FILTER']), $params);
208 }
209 catch (\Exception $e)
210 {
211 $params['CUSTOM_FILTER'] = array();
212 }
213 }
214 else
215 {
216 $params['CUSTOM_FILTER'] = array();
217 }
218
219 if ($this->isPaginationMode())
220 {
221 $this->getPaginationParams($params);
222 }
223
224 $this->getSpecificIblockParams($params);
225
226 $params['CALCULATE_SKU_MIN_PRICE'] = (isset($params['CALCULATE_SKU_MIN_PRICE']) && $params['CALCULATE_SKU_MIN_PRICE'] === 'Y');
227
228 return $params;
229 }
230
237 protected function prepareElementSortRow(array $params, array $orderRow, array $default): array
238 {
239 $order = (isset($orderRow['ORDER']) ? trim($orderRow['ORDER']) : '');
240 $direction = (isset($orderRow['DIRECTION']) ? trim($orderRow['DIRECTION']) : '');
241 if (empty($params) || $order === '' || $direction === '')
242 {
243 return $params;
244 }
245 if (empty($params[$order]))
246 {
247 $params[$order] = $default['ORDER'] ?? 'SORT';
248 }
249 $params[$order] = strtoupper($params[$order]);
250
251 if ($params[$order] === 'ID' && !empty($params[$direction]) && is_array($params[$direction]))
252 {
253 Collection::normalizeArrayValuesByInt($params[$direction], false);
254 if (empty($params[$direction]))
255 {
256 $params[$direction] = $default['DIRECTION'] ?? 'desc';
257 }
258 }
259 else
260 {
261 if (empty($params[$direction]) || !preg_match(self::SORT_ORDER_MASK, $params[$direction]))
262 {
263 $params[$direction] = $default['DIRECTION'] ?? 'desc';
264 }
265 }
266
267 return $params;
268 }
269
270 protected function checkProductIblock(array $product): bool
271 {
272 $result = true;
273 if (!$this->isMultiIblockMode())
274 {
275 $result = ($product['PRODUCT_IBLOCK_ID'] == $this->arParams['IBLOCK_ID']);
276 }
277 return $result;
278 }
279
280 protected static function predictElementCountByVariants($variants, $isBigData = false)
281 {
282 $count = 0;
283 $templateVariantsMap = static::getTemplateVariantsMap();
284
285 if (!empty($variants))
286 {
287 foreach ($variants as $variant)
288 {
289 foreach ($templateVariantsMap as $variantInfo)
290 {
291 if ((int)$variantInfo['VARIANT'] === (int)$variant['VARIANT'])
292 {
293 if (
294 ($isBigData && $variant['BIG_DATA'])
295 || (!$isBigData && !$variant['BIG_DATA'])
296 )
297 {
298 $count += (int)$variantInfo['COUNT'];
299 }
300
301 break;
302 }
303 }
304 }
305 }
306
307 return $count;
308 }
309
310 private function makeMagicWithPageNavigation()
311 {
312 if ($this->request->isAjaxRequest())
313 {
314 foreach ($this->request->getPostList() as $name => $value)
315 {
316 if (preg_match('%^PAGEN_(\d+)$%', $name, $m))
317 {
318 global $NavNum;
319 $NavNum = (int)$m[1] - 1;
320 return;
321 }
322 }
323 }
324 }
325
326 protected function getPaginationParams(&$params)
327 {
328 $params['DISPLAY_TOP_PAGER'] = isset($params['DISPLAY_TOP_PAGER']) && $params['DISPLAY_TOP_PAGER'] === 'Y';
329 $params['DISPLAY_BOTTOM_PAGER'] = !isset($params['DISPLAY_BOTTOM_PAGER']) || $params['DISPLAY_BOTTOM_PAGER'] !== 'N';
330 $params['LAZY_LOAD'] = isset($params['LAZY_LOAD']) && $params['LAZY_LOAD'] === 'Y' ? 'Y' : 'N';
331
332 if ($params['DISPLAY_TOP_PAGER'] || $params['DISPLAY_BOTTOM_PAGER'] || $params['LAZY_LOAD'] === 'Y')
333 {
334 \CPageOption::SetOptionString('main', 'nav_page_in_session', 'N');
335 $params['PAGER_TITLE'] = isset($params['PAGER_TITLE']) ? trim($params['PAGER_TITLE']) : '';
336 $params['PAGER_SHOW_ALWAYS'] = isset($params['PAGER_SHOW_ALWAYS']) && $params['PAGER_SHOW_ALWAYS'] === 'Y';
337 $params['PAGER_TEMPLATE'] = isset($params['PAGER_TEMPLATE']) ? trim($params['PAGER_TEMPLATE']) : '';
338 $params['PAGER_DESC_NUMBERING'] = isset($params['PAGER_DESC_NUMBERING']) && $params['PAGER_DESC_NUMBERING'] === 'Y';
339 $params['PAGER_DESC_NUMBERING_CACHE_TIME'] = (int)$params['PAGER_DESC_NUMBERING_CACHE_TIME'];
340 $params['PAGER_SHOW_ALL'] = isset($params['PAGER_SHOW_ALL']) && $params['PAGER_SHOW_ALL'] === 'Y';
341 $params['LOAD_ON_SCROLL'] = isset($params['LOAD_ON_SCROLL']) && $params['LOAD_ON_SCROLL'] === 'Y' ? 'Y' : 'N';
342 $params['MESS_BTN_LAZY_LOAD'] = isset($params['MESS_BTN_LAZY_LOAD']) ? trim($params['MESS_BTN_LAZY_LOAD']) : '';
343 }
344 else
345 {
346 $this->setPaginationMode(false);
347 $params['PAGER_SHOW_ALWAYS'] = false;
348 $params['PAGER_SHOW_ALL'] = false;
349 $params['LOAD_ON_SCROLL'] = 'N';
350 }
351 if ($params['LAZY_LOAD'] === 'Y' && $params['LOAD_ON_SCROLL'] === 'Y')
352 {
353 $params['DEFERRED_LOAD'] = isset($params['DEFERRED_LOAD']) && $params['DEFERRED_LOAD'] === 'Y' ? 'Y' : 'N';
354 }
355 else
356 {
357 $params['DEFERRED_LOAD'] = 'N';
358 }
359 }
360
361 protected function getSpecificIblockParams(&$params)
362 {
363 if ($this->isMultiIblockMode())
364 {
365 $parameters = $this->getMultiIblockParams($params);
366 }
367 else
368 {
369 $parameters = $this->getSingleIblockParams($params);
370 }
371
372 $this->storage['IBLOCK_PARAMS'] = $parameters;
373 }
374
381 protected function getMultiIblockParams(&$params)
382 {
383 $usePropertyFeatures = Iblock\Model\PropertyFeature::isEnabledFeatures();
384
385 $params['PROPERTY_CODE'] = array();
386 $params['CART_PROPERTIES'] = array();
387 $params['SHOW_PRODUCTS'] = $params['SHOW_PRODUCTS'] ?? array();
388
389 foreach ($params as $name => $prop)
390 {
391 $match = array();
392 if (preg_match('/^PROPERTY_CODE_(\d+)$/', $name, $match))
393 {
394 $iblockId = (int)$match[1];
395 if ($iblockId <= 0)
396 continue;
397
398 if (!empty($params[$name]) && is_array($params[$name]))
399 {
400 foreach ($params[$name] as $k => $v)
401 {
402 if ($v == '')
403 {
404 unset($params[$name][$k]);
405 }
406 }
407
408 $params['PROPERTY_CODE'][$iblockId] = $params[$name];
409 }
410 unset($params[$match[0]]);
411 }
412 elseif (preg_match('/^CART_PROPERTIES_(\d+)$/', $name, $match))
413 {
414 $iblockId = (int)$match[1];
415 if ($iblockId <= 0)
416 continue;
417
418 if (!empty($params[$name]) && is_array($params[$name]))
419 {
420 foreach ($params[$name] as $k => $v)
421 {
422 if ($v == '' || $v === '-')
423 {
424 unset($params[$name][$k]);
425 }
426 }
427 $params['CART_PROPERTIES'][$iblockId] = $params[$name];
428 }
429 unset($params[$match[0]]);
430 }
431 elseif (preg_match('/^OFFER_TREE_PROPS_(\d+)$/', $name, $match))
432 {
433 $iblockId = (int)$match[1];
434 if ($iblockId <= 0)
435 continue;
436
437 if (!empty($params[$name]) && is_array($params[$name]))
438 {
439 foreach ($params[$name] as $k => $v)
440 {
441 if ($v == '' || $v === '-')
442 {
443 unset($params[$name][$k]);
444 }
445 }
446
447 $params['OFFER_TREE_PROPS'][$iblockId] = $params[$name];
448 }
449 unset($params[$match[0]]);
450 }
451 elseif (preg_match('/^SHOW_PRODUCTS_(\d+)$/', $name, $match))
452 {
453 $iblockId = (int)$match[1];
454 if ($iblockId <= 0)
455 continue;
456
457 if ($params[$name] === 'Y')
458 {
459 $params['SHOW_PRODUCTS'][$iblockId] = true;
460 }
461
462 unset($params[$match[0]]);
463 }
464 unset($match);
465 }
466
467 $parameters = array();
468
469 if (!empty($params['SHOW_PRODUCTS']))
470 {
471 foreach (array_keys($params['SHOW_PRODUCTS']) as $iblockId)
472 {
473 $catalog = \CCatalogSku::GetInfoByProductIBlock($iblockId);
474
475 // product iblock parameters
476 $parameters[$iblockId] = array(
477 'PROPERTY_CODE' => $params['PROPERTY_CODE'][$iblockId] ?? array(),
478 'CART_PROPERTIES' => (!$usePropertyFeatures && isset($params['CART_PROPERTIES'][$iblockId])
479 ? $params['CART_PROPERTIES'][$iblockId]
480 : array()
481 )
482 );
483
484 // offers iblock parameters
485 if (!empty($catalog))
486 {
487 $parameters[$iblockId]['OFFERS_FIELD_CODE'] = array('ID', 'CODE', 'NAME', 'SORT', 'PREVIEW_PICTURE', 'DETAIL_PICTURE');
488 $parameters[$iblockId]['OFFERS_PROPERTY_CODE'] = $params['PROPERTY_CODE'][$catalog['IBLOCK_ID']] ?? array();
489 $parameters[$iblockId]['OFFERS_CART_PROPERTIES'] = (!$usePropertyFeatures && isset($params['CART_PROPERTIES'][$catalog['IBLOCK_ID']])
490 ? $params['CART_PROPERTIES'][$catalog['IBLOCK_ID']]
491 : array()
492 );
493 $parameters[$iblockId]['OFFERS_TREE_PROPS'] = (!$usePropertyFeatures && isset($params['OFFER_TREE_PROPS'][$catalog['IBLOCK_ID']])
494 ? $params['OFFER_TREE_PROPS'][$catalog['IBLOCK_ID']]
495 : []
496 );
497 }
498 }
499 }
500
501 return $parameters;
502 }
503
510 protected function getSingleIblockParams(&$params)
511 {
512 $usePropertyFeatures = Iblock\Model\PropertyFeature::isEnabledFeatures();
513
514 if (!isset($params['PROPERTY_CODE']) || !is_array($params['PROPERTY_CODE']))
515 {
516 $params['PROPERTY_CODE'] = array();
517 }
518
519 foreach ($params['PROPERTY_CODE'] as $k => $v)
520 {
521 if ($v == '')
522 {
523 unset($params['PROPERTY_CODE'][$k]);
524 }
525 }
526
527 if (!isset($params['OFFERS_FIELD_CODE']))
528 {
529 $params['OFFERS_FIELD_CODE'] = array();
530 }
531 elseif (!is_array($params['OFFERS_FIELD_CODE']))
532 {
533 $params['OFFERS_FIELD_CODE'] = array($params['OFFERS_FIELD_CODE']);
534 }
535
536 foreach ($params['OFFERS_FIELD_CODE'] as $key => $value)
537 {
538 if ($value == '')
539 {
540 unset($params['OFFERS_FIELD_CODE'][$key]);
541 }
542 }
543
544 if (!isset($params['OFFERS_PROPERTY_CODE']))
545 {
546 $params['OFFERS_PROPERTY_CODE'] = array();
547 }
548 elseif (!is_array($params['OFFERS_PROPERTY_CODE']))
549 {
550 $params['OFFERS_PROPERTY_CODE'] = array($params['OFFERS_PROPERTY_CODE']);
551 }
552
553 foreach ($params['OFFERS_PROPERTY_CODE'] as $key => $value)
554 {
555 if ($value == '')
556 {
557 unset($params['OFFERS_PROPERTY_CODE'][$key]);
558 }
559 }
560
561 $cartProperties = [];
562 $offersCartProperties = [];
563 $offersTreeProperties = [];
564 if (!$usePropertyFeatures)
565 {
566 if (!isset($params['PRODUCT_PROPERTIES']) || !is_array($params['PRODUCT_PROPERTIES']))
567 {
568 $params['PRODUCT_PROPERTIES'] = array();
569 }
570
571 foreach ($params['PRODUCT_PROPERTIES'] as $k => $v)
572 {
573 if ($v == '')
574 {
575 unset($params['PRODUCT_PROPERTIES'][$k]);
576 }
577 }
578 $cartProperties = $params['PRODUCT_PROPERTIES'];
579
580 if (!isset($params['OFFERS_CART_PROPERTIES']) || !is_array($params['OFFERS_CART_PROPERTIES']))
581 {
582 $params['OFFERS_CART_PROPERTIES'] = array();
583 }
584
585 foreach ($params['OFFERS_CART_PROPERTIES'] as $i => $pid)
586 {
587 if ($pid == '')
588 {
589 unset($params['OFFERS_CART_PROPERTIES'][$i]);
590 }
591 }
592 $offersCartProperties = $params['OFFERS_CART_PROPERTIES'];
593
594 if (!isset($params['OFFER_TREE_PROPS']))
595 {
596 $params['OFFER_TREE_PROPS'] = array();
597 }
598 elseif (!is_array($params['OFFER_TREE_PROPS']))
599 {
600 $params['OFFER_TREE_PROPS'] = array($params['OFFER_TREE_PROPS']);
601 }
602
603 foreach ($params['OFFER_TREE_PROPS'] as $key => $value)
604 {
605 $value = (string)$value;
606 if ($value == '' || $value === '-')
607 {
608 unset($params['OFFER_TREE_PROPS'][$key]);
609 }
610 }
611
612 if (empty($params['OFFER_TREE_PROPS']) && !empty($params['OFFERS_CART_PROPERTIES']))
613 {
614 $params['OFFER_TREE_PROPS'] = $params['OFFERS_CART_PROPERTIES'];
615 foreach ($params['OFFER_TREE_PROPS'] as $key => $value)
616 {
617 if ($value === '-')
618 {
619 unset($params['OFFER_TREE_PROPS'][$key]);
620 }
621 }
622 }
623 $offersTreeProperties = $params['OFFER_TREE_PROPS'];
624 }
625
626 return array(
627 $params['IBLOCK_ID'] => array(
628 'PROPERTY_CODE' => $params['PROPERTY_CODE'],
629 'CART_PROPERTIES' => $cartProperties,
630 'OFFERS_FIELD_CODE' => $params['OFFERS_FIELD_CODE'],
631 'OFFERS_PROPERTY_CODE' => $params['OFFERS_PROPERTY_CODE'],
632 'OFFERS_CART_PROPERTIES' => $offersCartProperties,
633 'OFFERS_TREE_PROPS' => $offersTreeProperties
634 )
635 );
636 }
637
642 protected function getProductIds()
643 {
644 if ($this->isEmptyStartLoad())
645 {
646 return [];
647 }
648 return parent::getProductIds();
649 }
650
654 protected function isEmptyStartLoad(): bool
655 {
656 return (
657 isset($this->arParams['LAZY_LOAD'])
658 && $this->arParams['LAZY_LOAD'] === 'Y'
659 && isset($this->arParams['LOAD_ON_SCROLL'])
660 && $this->arParams['LOAD_ON_SCROLL'] === 'Y'
661 && isset($this->arParams['DEFERRED_LOAD'])
662 && $this->arParams['DEFERRED_LOAD'] === 'Y'
663 );
664 }
665
666 // some logic of \CComponentAjax to execute in component_epilog
667 public function prepareLinks(&$data)
668 {
669 $addParam = \CAjax::GetSessionParam($this->arParams['AJAX_ID']);
670
671 $regexpLinks = '/(<a\s[^>]*?>.*?<\/a>)/is'.BX_UTF_PCRE_MODIFIER;
672 $regexpParams = '/([\w\-]+)\s*=\s*([\"\'])(.*?)\2/is'.BX_UTF_PCRE_MODIFIER;
673
674 $this->checkPcreLimit($data);
675 $arData = preg_split($regexpLinks, $data, -1, PREG_SPLIT_DELIM_CAPTURE);
676
677 $dataCount = count($arData);
678 if ($dataCount < 2)
679 return;
680
681 $ignoreAttributes = array(
682 'onclick' => true,
683 'target' => true
684 );
685 $search = array(
686 $addParam.'&',
687 $addParam,
688 'AJAX_CALL=Y&',
689 'AJAX_CALL=Y'
690 );
691 $dataChanged = false;
692
693 for ($i = 1; $i < $dataCount; $i += 2)
694 {
695 if (!preg_match('/^<a\s([^>]*?)>(.*?)<\/a>$/is'.BX_UTF_PCRE_MODIFIER, $arData[$i], $match))
696 continue;
697
698 $params = $match[1];
699
700 if (!preg_match_all($regexpParams, $params, $linkParams))
701 continue;
702
703 $strAdditional = ' ';
704 $urlKey = -1;
705 $ignoreLink = false;
706
707 foreach ($linkParams[0] as $key => $value)
708 {
709 if ($value == '')
710 continue;
711
712 $paramName = mb_strtolower($linkParams[1][$key]);
713
714 if ($paramName === 'href')
715 {
716 $urlKey = $key;
717 }
718 elseif (isset($ignoreAttributes[$paramName]))
719 {
720 $ignoreLink = true;
721 break;
722 }
723 else
724 {
725 $strAdditional .= $value.' ';
726 }
727 }
728
729 if ($urlKey >= 0 && !$ignoreLink)
730 {
731 $url = Text\Converter::getHtmlConverter()->decode($linkParams[3][$urlKey]);
732 $url = str_replace($search, '', $url);
733
734 if ($this->isAjaxURL($url))
735 {
736 $realUrl = $url;
737
738 $pos = mb_strpos($url, '#');
739 if ($pos !== false)
740 {
741 $realUrl = mb_substr($realUrl, 0, $pos);
742 }
743
744 $realUrl .= mb_strpos($url, '?') === false ? '?' : '&';
745 $realUrl .= $addParam;
746
747 $arData[$i] = \CAjax::GetLinkEx($realUrl, $url, $match[2], 'comp_'.$this->arParams['AJAX_ID'], $strAdditional);
748
749 $dataChanged = true;
750 }
751 }
752 }
753
754 if ($dataChanged)
755 {
756 $data = implode('', $arData);
757 }
758 }
759
760 private function checkPcreLimit($data)
761 {
762 $pcreBacktrackLimit = (int)ini_get('pcre.backtrack_limit');
763 $textLen = strlen($data);
764 $textLen++;
765
766 if ($pcreBacktrackLimit > 0 && $pcreBacktrackLimit < $textLen)
767 {
768 @ini_set('pcre.backtrack_limit', $textLen);
769 $pcreBacktrackLimit = intval(ini_get('pcre.backtrack_limit'));
770 }
771
772 return $pcreBacktrackLimit >= $textLen;
773 }
774
775 private function isAjaxURL($url)
776 {
777 if (preg_match('/^(#|mailto:|javascript:|callto:)/', $url))
778 return false;
779
780 if (mb_strpos($url, '://') !== false)
781 return false;
782
783 $url = preg_replace('/#.*/', '', $url);
784
785 if (mb_strpos($url, '?') !== false)
786 {
787 $url = mb_substr($url, 0, mb_strpos($url, '?'));
788 }
789
790 if (mb_substr($url, -4) != '.php')
791 {
792 if (mb_substr($url, -1) != '/')
793 {
794 $url .= '/';
795 }
796
797 $url .= 'index.php';
798 }
799
800 $currentUrl = $this->arParams['CURRENT_BASE_PAGE'];
801
802 if (mb_strpos($currentUrl, '?') !== false)
803 {
804 $currentUrl = mb_substr($currentUrl, 0, mb_strpos($currentUrl, '?'));
805 }
806
807 if (mb_substr($currentUrl, -4) != '.php')
808 {
809 if (mb_substr($currentUrl, -1) != '/')
810 {
811 $currentUrl .= '/';
812 }
813
814 $currentUrl .= 'index.php';
815 }
816
817 $currentUrlDirName = dirname($currentUrl);
818 $currentUrlBaseName = basename($currentUrl);
819 $dirName = dirname($url);
820
821 if (
822 ($dirName == $currentUrlDirName || $dirName == '' || $dirName == '.')
823 && basename($url) == $currentUrlBaseName
824 )
825 {
826 return true;
827 }
828
829 return false;
830 }
831
832 protected function initQueryFields()
833 {
834 parent::initQueryFields();
835 $this->initSubQuery();
836 }
837
838 protected function initSubQuery()
839 {
840 $this->storage['SUB_FILTER'] = array();
841
842 if (
843 $this->useCatalog
844 && !$this->isMultiIblockMode()
845 && $this->offerIblockExist($this->arParams['IBLOCK_ID'])
846 )
847 {
848 $catalogFilter = array();
849 foreach ($this->globalFilter as $key => $value)
850 {
851 if (\CProductQueryBuilder::isCatalogFilterField($key))
852 {
853 //TODO: remove this hack after new catalog.section filter
854 if ($key === '=PRODUCT_UF_PRODUCT_MAPPING')
855 {
856 continue;
857 }
858 $catalogFilter[$key] = $value;
859 unset($this->globalFilter[$key]);
860 }
861 }
862
863 $iblock = $this->storage['CATALOGS'][$this->arParams['IBLOCK_ID']];
864 $offersFilterExists = !empty($this->globalFilter['OFFERS']) && is_array($this->globalFilter['OFFERS']);
865
866 if ($offersFilterExists)
867 {
868 $this->storage['SUB_FILTER'] = array_merge($this->globalFilter['OFFERS'], $catalogFilter);
869 $this->storage['SUB_FILTER']['IBLOCK_ID'] = $iblock['IBLOCK_ID'];
870 $this->storage['SUB_FILTER']['ACTIVE_DATE'] = 'Y';
871 $this->storage['SUB_FILTER']['ACTIVE'] = 'Y';
872
873 if ($this->arParams['HIDE_NOT_AVAILABLE'] === 'Y')
874 {
875 $this->storage['SUB_FILTER']['AVAILABLE'] = 'Y';
876 }
877
878 $this->filterFields['=ID'] = \CIBlockElement::SubQuery(
879 'PROPERTY_'.$iblock['SKU_PROPERTY_ID'],
880 $this->storage['SUB_FILTER']
881 );
882 }
883 elseif (!empty($catalogFilter))
884 {
885 $this->storage['SUB_FILTER'] = $catalogFilter;
886 $this->storage['SUB_FILTER']['IBLOCK_ID'] = $iblock['IBLOCK_ID'];
887 $this->storage['SUB_FILTER']['ACTIVE_DATE'] = 'Y';
888 $this->storage['SUB_FILTER']['ACTIVE'] = 'Y';
889
890 $this->filterFields[] = array(
891 'LOGIC' => 'OR',
892 array($catalogFilter),
893 '=ID' => \CIBlockElement::SubQuery(
894 'PROPERTY_'.$iblock['SKU_PROPERTY_ID'],
895 $this->storage['SUB_FILTER']
896 ),
897 );
898 }
899 }
900 }
901
902 protected function getIblockElements($elementIterator)
903 {
904 $iblockElements = array();
905
906 if (!empty($elementIterator))
907 {
908 while ($element = $elementIterator->GetNext())
909 {
910 $this->processElement($element);
911 $iblockElements[$element['ID']] = $element;
912 }
913 }
914
915 return $iblockElements;
916 }
917
918 protected function modifyDisplayProperties($iblock, &$iblockElements)
919 {
920 if (!empty($iblockElements))
921 {
922 $iblockParams = $this->storage['IBLOCK_PARAMS'][$iblock];
923 $propertyCodes = $iblockParams['PROPERTY_CODE'];
924 $productProperties = $iblockParams['CART_PROPERTIES'];
925 $getPropertyCodes = !empty($propertyCodes);
926 $getProductProperties = $this->arParams['ADD_PROPERTIES_TO_BASKET'] === 'Y' && !empty($productProperties);
927 $getIblockProperties = $getPropertyCodes || $getProductProperties;
928
929 if ($getIblockProperties || ($this->useCatalog && $this->useDiscountCache))
930 {
931 $propFilter = array(
932 'ID' => array_keys($iblockElements),
933 'IBLOCK_ID' => $iblock
934 );
935 \CIBlockElement::GetPropertyValuesArray($iblockElements, $iblock, $propFilter);
936
937 if ($getPropertyCodes)
938 {
939 $propertyList = $this->getPropertyList($iblock, $propertyCodes);
940 }
941
942 foreach ($iblockElements as &$element)
943 {
944 if ($this->useCatalog && $this->useDiscountCache)
945 {
946 if ($this->storage['USE_SALE_DISCOUNTS'])
947 Catalog\Discount\DiscountManager::setProductPropertiesCache($element['ID'], $element["PROPERTIES"]);
948 else
949 \CCatalogDiscount::SetProductPropertiesCache($element['ID'], $element['PROPERTIES']);
950 }
951
952 if ($getIblockProperties)
953 {
954 if (!empty($propertyList))
955 {
956 foreach ($propertyList as $pid)
957 {
958 if (!isset($element['PROPERTIES'][$pid]))
959 continue;
960
961 $prop =& $element['PROPERTIES'][$pid];
962 $isArr = is_array($prop['VALUE']);
963 if (
964 ($isArr && !empty($prop['VALUE']))
965 || (!$isArr && (string)$prop['VALUE'] !== '')
967 )
968 {
969 $element['DISPLAY_PROPERTIES'][$pid] = \CIBlockFormatProperties::GetDisplayValue($element, $prop);
970 }
971 unset($prop);
972 }
973 unset($pid);
974 }
975
976 if ($getProductProperties)
977 {
978 $element['PRODUCT_PROPERTIES'] = \CIBlockPriceTools::GetProductProperties(
979 $iblock,
980 $element['ID'],
981 $productProperties,
982 $element['PROPERTIES']
983 );
984
985 if (!empty($element['PRODUCT_PROPERTIES']))
986 {
987 $element['PRODUCT_PROPERTIES_FILL'] = \CIBlockPriceTools::getFillProductProperties($element['PRODUCT_PROPERTIES']);
988 }
989 }
990 }
991 }
992 unset($element);
993
994 \CIBlockFormatProperties::clearCache();
996 }
997 }
998 }
999
1000 protected function getFilter()
1001 {
1002 $filterFields = parent::getFilter();
1003 $filterFields['ACTIVE'] = 'Y';
1004
1005 if ($this->arParams['HIDE_NOT_AVAILABLE'] === 'Y')
1006 {
1007 $filterFields['AVAILABLE'] = 'Y';
1008 }
1009
1010 if (!empty($this->arParams['CUSTOM_FILTER']))
1011 {
1012 $filterFields[] = $this->arParams['CUSTOM_FILTER'];
1013 }
1014
1015 if (!empty($this->arParams['FILTER_IDS']))
1016 {
1017 $filterFields['!ID'] = $this->arParams['FILTER_IDS'];
1018 }
1019
1020 return $filterFields;
1021 }
1022
1023 protected function getSort()
1024 {
1025 $sortFields = $this->getCustomSort();
1026 if (empty($sortFields))
1027 {
1028 if (
1029 (
1030 $this->isIblockCatalog
1031 || (
1032 $this->isMultiIblockMode()
1033 || (!$this->isMultiIblockMode() && $this->offerIblockExist($this->arParams['IBLOCK_ID']))
1034 )
1035 )
1036 && $this->arParams['HIDE_NOT_AVAILABLE'] === 'L'
1037 )
1038 {
1039 $sortFields['AVAILABLE'] = 'desc,nulls';
1040 }
1041
1042 $field = strtoupper($this->arParams['ELEMENT_SORT_FIELD']);
1043 if (!isset($sortFields[$field]))
1044 {
1045 $sortFields[$field] = $this->arParams['ELEMENT_SORT_ORDER'];
1046 }
1047
1048 $field = strtoupper($this->arParams['ELEMENT_SORT_FIELD2']);
1049 if (!isset($sortFields[$field]))
1050 {
1051 $sortFields[$field] = $this->arParams['ELEMENT_SORT_ORDER2'];
1052 }
1053 unset($field);
1054 if (!isset($sortFields['ID']))
1055 {
1056 $sortFields['ID'] = 'DESC';
1057 }
1058 }
1059
1060 return $sortFields;
1061 }
1062
1063 protected function getCustomSort(): array
1064 {
1065 $result = [];
1066
1067 if (!empty($this->arParams['CUSTOM_ELEMENT_SORT']) && is_array($this->arParams['CUSTOM_ELEMENT_SORT']))
1068 {
1069 foreach ($this->arParams['CUSTOM_ELEMENT_SORT'] as $field => $value)
1070 {
1071 $field = strtoupper($field);
1072 if (isset($result[$field]))
1073 {
1074 continue;
1075 }
1076 if ($field === 'ID' && !empty($value) && is_array($value))
1077 {
1078 Collection::normalizeArrayValuesByInt($value, false);
1079 if (empty($value))
1080 {
1081 continue;
1082 }
1083 }
1084 else
1085 {
1086 if (!is_string($value))
1087 {
1088 continue;
1089 }
1090 if (!preg_match(self::SORT_ORDER_MASK, $value))
1091 {
1092 continue;
1093 }
1094 }
1095
1096 $result[$field] = $value;
1097 }
1098 unset($field, $value);
1099 }
1100
1101 return $result;
1102 }
1103
1104 protected function getElementList($iblockId, $products)
1105 {
1106 // initialLoad case with only deferred bigData items
1107 if (is_array($this->navParams) && isset($this->navParams['nTopCount']) && $this->navParams['nTopCount'] == 0)
1108 {
1109 return false;
1110 }
1111
1112 $elementIterator = parent::getElementList($iblockId, $products);
1113
1114 if (!empty($elementIterator) && $this->isPaginationMode())
1115 {
1116 $this->initNavString($elementIterator);
1117 }
1118
1119 return $elementIterator;
1120 }
1121
1122 protected function initNavString(\CIBlockResult $elementIterator)
1123 {
1124 $navComponentParameters = array();
1125
1126 if ($this->arParams['PAGER_BASE_LINK_ENABLE'] === 'Y')
1127 {
1128 $pagerBaseLink = trim($this->arParams['PAGER_BASE_LINK']) ?: $this->arResult['SECTION_PAGE_URL'];
1129
1130 if ($this->pagerParameters && isset($this->pagerParameters['BASE_LINK']))
1131 {
1132 $pagerBaseLink = $this->pagerParameters['BASE_LINK'];
1133 unset($this->pagerParameters['BASE_LINK']);
1134 }
1135
1136 $navComponentParameters['BASE_LINK'] = \CHTTP::urlAddParams($pagerBaseLink, $this->pagerParameters, array('encode' => true));
1137 }
1138 else
1139 {
1140 $uri = new Main\Web\Uri($this->arParams['CURRENT_BASE_PAGE']);
1141 $uri->deleteParams(array(
1142 'PAGEN_'.$elementIterator->NavNum,
1143 'SIZEN_'.$elementIterator->NavNum,
1144 'SHOWALL_'.$elementIterator->NavNum,
1145 'PHPSESSID',
1146 'clear_cache',
1147 'bitrix_include_areas'
1148 ));
1149 $navComponentParameters['BASE_LINK'] = $uri->getUri();
1150 }
1151
1152 $this->arResult['NAV_STRING'] = $elementIterator->GetPageNavStringEx(
1153 $navComponentObject,
1154 $this->arParams['PAGER_TITLE'],
1155 $this->arParams['PAGER_TEMPLATE'],
1156 $this->arParams['PAGER_SHOW_ALWAYS'],
1157 $this,
1158 $navComponentParameters
1159 );
1160 $this->arResult['NAV_CACHED_DATA'] = null;
1161 $this->arResult['NAV_RESULT'] = $elementIterator;
1162 $this->arResult['NAV_PARAM'] = $navComponentParameters;
1163 }
1164
1165 protected function chooseOffer($offers, $iblockId)
1166 {
1167 if (empty($offers) || empty($this->storage['CATALOGS'][$iblockId]))
1168 return;
1169 $uniqueSortHash = array();
1170 $filteredOffers = array();
1171 $filteredElements = array();
1172 $filteredByProperty = $this->getFilteredOffersByProperty($iblockId);
1173
1174 if (!$this->isMultiIblockMode() && !empty($this->storage['SUB_FILTER']))
1175 {
1176 $catalog = $this->storage['CATALOGS'][$iblockId];
1177 $this->storage['SUB_FILTER']['=PROPERTY_'.$catalog['SKU_PROPERTY_ID']] = array_keys($this->elementLinks);
1178 $filteredOffers = Iblock\Component\Filters::getFilteredOffersByProduct(
1179 $catalog['IBLOCK_ID'],
1180 $catalog['SKU_PROPERTY_ID'],
1181 $this->storage['SUB_FILTER']
1182 );
1183 unset($catalog);
1184 }
1185
1186 foreach ($offers as &$offer)
1187 {
1188 $elementId = $offer['LINK_ELEMENT_ID'];
1189
1190 if (!isset($this->elementLinks[$elementId]))
1191 continue;
1192
1193 if (!isset($uniqueSortHash[$elementId]))
1194 {
1195 $uniqueSortHash[$elementId] = array();
1196 }
1197
1198 $uniqueSortHash[$elementId][$offer['SORT_HASH']] = true;
1199
1200 if ($this->elementLinks[$elementId]['OFFER_ID_SELECTED'] == 0 && $offer['CAN_BUY'])
1201 {
1202 if (isset($filteredOffers[$elementId]))
1203 {
1204 if (isset($filteredOffers[$elementId][$offer['ID']]))
1205 {
1206 $this->elementLinks[$elementId]['OFFER_ID_SELECTED'] = $offer['ID'];
1207 $filteredElements[$elementId] = true;
1208 }
1209 }
1210 elseif (isset($filteredByProperty[$elementId]))
1211 {
1212 if (isset($filteredByProperty[$elementId][$offer['ID']]))
1213 {
1214 $this->elementLinks[$elementId]['OFFER_ID_SELECTED'] = $offer['ID'];
1215 $filteredElements[$elementId] = true;
1216 }
1217 }
1218 else
1219 {
1220 $this->elementLinks[$elementId]['OFFER_ID_SELECTED'] = $offer['ID'];
1221 }
1222 }
1223 unset($elementId);
1224 }
1225
1226 if (!empty($filteredOffers))
1227 {
1228 $this->arResult['FILTERED_OFFERS_ID'] = array();
1229 }
1230
1231 foreach ($this->elementLinks as &$element)
1232 {
1233 if (isset($filteredOffers[$element['ID']]))
1234 {
1235 $this->arResult['FILTERED_OFFERS_ID'][$element['ID']] = $filteredOffers[$element['ID']];
1236 }
1237
1238 if ($element['OFFER_ID_SELECTED'] == 0 || isset($filteredElements[$element['ID']]))
1239 continue;
1240
1241 if (count($uniqueSortHash[$element['ID']]) < 2)
1242 {
1243 $element['OFFER_ID_SELECTED'] = 0;
1244 }
1245 }
1246 }
1247
1248 protected function getFilteredOffersByProperty($iblockId)
1249 {
1250 $offers = array();
1251 if (empty($this->storage['CATALOGS'][$iblockId]))
1252 return $offers;
1253
1254 if (!$this->isMultiIblockMode())
1255 {
1256 $filter = $this->getOffersPropFilter($this->arParams['CUSTOM_FILTER']);
1257 if (!empty($filter))
1258 {
1259 $catalog = $this->storage['CATALOGS'][$iblockId];
1260 $offers = Iblock\Component\Filters::getFilteredOffersByProduct(
1261 $catalog['IBLOCK_ID'],
1262 $catalog['SKU_PROPERTY_ID'],
1263 array(
1264 '=PROPERTY_'.$catalog['SKU_PROPERTY_ID'] => array_keys($this->elementLinks),
1265 $filter
1266 )
1267 );
1268 }
1269 }
1270
1271 return $offers;
1272 }
1273
1274 protected function getOffersPropFilter(array $level)
1275 {
1276 $filter = array();
1277 $checkLogic = true;
1278
1279 if (!empty($level))
1280 {
1281 foreach ($level as $prop)
1282 {
1283 if (is_array($prop))
1284 {
1285 $filter[] = $this->getOffersPropFilter($prop);
1286 }
1287 elseif ($prop instanceOf \CIBlockElement)
1288 {
1289 $checkLogic = false;
1290 $filter = $prop->arFilter;
1291 }
1292 }
1293
1294 if ($checkLogic && is_array($filter) && count($filter) > 1)
1295 {
1296 $filter['LOGIC'] = $level['LOGIC'];
1297 }
1298 }
1299
1300 return $filter;
1301 }
1302
1303 protected function getAdditionalCacheId()
1304 {
1305 return array(
1306 $this->globalFilter,
1307 $this->productIdMap,
1308 $this->arParams['CACHE_GROUPS'] === 'N' ? false : $this->getUserGroupsCacheId(),
1311 );
1312 }
1313
1314 protected function getComponentCachePath()
1315 {
1316 return '/'.$this->getSiteId().$this->getRelativePath();
1317 }
1318
1319 protected function makeOutputResult()
1320 {
1321 parent::makeOutputResult();
1322 $this->arResult['PRICES'] = $this->storage['PRICES'];
1323 $this->arResult['ITEMS'] = $this->elements;
1324 $this->arResult['ELEMENTS'] = array_keys($this->elementLinks);
1325 }
1326
1327 public function loadData()
1328 {
1329 $this->initNavParams();
1330 parent::loadData();
1331 }
1332
1333 protected function deferredLoadAction()
1334 {
1335 $this->prepareDeferredParams();
1336 parent::deferredLoadAction();
1337 }
1338
1339 protected function prepareDeferredParams()
1340 {
1341 $this->arParams['~PRODUCT_ROW_VARIANTS'] = $this->arParams['~DEFERRED_PRODUCT_ROW_VARIANTS'];
1342 $this->arParams['PRODUCT_ROW_VARIANTS'] = static::parseJsonParameter($this->arParams['~PRODUCT_ROW_VARIANTS']);
1343
1344 if (isset($this->arParams['PREDICT_ELEMENT_COUNT']) && $this->arParams['PREDICT_ELEMENT_COUNT'] === 'Y')
1345 {
1346 $this->arParams['PAGE_ELEMENT_COUNT'] = static::predictElementCountByVariants($this->arParams['PRODUCT_ROW_VARIANTS']);
1347 }
1348 else
1349 {
1350 $this->arParams['PAGE_ELEMENT_COUNT'] = $this->arParams['DEFERRED_PAGE_ELEMENT_COUNT'];
1351 }
1352
1353 $this->arParams['PAGE_ELEMENT_COUNT'] = (int)$this->arParams['PAGE_ELEMENT_COUNT'];
1354 }
1355
1359 protected function initNavParams()
1360 {
1361 if ($this->isPaginationMode())
1362 {
1363 if (
1364 $this->arParams['PAGE_ELEMENT_COUNT'] > 0
1365 && (
1366 $this->arParams['DISPLAY_TOP_PAGER']
1367 || $this->arParams['DISPLAY_BOTTOM_PAGER']
1368 || $this->arParams['LAZY_LOAD'] === 'Y'
1369 )
1370 )
1371 {
1372 $this->navParams = array(
1373 'nPageSize' => $this->arParams['PAGE_ELEMENT_COUNT'],
1374 'bDescPageNumbering' => $this->arParams['PAGER_DESC_NUMBERING'],
1375 'bShowAll' => $this->arParams['PAGER_SHOW_ALL']
1376 );
1377 $this->navigation = \CDBResult::GetNavParams($this->navParams);
1378
1379 if ($this->navigation['PAGEN'] == 0 && $this->arParams['PAGER_DESC_NUMBERING_CACHE_TIME'] > 0)
1380 {
1381 $this->arParams['CACHE_TIME'] = $this->arParams['PAGER_DESC_NUMBERING_CACHE_TIME'];
1382 }
1383 }
1384 else
1385 {
1386 $this->navParams = array(
1387 'nTopCount' => $this->arParams['PAGE_ELEMENT_COUNT'],
1388 'bDescPageNumbering' => $this->arParams['PAGER_DESC_NUMBERING'],
1389 );
1390 $this->navigation = false;
1391 }
1392 }
1393 else
1394 {
1395 $this->navParams = array('nTopCount' => $this->arParams['PAGE_ELEMENT_COUNT']);
1396 $this->navigation = false;
1397 }
1398 }
1399
1400 protected function prepareTemplateParams()
1401 {
1402 parent::prepareTemplateParams();
1403 $params =& $this->arParams;
1404
1405 if ($params['LINE_ELEMENT_COUNT'] < 2)
1406 {
1407 $params['LINE_ELEMENT_COUNT'] = 2;
1408 }
1409
1410 if ($params['LINE_ELEMENT_COUNT'] > 5)
1411 {
1412 $params['LINE_ELEMENT_COUNT'] = 5;
1413 }
1414
1415 if ($params['ADD_TO_BASKET_ACTION'] != 'BUY')
1416 {
1417 $params['ADD_TO_BASKET_ACTION'] = 'ADD';
1418 }
1419
1420 if (
1421 (empty($params['PRODUCT_ROW_VARIANTS']) || !is_array($params['PRODUCT_ROW_VARIANTS']))
1422 && isset($params['~PRODUCT_ROW_VARIANTS'])
1423 )
1424 {
1425 $params['PRODUCT_ROW_VARIANTS'] = static::parseJsonParameter($params['~PRODUCT_ROW_VARIANTS']);
1426 }
1427
1428 if (empty($params['PRODUCT_ROW_VARIANTS']))
1429 {
1430 $params['PRODUCT_ROW_VARIANTS'] = static::predictRowVariants($params['LINE_ELEMENT_COUNT'], $params['PAGE_ELEMENT_COUNT']);
1431 }
1432
1433 if (empty($params['PRODUCT_BLOCKS_ORDER']))
1434 {
1435 $params['PRODUCT_BLOCKS_ORDER'] = 'price,props,sku,quantityLimit,quantity,buttons';
1436 }
1437
1438 if (is_string($params['PRODUCT_BLOCKS_ORDER']))
1439 {
1440 $params['PRODUCT_BLOCKS_ORDER'] = explode(',', $params['PRODUCT_BLOCKS_ORDER']);
1441 }
1442
1443 $params['PRODUCT_DISPLAY_MODE'] = isset($params['PRODUCT_DISPLAY_MODE']) && $params['PRODUCT_DISPLAY_MODE'] === 'Y' ? 'Y' : 'N';
1444
1445 if ($this->isMultiIblockMode())
1446 {
1447 $this->getTemplateMultiIblockParams($params);
1448 }
1449 else
1450 {
1451 $this->getTemplateSingleIblockParams($params);
1452 }
1453 }
1454
1455 protected static function parseJsonParameter($jsonString)
1456 {
1457 $parameter = [];
1458
1459 if (!empty($jsonString) && is_string($jsonString))
1460 {
1461 try
1462 {
1463 $parameter = Json::decode(str_replace("'", '"', $jsonString));
1464 }
1465 catch (\Exception $e) {}
1466 }
1467
1468 return $parameter;
1469 }
1470
1476 protected function getTemplateMultiIblockParams(&$params)
1477 {
1478 $params['ADDITIONAL_PICT_PROP'] = array();
1479 $params['LABEL_PROP'] = array();
1480 $params['LABEL_PROP_MOBILE'] = array();
1481 $params['PROPERTY_CODE_MOBILE'] = array();
1482 $params['ENLARGE_PROP'] = array();
1483 $params['OFFER_TREE_PROPS'] = array();
1484
1485 foreach ($params as $name => $prop)
1486 {
1487 if (preg_match('/^ADDITIONAL_PICT_PROP_(\d+)$/', $name, $match))
1488 {
1489 $iblockId = (int)$match[1];
1490 if ($iblockId <= 0)
1491 continue;
1492
1493 if ($params[$name] != '' && $params[$name] != '-')
1494 {
1495 $params['ADDITIONAL_PICT_PROP'][$iblockId] = $params[$name];
1496 }
1497 unset($params[$match[0]]);
1498 }
1499 elseif (preg_match('/^LABEL_PROP_(\d+)$/', $name, $match))
1500 {
1501 $iblockId = (int)$match[1];
1502 if ($iblockId <= 0)
1503 continue;
1504
1505 if (!empty($params[$name]))
1506 {
1507 if (!is_array($params[$name]))
1508 {
1509 $params[$name] = array($params[$name]);
1510 }
1511
1512 foreach ($params[$name] as $k => $v)
1513 {
1514 if ($v == '')
1515 {
1516 unset($params[$name][$k]);
1517 }
1518 }
1519
1520 $params['LABEL_PROP'][$iblockId] = $params[$name];
1521 }
1522 }
1523 elseif (preg_match('/^LABEL_PROP_MOBILE_(\d+)$/', $name, $match))
1524 {
1525 $iblockId = (int)$match[1];
1526 if ($iblockId <= 0)
1527 continue;
1528
1529 if (!empty($params[$name]) && is_array($params[$name]))
1530 {
1531 foreach ($params[$name] as $k => $v)
1532 {
1533 if ($v == '')
1534 {
1535 unset($params[$name][$k]);
1536 }
1537 }
1538
1539 if (!empty($params[$name]))
1540 {
1541 $params[$name] = array_flip($params[$name]);
1542 }
1543
1544 $params['LABEL_PROP_MOBILE'][$iblockId] = $params[$name];
1545 }
1546 unset($params[$match[0]]);
1547 }
1548 elseif (preg_match('/^PROPERTY_CODE_MOBILE_(\d+)$/', $name, $match))
1549 {
1550 $iblockId = (int)$match[1];
1551 if ($iblockId <= 0)
1552 continue;
1553
1554 if (!empty($params[$name]) && is_array($params[$name]))
1555 {
1556 foreach ($params[$name] as $k => $v)
1557 {
1558 if ($v == '')
1559 {
1560 unset($params[$name][$k]);
1561 }
1562 }
1563
1564 if (!empty($params[$name]))
1565 {
1566 $params[$name] = array_flip($params[$name]);
1567 }
1568
1569 $params['PROPERTY_CODE_MOBILE'][$iblockId] = $params[$name];
1570 }
1571 unset($params[$match[0]]);
1572 }
1573 elseif (preg_match('/^ENLARGE_PROP_(\d+)$/', $name, $match))
1574 {
1575 $iblockId = (int)$match[1];
1576 if ($iblockId <= 0)
1577 continue;
1578
1579 if ($params[$name] != '' && $params[$name] != '-')
1580 {
1581 $params['ENLARGE_PROP'][$iblockId] = $params[$name];
1582 }
1583 unset($params[$match[0]]);
1584 }
1585 }
1586
1587 if (!empty($params['SHOW_PRODUCTS']))
1588 {
1589 $usePropertyFeatures = Iblock\Model\PropertyFeature::isEnabledFeatures();
1590
1591 foreach (array_keys($params['SHOW_PRODUCTS']) as $iblockId)
1592 {
1593 if (!isset($this->storage['IBLOCK_PARAMS'][$iblockId]) || !is_array($this->storage['IBLOCK_PARAMS'][$iblockId]))
1594 {
1595 $this->storage['IBLOCK_PARAMS'][$iblockId] = array();
1596 }
1597
1598 // product iblock parameters
1599 $this->storage['IBLOCK_PARAMS'][$iblockId]['ADD_PICT_PROP'] = $params['ADDITIONAL_PICT_PROP'][$iblockId] ?? '';
1600 $this->storage['IBLOCK_PARAMS'][$iblockId]['LABEL_PROP'] = $params['LABEL_PROP'][$iblockId] ?? array();
1601 $this->storage['IBLOCK_PARAMS'][$iblockId]['LABEL_PROP_MOBILE'] = $params['LABEL_PROP_MOBILE'][$iblockId] ?? array();
1602 $this->storage['IBLOCK_PARAMS'][$iblockId]['PROPERTY_CODE_MOBILE'] = $params['PROPERTY_CODE_MOBILE'][$iblockId] ?? array();
1603 $this->storage['IBLOCK_PARAMS'][$iblockId]['ENLARGE_PROP'] = $params['ENLARGE_PROP'][$iblockId] ?? '';
1604
1605 // offers iblock parameters
1606 $catalog = \CCatalogSku::GetInfoByProductIBlock($iblockId);
1607 if (!empty($catalog))
1608 {
1609 $this->storage['IBLOCK_PARAMS'][$iblockId]['OFFERS_ADD_PICT_PROP'] = $params['ADDITIONAL_PICT_PROP'][$catalog['IBLOCK_ID']] ?? '';
1610 }
1611 }
1612
1613 unset($usePropertyFeatures);
1614 }
1615 }
1616
1622 protected function getTemplateSingleIblockParams(&$params)
1623 {
1624 $params['ADD_PICT_PROP'] = isset($params['ADD_PICT_PROP']) ? trim($params['ADD_PICT_PROP']) : '';
1625 if ($params['ADD_PICT_PROP'] === '-')
1626 {
1627 $params['ADD_PICT_PROP'] = '';
1628 }
1629
1630 if (!isset($params['LABEL_PROP']) || !is_array($params['LABEL_PROP']))
1631 {
1632 $params['LABEL_PROP'] = array();
1633 }
1634
1635 if (!isset($params['LABEL_PROP_MOBILE']) || !is_array($params['LABEL_PROP_MOBILE']))
1636 {
1637 $params['LABEL_PROP_MOBILE'] = array();
1638 }
1639
1640 if (!empty($params['LABEL_PROP_MOBILE']))
1641 {
1642 $params['LABEL_PROP_MOBILE'] = array_flip($params['LABEL_PROP_MOBILE']);
1643 }
1644
1645 if (!isset($params['PROPERTY_CODE_MOBILE']) || !is_array($params['PROPERTY_CODE_MOBILE']))
1646 {
1647 $params['PROPERTY_CODE_MOBILE'] = array();
1648 }
1649
1650 if (!empty($params['PROPERTY_CODE_MOBILE']))
1651 {
1652 $params['PROPERTY_CODE_MOBILE'] = array_flip($params['PROPERTY_CODE_MOBILE']);
1653 }
1654
1655 $params['ENLARGE_PROP'] = isset($params['ENLARGE_PROP']) ? trim($params['ENLARGE_PROP']) : '';
1656 if ($params['ENLARGE_PROP'] === '-')
1657 {
1658 $params['ENLARGE_PROP'] = '';
1659 }
1660
1661 $params['OFFER_ADD_PICT_PROP'] = isset($params['OFFER_ADD_PICT_PROP']) ? trim($params['OFFER_ADD_PICT_PROP']) : '';
1662 if ($params['OFFER_ADD_PICT_PROP'] === '-')
1663 {
1664 $params['OFFER_ADD_PICT_PROP'] = '';
1665 }
1666
1667 if (!isset($this->storage['IBLOCK_PARAMS'][$params['IBLOCK_ID']]) || !is_array($this->storage['IBLOCK_PARAMS'][$params['IBLOCK_ID']]))
1668 {
1669 $this->storage['IBLOCK_PARAMS'][$params['IBLOCK_ID']] = array();
1670 }
1671
1672 $this->storage['IBLOCK_PARAMS'][$params['IBLOCK_ID']]['ADD_PICT_PROP'] = $params['ADD_PICT_PROP'];
1673 $this->storage['IBLOCK_PARAMS'][$params['IBLOCK_ID']]['LABEL_PROP'] = $params['LABEL_PROP'];
1674 $this->storage['IBLOCK_PARAMS'][$params['IBLOCK_ID']]['LABEL_PROP_MOBILE'] = $params['LABEL_PROP_MOBILE'];
1675 $this->storage['IBLOCK_PARAMS'][$params['IBLOCK_ID']]['PROPERTY_CODE_MOBILE'] = $params['PROPERTY_CODE_MOBILE'];
1676 $this->storage['IBLOCK_PARAMS'][$params['IBLOCK_ID']]['ENLARGE_PROP'] = $params['ENLARGE_PROP'];
1677 $this->storage['IBLOCK_PARAMS'][$params['IBLOCK_ID']]['OFFERS_ADD_PICT_PROP'] = $params['OFFER_ADD_PICT_PROP'];
1678 unset($skuTreeProperties);
1679 }
1680
1681 public static function getDefaultVariantId()
1682 {
1683 $variantId = 0;
1684 $templateVariantsMap = static::getTemplateVariantsMap();
1685
1686 if (!empty($templateVariantsMap))
1687 {
1688 foreach ($templateVariantsMap as $key => $variant)
1689 {
1690 if (isset($variant['DEFAULT']) && $variant['DEFAULT'] === 'Y')
1691 {
1692 $variantId = $variant['VARIANT'];
1693 break;
1694 }
1695 }
1696 }
1697
1698 return $variantId;
1699 }
1700
1701 public static function predictRowVariants($lineElementCount, $pageElementCount)
1702 {
1703 if ($pageElementCount <= 0)
1704 {
1705 return array();
1706 }
1707
1708 $templateVariantsMap = static::getTemplateVariantsMap();
1709
1710 if (empty($templateVariantsMap))
1711 {
1712 return array();
1713 }
1714
1715 $variantId = self::getDefaultVariantId();
1716
1717 foreach ($templateVariantsMap as $key => $variant)
1718 {
1719 if ($variant['COUNT'] == $lineElementCount && $variant['ENLARGED_POS'] === false)
1720 {
1721 $variantId = $key;
1722 break;
1723 }
1724 }
1725
1726 return array_fill(
1727 0,
1728 ceil($pageElementCount / $templateVariantsMap[$variantId]['COUNT']),
1729 array('VARIANT' => $variantId, 'BIG_DATA' => false)
1730 );
1731 }
1732
1733 protected function checkTemplateTheme()
1734 {
1735 parent::checkTemplateTheme();
1736
1737 if ($this->isPaginationMode())
1738 {
1739 if (isset($this->arResult['NAV_PARAM']) && is_array($this->arResult['NAV_PARAM']))
1740 {
1741 $this->arResult['NAV_PARAM']['TEMPLATE_THEME'] = $this->arParams['TEMPLATE_THEME'];
1742 }
1743
1744 if (!empty($this->arResult['NAV_RESULT']) && empty($this->arResult['NAV_STRING']))
1745 {
1747 $this->arResult['NAV_STRING'] = $this->arResult['NAV_RESULT']->GetPageNavStringEx(
1748 $navComponentObject,
1749 $this->arParams['PAGER_TITLE'],
1750 $this->arParams['PAGER_TEMPLATE'],
1751 $this->arParams['PAGER_SHOW_ALWAYS'],
1752 $this,
1753 $this->arResult['NAV_PARAM']
1754 );
1755 }
1756 }
1757 }
1758
1759 protected function getTemplateDefaultParams()
1760 {
1761 $defaultParams = parent::getTemplateDefaultParams();
1762 $defaultParams['PRODUCT_BLOCKS_ORDER'] = 'price,props,sku,quantity,buttons';
1763 $defaultParams['PRODUCT_ROW_VARIANTS'] = array();
1764 $defaultParams['PROPERTY_CODE_MOBILE'] = array();
1765 $defaultParams['SHOW_SLIDER'] = 'Y';
1766 $defaultParams['SLIDER_INTERVAL'] = 3000;
1767 $defaultParams['ENLARGE_PRODUCT'] = 'STRICT';
1768 $defaultParams['ENLARGE_PROP'] = '';
1769 $defaultParams['ADD_TO_BASKET_ACTION'] = 'ADD';
1770 $defaultParams['MESS_BTN_LAZY_LOAD'] = '';
1771
1772 return $defaultParams;
1773 }
1774
1775 protected function editTemplateData()
1776 {
1777 $this->arResult['CURRENCIES'] = $this->getTemplateCurrencies();
1778
1779 if (!empty($this->arResult['ITEMS']))
1780 {
1781 $this->arResult['DEFAULT_PICTURE'] = $this->getTemplateEmptyPreview();
1782 $this->arResult['SKU_PROPS'] = $this->getTemplateSkuPropList();
1783 $this->editTemplateItems($this->arResult['ITEMS']);
1785 }
1786
1787 $this->arResult['BIG_DATA'] = [];
1788 if ($this->request->getRequestMethod() === 'GET')
1789 {
1790 $this->arResult['BIG_DATA'] = $this->getBigDataInfo();
1791 }
1792 }
1793
1797 protected function sortItemsByTemplateVariants()
1798 {
1799 $rows = array();
1800 $variantsMap = static::getTemplateVariantsMap();
1801 $isBigData = $this->getAction() === 'bigDataLoad';
1802
1803 if ($this->arParams['ENLARGE_PRODUCT'] === 'PROP')
1804 {
1805 $enlargedIndexMap = $this->getEnlargedIndexMap();
1806 }
1807
1808 if (!empty($this->arParams['PRODUCT_ROW_VARIANTS']))
1809 {
1810 $showItems = false;
1811
1812 foreach ($this->arParams['PRODUCT_ROW_VARIANTS'] as $variant)
1813 {
1814 if (
1815 (!$isBigData && !$variant['BIG_DATA'])
1816 || ($isBigData && $variant['BIG_DATA'])
1817 )
1818 {
1819 $showItems = true;
1820 break;
1821 }
1822 }
1823 }
1824 else
1825 {
1826 $showItems = true;
1827 }
1828
1829 if ($showItems)
1830 {
1831 $variantParam = false;
1832 $itemsCounter = 0;
1833 $itemsLength = count($this->arResult['ITEMS']);
1834
1835 while (($itemsRemaining = $itemsLength - $itemsCounter) > 0)
1836 {
1837 if ($variantParam === false)
1838 {
1839 $variantParam = reset($this->arParams['PRODUCT_ROW_VARIANTS']);
1840 }
1841
1842 // skip big_data rows on initial load and not_big_data rows on deferred load
1843 if (!empty($variantParam))
1844 {
1845 if (
1846 $isBigData && !$variantParam['BIG_DATA']
1847 || !$isBigData && $variantParam['BIG_DATA']
1848 )
1849 {
1850 $variantParam = next($this->arParams['PRODUCT_ROW_VARIANTS']);
1851 // if last variant is not suitable - should reset again
1852 if ($variantParam === false)
1853 {
1854 $variantParam = reset($this->arParams['PRODUCT_ROW_VARIANTS']);
1855 }
1856
1857 if ($variantParam === false)
1858 break;
1859 else
1860 continue;
1861 }
1862 }
1863
1864 if (
1865 $variantParam === false
1866 || !isset($variantsMap[$variantParam['VARIANT']])
1867 || ($variantsMap[$variantParam['VARIANT']]['SHOW_ONLY_FULL'] && $variantsMap[$variantParam['VARIANT']]['COUNT'] > $itemsRemaining)
1868 )
1869 {
1870 // default variant
1871 $variant = $variantsMap[self::getDefaultVariantId()];
1872 }
1873 else
1874 {
1875 $variant = $variantsMap[$variantParam['VARIANT']];
1876 }
1877
1878 // sorting by property $arResult['ITEMS'] for proper elements enlarge
1879 if ($this->arParams['ENLARGE_PRODUCT'] === 'PROP' && $variant['ENLARGED_POS'] !== false)
1880 {
1881 if (!empty($enlargedIndexMap))
1882 {
1883 $overallPos = $itemsCounter + $variant['ENLARGED_POS'];
1884 $overallPosKey = array_search($overallPos, $enlargedIndexMap);
1885 if ($overallPosKey === false)
1886 {
1887 $closestPos = false;
1888 $closestPosKey = false;
1889 $enlargedPosInRange = array_intersect($enlargedIndexMap , range($itemsCounter, $itemsCounter + $variant['COUNT']));
1890
1891 if (!empty($enlargedPosInRange))
1892 {
1893 foreach ($enlargedPosInRange as $key => $posInRange)
1894 {
1895 if ($closestPos === false || abs($overallPos - $closestPos) > abs($posInRange - $overallPos))
1896 {
1897 $closestPos = $posInRange;
1898 $closestPosKey = $key;
1899 }
1900 }
1901
1902 $temporary = array($this->arResult['ITEMS'][$closestPos]);
1903 unset($this->arResult['ITEMS'][$closestPos], $enlargedIndexMap[$closestPosKey]);
1904 array_splice($this->arResult['ITEMS'], $overallPos, 0, $temporary);
1905 }
1906 }
1907 else
1908 {
1909 unset($enlargedIndexMap[$overallPosKey]);
1910 }
1911 }
1912 }
1913
1914 $rows[] = $variant;
1915 $itemsCounter += $variant['COUNT'];
1916 $variantParam = next($this->arParams['PRODUCT_ROW_VARIANTS']);
1917 }
1918 }
1919
1920 $this->arResult['ITEM_ROWS'] = $rows;
1921 }
1922
1928 protected function getBigDataInfo()
1929 {
1930 $rows = array();
1931 $count = 0;
1932 $rowsRange = array();
1933 $variantsMap = static::getTemplateVariantsMap();
1934
1935 if (!empty($this->arParams['PRODUCT_ROW_VARIANTS']))
1936 {
1937 foreach ($this->arParams['PRODUCT_ROW_VARIANTS'] as $key => $row)
1938 {
1939 if ($row['BIG_DATA'])
1940 {
1941 $rows[$key] = $row;
1942
1943 if (isset($variantsMap[$row['VARIANT']]))
1944 {
1945 $count += (int)$variantsMap[$row['VARIANT']]['COUNT'];
1946 }
1947
1948 $rowsRange[] = $count;
1949 }
1950 }
1951 }
1952
1953 $shownIds = array();
1954 if (!empty($this->elements))
1955 {
1956 foreach ($this->elements as $element)
1957 {
1958 $shownIds[] = $element['ID'];
1959 }
1960 }
1961
1962 return array(
1963 'enabled' => $count > 0,
1964 'rows' => $rows,
1965 'count' => $count,
1966 'rowsRange' => $rowsRange,
1967 'shownIds' => $shownIds,
1968 'js' => array(
1969 'cookiePrefix' => \COption::GetOptionString('main', 'cookie_name', 'BITRIX_SM'),
1970 'cookieDomain' => Main\Web\Cookie::getCookieDomain(),
1971 'serverTime' => $count > 0 ? time() : 0,
1972 ),
1973 'params' => $this->getBigDataServiceRequestParams(($this->arParams['RCM_TYPE'] ?? ''))
1974 );
1975 }
1976
1977 // getting positions of enlarged elements
1978 protected function getEnlargedIndexMap()
1979 {
1980 $enlargedIndexMap = array();
1981
1982 foreach ($this->arResult['ITEMS'] as $key => $item)
1983 {
1984 if ($item['ENLARGED'] === 'Y')
1985 {
1986 $enlargedIndexMap[] = $key;
1987 }
1988 }
1989
1990 return $enlargedIndexMap;
1991 }
1992
1993 public static function getTemplateVariantsMap()
1994 {
1995 return array(
1996 array(
1997 'VARIANT' => 0,
1998 'TYPE' => 'CARD',
1999 'COLS' => 1,
2000 'CLASS' => 'product-item-list-col-1',
2001 'CODE' => '1',
2002 'ENLARGED_POS' => false,
2003 'SHOW_ONLY_FULL' => false,
2004 'COUNT' => 1,
2005 'DEFAULT' => 'N'
2006 ),
2007 array(
2008 'VARIANT' => 1,
2009 'TYPE' => 'CARD',
2010 'COLS' => 2,
2011 'CLASS' => 'product-item-list-col-2',
2012 'CODE' => '2',
2013 'ENLARGED_POS' => false,
2014 'SHOW_ONLY_FULL' => false,
2015 'COUNT' => 2,
2016 'DEFAULT' => 'N'
2017 ),
2018 array(
2019 'VARIANT' => 2,
2020 'TYPE' => 'CARD',
2021 'COLS' => 3,
2022 'CLASS' => 'product-item-list-col-3',
2023 'CODE' => '3',
2024 'ENLARGED_POS' => false,
2025 'SHOW_ONLY_FULL' => false,
2026 'COUNT' => 3,
2027 'DEFAULT' => 'Y'
2028 ),
2029 array(
2030 'VARIANT' => 3,
2031 'TYPE' => 'CARD',
2032 'COLS' => 4,
2033 'CLASS' => 'product-item-list-col-4',
2034 'CODE' => '4',
2035 'ENLARGED_POS' => false,
2036 'SHOW_ONLY_FULL' => false,
2037 'COUNT' => 4,
2038 'DEFAULT' => 'N'
2039 ),
2040 array(
2041 'VARIANT' => 4,
2042 'TYPE' => 'CARD',
2043 'COLS' => 4,
2044 'CLASS' => 'product-item-list-col-1-4',
2045 'CODE' => '1-4',
2046 'ENLARGED_POS' => 0,
2047 'SHOW_ONLY_FULL' => false,
2048 'COUNT' => 5,
2049 'DEFAULT' => 'N'
2050 ),
2051 array(
2052 'VARIANT' => 5,
2053 'TYPE' => 'CARD',
2054 'COLS' => 4,
2055 'CLASS' => 'product-item-list-col-4-1',
2056 'CODE' => '4-1',
2057 'ENLARGED_POS' => 4,
2058 'SHOW_ONLY_FULL' => true,
2059 'COUNT' => 5,
2060 'DEFAULT' => 'N'
2061 ),
2062 array(
2063 'VARIANT' => 6,
2064 'TYPE' => 'CARD',
2065 'COLS' => 6,
2066 'CLASS' => 'product-item-list-col-6',
2067 'CODE' => '6',
2068 'ENLARGED_POS' => false,
2069 'SHOW_ONLY_FULL' => false,
2070 'COUNT' => 6,
2071 'DEFAULT' => 'N'
2072 ),
2073 array(
2074 'VARIANT' => 7,
2075 'TYPE' => 'CARD',
2076 'COLS' => 6,
2077 'CLASS' => 'product-item-list-col-1-6',
2078 'CODE' => '1-6',
2079 'ENLARGED_POS' => 0,
2080 'SHOW_ONLY_FULL' => false,
2081 'COUNT' => 7,
2082 'DEFAULT' => 'N'
2083 ),
2084 array(
2085 'VARIANT' => 8,
2086 'TYPE' => 'CARD',
2087 'COLS' => 6,
2088 'CLASS' => 'product-item-list-col-6-1',
2089 'CODE' => '6-1',
2090 'ENLARGED_POS' => 6,
2091 'SHOW_ONLY_FULL' => true,
2092 'COUNT' => 7,
2093 'DEFAULT' => 'N'
2094 ),
2095 array(
2096 'VARIANT' => 9,
2097 'TYPE' => 'LINE',
2098 'COLS' => 1,
2099 'CLASS' => 'product-item-line-list',
2100 'CODE' => 'line',
2101 'ENLARGED_POS' => false,
2102 'SHOW_ONLY_FULL' => false,
2103 'COUNT' => 1,
2104 'DEFAULT' => 'N'
2105 )
2106 );
2107 }
2108
2109 public function getTemplateSkuPropList()
2110 {
2111 $skuPropList = array();
2112
2113 if ($this->arResult['MODULES']['catalog'] && !empty($this->storage['IBLOCK_PARAMS']))
2114 {
2115 $elementIndex = array_keys($this->elements);
2116
2117 foreach ($this->storage['IBLOCK_PARAMS'] as $iblockId => $iblockParams)
2118 {
2119 $skuPropList[$iblockId] = array();
2120 $sku = \CCatalogSku::GetInfoByProductIBlock($iblockId);
2121 $boolSku = !empty($sku) && is_array($sku);
2122
2123 if ($boolSku && !empty($iblockParams['OFFERS_TREE_PROPS']) && $this->arParams['PRODUCT_DISPLAY_MODE'] === 'Y')
2124 {
2125 $skuPropList[$iblockId] = \CIBlockPriceTools::getTreeProperties(
2126 $sku,
2127 $iblockParams['OFFERS_TREE_PROPS'],
2128 array(
2129 'PICT' => $this->arResult['DEFAULT_PICTURE'],
2130 'NAME' => '-'
2131 )
2132 );
2133
2134 if (!empty($skuPropList[$iblockId]))
2135 {
2136 if (!empty($this->productWithOffers[$iblockId]))
2137 {
2138 $skuPropIds = array();
2139 foreach ($skuPropList[$iblockId] as $property)
2140 {
2141 $skuPropIds[$property['CODE']] = array(
2142 'ID' => $property['ID'],
2143 'CODE' => $property['CODE'],
2144 'PROPERTY_TYPE' => $property['PROPERTY_TYPE'],
2145 'USER_TYPE' => $property['USER_TYPE']
2146 );
2147 }
2148 unset($property);
2149
2150 $needValues = array();
2151 foreach ($elementIndex as $index)
2152 {
2153 if ($this->elements[$index]['IBLOCK_ID'] != $iblockId)
2154 continue;
2155 if ($this->elements[$index]['PRODUCT']['TYPE'] != Catalog\ProductTable::TYPE_SKU)
2156 continue;
2157 if (empty($this->elements[$index]['OFFERS']))
2158 continue;
2159 foreach ($this->elements[$index]['OFFERS'] as $offer)
2160 {
2161 foreach ($skuPropIds as $property)
2162 {
2163 if (isset($offer['DISPLAY_PROPERTIES'][$property['CODE']]))
2164 {
2165 if (!isset($needValues[$property['ID']]))
2166 $needValues[$property['ID']] = array();
2167 $valueId = ($property['PROPERTY_TYPE'] == Iblock\PropertyTable::TYPE_LIST
2168 ? $offer['DISPLAY_PROPERTIES'][$property['CODE']]['VALUE_ENUM_ID']
2169 : $offer['DISPLAY_PROPERTIES'][$property['CODE']]['VALUE']
2170 );
2171 $needValues[$property['ID']][$valueId] = $valueId;
2172 unset($valueId);
2173 }
2174 }
2175 unset($property);
2176 }
2177 unset($offer);
2178 }
2179 unset($index);
2180
2181 if (!empty($needValues))
2182 \CIBlockPriceTools::getTreePropertyValues($skuPropList[$iblockId], $needValues);
2183 unset($needValues);
2184
2185 unset($skuPropIds);
2186 }
2187 }
2188 else
2189 {
2190 $this->arParams['PRODUCT_DISPLAY_MODE'] = 'N';
2191 }
2192 }
2193 }
2194 }
2195
2196 return $skuPropList;
2197 }
2198
2199 protected function editTemplateItems(&$items)
2200 {
2201 $enableCompatible = $this->isEnableCompatible();
2202 foreach ($items as $key => &$item)
2203 {
2204 $iblockParams = $this->storage['IBLOCK_PARAMS'][$item['IBLOCK_ID']];
2205
2206 if (!isset($item['CATALOG_QUANTITY']))
2207 {
2208 $item['CATALOG_QUANTITY'] = 0;
2209 }
2210
2211 $item['CATALOG_QUANTITY'] = $item['CATALOG_QUANTITY'] > 0 && is_float($item['ITEM_MEASURE_RATIOS'][$item['ITEM_MEASURE_RATIO_SELECTED']]['RATIO'])
2212 ? (float)$item['CATALOG_QUANTITY']
2213 : (int)$item['CATALOG_QUANTITY'];
2214
2215 $item['CATALOG'] = false;
2216 $item['CATALOG_SUBSCRIPTION'] = ($item['CATALOG_SUBSCRIPTION'] ?? '') === 'Y' ? 'Y' : 'N';
2217
2218 $item['BIG_DATA'] = $this->getAction() === 'bigDataLoad';
2219
2220 \CIBlockPriceTools::getLabel($item, $iblockParams['LABEL_PROP']);
2221 $item['LABEL_PROP_MOBILE'] = $iblockParams['LABEL_PROP_MOBILE'];
2222 $item['PROPERTY_CODE_MOBILE'] = $iblockParams['PROPERTY_CODE_MOBILE'];
2223 static::checkEnlargedData($item, $iblockParams['ENLARGE_PROP']);
2224
2225 if ($this->arParams['SHOW_SLIDER'] === 'Y')
2226 {
2227 $this->editTemplateProductSlider($item, $item['IBLOCK_ID'], 5, true, array($this->arResult['DEFAULT_PICTURE']));
2228 }
2229
2230 $this->editTemplateProductPictures($item);
2231 $this->editTemplateCatalogInfo($item);
2232
2233 if ($item['CATALOG'] && !empty($item['OFFERS']))
2234 {
2235 if ($this->arParams['PRODUCT_DISPLAY_MODE'] === 'Y')
2236 {
2237 $this->editTemplateOfferProps($item);
2238 $this->editTemplateJsOffers($item);
2239 }
2240
2241 if ($this->arParams['CALCULATE_SKU_MIN_PRICE'] || $this->arParams['PRODUCT_DISPLAY_MODE'] !== 'Y')
2242 {
2243 $baseCurrency = '';
2244 if ($this->arResult['MODULES']['catalog'] && !isset($this->arResult['CONVERT_CURRENCY']['CURRENCY_ID']))
2245 {
2246 $baseCurrency = Currency\CurrencyManager::getBaseCurrency();
2247 }
2248
2249 $currency = $this->arResult['CONVERT_CURRENCY']['CURRENCY_ID'] ?? $baseCurrency;
2250
2251 $item['ITEM_START_PRICE'] = null;
2252 $item['ITEM_START_PRICE_SELECTED'] = null;
2253 if ($enableCompatible)
2254 $item['MIN_PRICE'] = false;
2255
2256 $minPrice = null;
2257 $minPriceIndex = null;
2258 foreach (array_keys($item['OFFERS']) as $index)
2259 {
2260 if (!$item['OFFERS'][$index]['CAN_BUY'] || $item['OFFERS'][$index]['ITEM_PRICE_SELECTED'] === null)
2261 continue;
2262
2263 $currentPrice = $item['OFFERS'][$index]['ITEM_PRICES'][$item['OFFERS'][$index]['ITEM_PRICE_SELECTED']];
2264 if ($currentPrice['CURRENCY'] != $currency)
2265 {
2266 $priceScale = \CCurrencyRates::ConvertCurrency(
2267 $currentPrice['RATIO_PRICE'],
2268 $currentPrice['CURRENCY'],
2269 $currency
2270 );
2271 }
2272 else
2273 {
2274 $priceScale = $currentPrice['RATIO_PRICE'];
2275 }
2276 if ($minPrice === null || $minPrice > $priceScale)
2277 {
2278 $minPrice = $priceScale;
2279 $minPriceIndex = $index;
2280 }
2281 unset($priceScale, $currentPrice);
2282 }
2283 unset($index);
2284
2285 if ($minPriceIndex !== null)
2286 {
2287 $minOffer = $item['OFFERS'][$minPriceIndex];
2288 $item['ITEM_START_PRICE_SELECTED'] = $minPriceIndex;
2289 $item['ITEM_START_PRICE'] = $minOffer['ITEM_PRICES'][$minOffer['ITEM_PRICE_SELECTED']];
2290 if ($enableCompatible)
2291 {
2292 $item['MIN_PRICE'] = array(
2293 'CATALOG_MEASURE_RATIO' => $minOffer['ITEM_MEASURE_RATIOS'][$minOffer['ITEM_MEASURE_RATIO_SELECTED']]['RATIO'],
2294 'CATALOG_MEASURE' => $minOffer['ITEM_MEASURE']['ID'],
2295 'CATALOG_MEASURE_NAME' => $minOffer['ITEM_MEASURE']['TITLE'],
2296 '~CATALOG_MEASURE_NAME' => $minOffer['ITEM_MEASURE']['~TITLE'],
2297 'VALUE' => $item['ITEM_START_PRICE']['RATIO_BASE_PRICE'],
2298 'DISCOUNT_VALUE' => $item['ITEM_START_PRICE']['RATIO_PRICE'],
2299 'PRINT_VALUE' => $item['ITEM_START_PRICE']['PRINT_RATIO_BASE_PRICE'],
2300 'PRINT_DISCOUNT_VALUE' => $item['ITEM_START_PRICE']['PRINT_RATIO_PRICE'],
2301 'DISCOUNT_DIFF' => $item['ITEM_START_PRICE']['RATIO_DISCOUNT'],
2302 'PRINT_DISCOUNT_DIFF' => $item['ITEM_START_PRICE']['PRINT_RATIO_DISCOUNT'],
2303 'DISCOUNT_DIFF_PERCENT' => $item['ITEM_START_PRICE']['PERCENT'],
2304 'CURRENCY' => $item['ITEM_START_PRICE']['CURRENCY']
2305 );
2306 }
2307 unset($minOffer);
2308 }
2309 unset($minPriceIndex, $minPrice);
2310
2311 unset($baseCurrency, $currency);
2312 }
2313 }
2314
2315 if (
2316 $this->arResult['MODULES']['catalog']
2317 && $item['CATALOG']
2318 && (
2319 $item['CATALOG_TYPE'] == Catalog\ProductTable::TYPE_PRODUCT
2320 || $item['CATALOG_TYPE'] == Catalog\ProductTable::TYPE_SET
2321 )
2322 )
2323 {
2324 if ($enableCompatible)
2325 {
2326 if ($item['ITEM_PRICE_SELECTED'] === null)
2327 {
2328 $item['RATIO_PRICE'] = null;
2329 $item['MIN_BASIS_PRICE'] = null;
2330 }
2331 else
2332 {
2333 $itemPrice = $item['ITEM_PRICES'][$item['ITEM_PRICE_SELECTED']];
2334 $item['RATIO_PRICE'] = array(
2335 'VALUE' => $itemPrice['RATIO_BASE_PRICE'],
2336 'DISCOUNT_VALUE' => $itemPrice['RATIO_PRICE'],
2337 'PRINT_VALUE' => $itemPrice['PRINT_RATIO_BASE_PRICE'],
2338 'PRINT_DISCOUNT_VALUE' => $itemPrice['PRINT_RATIO_PRICE'],
2339 'DISCOUNT_DIFF' => $itemPrice['RATIO_DISCOUNT'],
2340 'PRINT_DISCOUNT_DIFF' => $itemPrice['PRINT_RATIO_DISCOUNT'],
2341 'DISCOUNT_DIFF_PERCENT' => $itemPrice['PERCENT'],
2342 'CURRENCY' => $itemPrice['CURRENCY']
2343 );
2344 $item['MIN_BASIS_PRICE'] = array(
2345 'VALUE' => $itemPrice['BASE_PRICE'],
2346 'DISCOUNT_VALUE' => $itemPrice['PRICE'],
2347 'PRINT_VALUE' => $itemPrice['PRINT_BASE_PRICE'],
2348 'PRINT_DISCOUNT_VALUE' => $itemPrice['PRINT_PRICE'],
2349 'DISCOUNT_DIFF' => $itemPrice['DISCOUNT'],
2350 'PRINT_DISCOUNT_DIFF' => $itemPrice['PRINT_DISCOUNT'],
2351 'DISCOUNT_DIFF_PERCENT' => $itemPrice['PERCENT'],
2352 'CURRENCY' => $itemPrice['CURRENCY']
2353 );
2354 unset($itemPrice);
2355 }
2356 }
2357 }
2358
2359 if (!empty($item['DISPLAY_PROPERTIES']))
2360 {
2361 foreach ($item['DISPLAY_PROPERTIES'] as $propKey => $displayProp)
2362 {
2363 {
2364 if ($displayProp['PROPERTY_TYPE'] === 'F')
2365 {
2366 unset($item['DISPLAY_PROPERTIES'][$propKey]);
2367 }
2368 }
2369 }
2370 }
2371
2372 $item['LAST_ELEMENT'] = 'N';
2373 }
2374
2375 end($items);
2376 $items[key($items)]['LAST_ELEMENT'] = 'Y';
2377 }
2378
2379 protected function editTemplateProductPictures(&$item)
2380 {
2381 $iblockParams = $this->storage['IBLOCK_PARAMS'][$item['IBLOCK_ID']];
2382 $productPictures = \CIBlockPriceTools::getDoublePicturesForItem($item, $iblockParams['ADD_PICT_PROP']);
2383
2384 if (empty($productPictures['PICT']))
2385 {
2386 $productPictures['PICT'] = $this->arResult['DEFAULT_PICTURE'];
2387 }
2388
2389 if (empty($productPictures['SECOND_PICT']))
2390 {
2391 $productPictures['SECOND_PICT'] = $productPictures['PICT'];
2392 }
2393
2394 $item['PREVIEW_PICTURE'] = $productPictures['PICT'];
2395 $item['PREVIEW_PICTURE_SECOND'] = $productPictures['SECOND_PICT'];
2396 $item['SECOND_PICT'] = true;
2397 $item['PRODUCT_PREVIEW'] = $productPictures['PICT'];
2398 $item['PRODUCT_PREVIEW_SECOND'] = $productPictures['SECOND_PICT'];
2399 }
2400
2401 protected function editTemplateJsOffers(&$item)
2402 {
2403 $matrix = array();
2404 $boolSkuDisplayProperties = false;
2405 $intSelected = -1;
2406
2407 foreach ($item['OFFERS'] as $offerKey => $offer)
2408 {
2409 if ($item['OFFER_ID_SELECTED'] > 0)
2410 {
2411 $foundOffer = ($item['OFFER_ID_SELECTED'] == $offer['ID']);
2412 }
2413 else
2414 {
2415 $foundOffer = $offer['CAN_BUY'];
2416 }
2417
2418 if ($foundOffer && $intSelected == -1)
2419 {
2420 $intSelected = $offerKey;
2421 }
2422
2423 unset($foundOffer);
2424
2425 $skuProps = false;
2426 if (!empty($offer['DISPLAY_PROPERTIES']))
2427 {
2428 $boolSkuDisplayProperties = true;
2429 $skuProps = array();
2430 foreach ($offer['DISPLAY_PROPERTIES'] as $oneProp)
2431 {
2432 if ($oneProp['PROPERTY_TYPE'] === 'F')
2433 continue;
2434
2435 $skuProps[] = array(
2436 'CODE' => $oneProp['CODE'],
2437 'NAME' => $oneProp['NAME'],
2438 'VALUE' => $oneProp['DISPLAY_VALUE']
2439 );
2440 }
2441 unset($oneProp);
2442 }
2443
2444 $ratioSelectedIndex = $offer['ITEM_MEASURE_RATIO_SELECTED'];
2445 $oneRow = array(
2446 'ID' => $offer['ID'],
2447 'NAME' => ($offer['~NAME'] ?? ''),
2448 'TREE' => $offer['TREE'],
2449 'DISPLAY_PROPERTIES' => $skuProps,
2450
2451 // compatible prices
2452 'PRICE' => ($offer['RATIO_PRICE'] ?? $offer['MIN_PRICE'] ?? 0),
2453 'BASIS_PRICE' => ($offer['MIN_PRICE'] ?? 0),
2454
2455 // new prices
2456 'ITEM_PRICE_MODE' => $offer['ITEM_PRICE_MODE'],
2457 'ITEM_PRICES' => $offer['ITEM_PRICES'],
2458 'ITEM_PRICE_SELECTED' => $offer['ITEM_PRICE_SELECTED'],
2459 'ITEM_QUANTITY_RANGES' => $offer['ITEM_QUANTITY_RANGES'],
2460 'ITEM_QUANTITY_RANGE_SELECTED' => $offer['ITEM_QUANTITY_RANGE_SELECTED'],
2461 'ITEM_MEASURE_RATIOS' => $offer['ITEM_MEASURE_RATIOS'],
2462 'ITEM_MEASURE_RATIO_SELECTED' => $ratioSelectedIndex,
2463 'SECOND_PICT' => $offer['SECOND_PICT'],
2464 'OWNER_PICT' => $offer['OWNER_PICT'],
2465 'PREVIEW_PICTURE' => $offer['PREVIEW_PICTURE'],
2466 'PREVIEW_PICTURE_SECOND' => $offer['PREVIEW_PICTURE_SECOND'],
2467 'CHECK_QUANTITY' => $offer['CHECK_QUANTITY'],
2468 'MAX_QUANTITY' => $offer['PRODUCT']['QUANTITY'],
2469 'STEP_QUANTITY' => $offer['ITEM_MEASURE_RATIOS'][$ratioSelectedIndex]['RATIO'], // deprecated
2470 'QUANTITY_FLOAT' => is_float($offer['ITEM_MEASURE_RATIOS'][$ratioSelectedIndex]['RATIO']), //deprecated
2471 'MEASURE' => $offer['ITEM_MEASURE']['TITLE'],
2472 'CAN_BUY' => $offer['CAN_BUY'],
2473 'CATALOG_SUBSCRIBE' => $offer['PRODUCT']['SUBSCRIBE']
2474 );
2475 unset($ratioSelectedIndex);
2476
2477 if (isset($offer['MORE_PHOTO_COUNT']) && $offer['MORE_PHOTO_COUNT'] > 0)
2478 {
2479 $oneRow['MORE_PHOTO'] = $offer['MORE_PHOTO'];
2480 $oneRow['MORE_PHOTO_COUNT'] = $offer['MORE_PHOTO_COUNT'];
2481 }
2482
2483 $matrix[$offerKey] = $oneRow;
2484 }
2485
2486 if ($intSelected == -1)
2487 {
2488 $intSelected = 0;
2489 }
2490
2491 if (!$matrix[$intSelected]['OWNER_PICT'])
2492 {
2493 $item['PREVIEW_PICTURE'] = $matrix[$intSelected]['PREVIEW_PICTURE'];
2494 $item['PREVIEW_PICTURE_SECOND'] = $matrix[$intSelected]['PREVIEW_PICTURE_SECOND'];
2495 }
2496
2497 $item['JS_OFFERS'] = $matrix;
2498 $item['OFFERS_SELECTED'] = $intSelected;
2499 $item['OFFERS_PROPS_DISPLAY'] = $boolSkuDisplayProperties;
2500 }
2501
2502 protected function editTemplateOfferProps(&$item)
2503 {
2504 $matrix = array();
2505 $newOffers = array();
2506 $double = array();
2507 $item['OFFERS_PROP'] = false;
2508 $item['SKU_TREE_VALUES'] = array();
2509
2510 $iblockParams = $this->storage['IBLOCK_PARAMS'][$item['IBLOCK_ID']];
2511 $skuPropList = [];
2512 if (isset($this->arResult['SKU_PROPS'][$item['IBLOCK_ID']]))
2513 {
2514 $skuPropList = $this->arResult['SKU_PROPS'][$item['IBLOCK_ID']];
2515 }
2516 $skuPropIds = array_keys($skuPropList);
2517 $matrixFields = array_fill_keys($skuPropIds, false);
2518
2519 foreach ($item['OFFERS'] as $offerKey => $offer)
2520 {
2521 $offer['ID'] = (int)$offer['ID'];
2522
2523 if (isset($double[$offer['ID']]))
2524 continue;
2525
2526 $row = array();
2527 foreach ($skuPropIds as $code)
2528 {
2529 $row[$code] = $this->getTemplatePropCell($code, $offer, $matrixFields, $skuPropList);
2530 }
2531
2532 $matrix[$offerKey] = $row;
2533
2534 \CIBlockPriceTools::clearProperties($offer['DISPLAY_PROPERTIES'], $iblockParams['OFFERS_TREE_PROPS']);
2535 \CIBlockPriceTools::setRatioMinPrice($offer, false);
2536
2537 if ($this->arParams['SHOW_SLIDER'] === 'Y')
2538 {
2539 $this->editTemplateOfferSlider($offer, $item['IBLOCK_ID'], 5, true, $item['MORE_PHOTO']);
2540 }
2541
2542 $offerPictures = \CIBlockPriceTools::getDoublePicturesForItem($offer, $iblockParams['OFFERS_ADD_PICT_PROP']);
2543 $offer['OWNER_PICT'] = empty($offerPictures['PICT']);
2544 $offer['PREVIEW_PICTURE'] = false;
2545 $offer['PREVIEW_PICTURE_SECOND'] = false;
2546 $offer['SECOND_PICT'] = true;
2547
2548 if (!$offer['OWNER_PICT'])
2549 {
2550 if (empty($offerPictures['SECOND_PICT']))
2551 {
2552 $offerPictures['SECOND_PICT'] = $offerPictures['PICT'];
2553 }
2554
2555 $offer['PREVIEW_PICTURE'] = $offerPictures['PICT'];
2556 $offer['PREVIEW_PICTURE_SECOND'] = $offerPictures['SECOND_PICT'];
2557 }
2558
2559 if ($iblockParams['OFFERS_ADD_PICT_PROP'] != '' && isset($offer['DISPLAY_PROPERTIES'][$iblockParams['OFFERS_ADD_PICT_PROP']]))
2560 {
2561 unset($offer['DISPLAY_PROPERTIES'][$iblockParams['OFFERS_ADD_PICT_PROP']]);
2562 }
2563 $offer['TREE'] = [];
2564
2565 $double[$offer['ID']] = true;
2566 $newOffers[$offerKey] = $offer;
2567 }
2568
2569 $item['OFFERS'] = $newOffers;
2570
2571 $usedFields = array();
2572 $sortFields = array();
2573
2574 $matrixKeys = array_keys($matrix);
2575 foreach ($skuPropIds as $propCode)
2576 {
2577 $boolExist = $matrixFields[$propCode];
2578 foreach ($matrixKeys as $offerKey)
2579 {
2580 if ($boolExist)
2581 {
2582 $propId = $this->arResult['SKU_PROPS'][$item['IBLOCK_ID']][$propCode]['ID'];
2583 $value = $matrix[$offerKey][$propCode]['VALUE'];
2584
2585 if (!isset($item['SKU_TREE_VALUES'][$propId]))
2586 {
2587 $item['SKU_TREE_VALUES'][$propId] = array();
2588 }
2589
2590 $item['SKU_TREE_VALUES'][$propId][$value] = true;
2591 $item['OFFERS'][$offerKey]['TREE']['PROP_'.$propId] = $value;
2592 $item['OFFERS'][$offerKey]['SKU_SORT_'.$propCode] = $matrix[$offerKey][$propCode]['SORT'];
2593 $usedFields[$propCode] = true;
2594 $sortFields['SKU_SORT_'.$propCode] = SORT_NUMERIC;
2595 unset($value, $propId);
2596 }
2597 else
2598 {
2599 unset($matrix[$offerKey][$propCode]);
2600 }
2601 }
2602 unset($offerKey);
2603 }
2604 unset($propCode, $matrixKeys);
2605
2606 $item['OFFERS_PROP'] = $usedFields;
2607 $item['OFFERS_PROP_CODES'] = !empty($usedFields) ? base64_encode(serialize(array_keys($usedFields))) : '';
2608
2609 Collection::sortByColumn($item['OFFERS'], $sortFields);
2610 }
2611
2615 protected function initIblockPropertyFeatures()
2616 {
2617 if (!Iblock\Model\PropertyFeature::isEnabledFeatures())
2618 return;
2619
2620 foreach (array_keys($this->storage['IBLOCK_PARAMS']) as $iblockId)
2621 {
2622 $this->loadDisplayPropertyCodes($iblockId);
2623 $this->loadBasketPropertyCodes($iblockId);
2624 $this->loadOfferTreePropertyCodes($iblockId);
2625 }
2626 unset($iblockId);
2627 }
2628
2633 protected function loadDisplayPropertyCodes($iblockId)
2634 {
2635 $list = Iblock\Model\PropertyFeature::getListPageShowPropertyCodes(
2636 $iblockId,
2637 ['CODE' => 'Y']
2638 );
2639 if ($list === null)
2640 $list = [];
2641 $this->storage['IBLOCK_PARAMS'][$iblockId]['PROPERTY_CODE'] = $list;
2642 if ($this->useCatalog)
2643 {
2644 $list = Iblock\Model\PropertyFeature::getListPageShowPropertyCodes(
2645 $this->getOffersIblockId($iblockId),
2646 ['CODE' => 'Y']
2647 );
2648 if ($list === null)
2649 $list = [];
2650 $this->storage['IBLOCK_PARAMS'][$iblockId]['OFFERS_PROPERTY_CODE'] = $list;
2651 }
2652 unset($list);
2653 }
2654}
initNavString(\CIBlockResult $elementIterator)
static predictRowVariants($lineElementCount, $pageElementCount)
getElementList($iblockId, $products)
static predictElementCountByVariants($variants, $isBigData=false)
modifyDisplayProperties($iblock, &$iblockElements)
prepareElementSortRow(array $params, array $orderRow, array $default)
static isCheckboxProperty(array $property)
Definition tools.php:207
$GLOBALS['____1444769544']
Definition license.php:1