Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
component.php
1<?php
3
4use \Bitrix\Main\Localization\Loc;
5
6Loc::loadMessages(__FILE__);
7
9{
14 protected static $predefineForDynamicProps = array();
15
20 public static function getHandlerJS()
21 {
22 return 'BX.Landing.Node.Component';
23 }
24
30 public static function setPredefineForDynamicProps(array $additionalVals)
31 {
32 foreach ($additionalVals as $code => $val)
33 {
34 self::$predefineForDynamicProps[$code] = $val;
35 }
36 }
37
45 protected static function saveComponent($content, $code, array $params)
46 {
47 $components = \PHPParser::parseScript($content);
48 foreach ($components as $component)
49 {
50 // get first component with code = $code
51 if ($component['DATA']['COMPONENT_NAME'] == $code)
52 {
53 $params = array_merge($component['DATA']['PARAMS'], $params);
54 $componentCode = ($component['DATA']['VARIABLE'] ? $component['DATA']['VARIABLE'] . '=' : '') .
55 '$APPLICATION->IncludeComponent(' . PHP_EOL .
56 "\t" . '"' . $component['DATA']['COMPONENT_NAME'] . '", ' . PHP_EOL .
57 "\t" . '"' . $component['DATA']['TEMPLATE_NAME'] . '", ' . PHP_EOL .
58 "\t" . 'array(' . PHP_EOL .
59 "\t" . "\t" . \PHPParser::returnPHPStr2($params) . PHP_EOL .
60 "\t" . '),' . PHP_EOL .
61 "\t" . ($component['DATA']['PARENT_COMP'] ? $component['DATA']['PARENT_COMP'] : 'false') .
62 (!empty($component['DATA']['FUNCTION_PARAMS']) ? ',' . PHP_EOL .
63 "\t" . 'array(' . PHP_EOL . "\t" . "\t" . \PHPParser::returnPHPStr2($component['DATA']['FUNCTION_PARAMS']) . PHP_EOL .
64 "\t" . ')' : '') . PHP_EOL .
65 ');';
66 $componentCode = str_replace(array('<?', '?>'), array('< ?', '? >'), $componentCode);
67 $content = mb_substr($content, 0, $component['START']).$componentCode.mb_substr($content, $component['END']);
68 break;
69 }
70 }
71
72 return $content;
73 }
74
80 protected static function checkPhpCode($code)
81 {
82 if (is_array($code))
83 {
84 foreach ($code as $k => $v)
85 {
86 if (
87 self::checkPhpCode($k) ||
88 self::checkPhpCode($v)
89 )
90 {
91 return true;
92 }
93 }
94 }
95 else{
96 if (
97 mb_substr($code, 0, 2) == '={' &&
98 mb_substr($code, -1, 1) == '}' &&
99 mb_strlen($code) > 3
100 )
101 {
102 return true;
103 }
104 }
105
106 return false;
107 }
108
116 public static function saveNode(\Bitrix\Landing\Block $block, $selector, array $data)
117 {
118 //$data = array_pop($data);// we allow one type of component per block
119 $manifest = $block->getManifest();
120 if (isset($manifest['nodes'][$selector]['extra']))
121 {
122 $updateProps = array();
123 $allowedProps = $manifest['nodes'][$selector]['extra'];
124 foreach ($data as $code => $val)
125 {
126 if (isset($allowedProps[$code]))
127 {
128 $updateProps[$code] = self::transformPropValue(
129 $val,
130 $allowedProps[$code]
131 );
132 if (self::checkPhpCode(array($code => $updateProps[$code])))
133 {
134 unset($updateProps[$code]);
135 }
136 }
137 }
138 if (!empty($updateProps))
139 {
140 // !tmp bugfix about set section id to null
141 if (
142 array_key_exists('SECTION_ID', $updateProps) &&
143 !trim($updateProps['SECTION_ID'])
144 )
145 {
146 $updateProps['SECTION_ID'] = '={$sectionId}';
147 }
148 $doc = $block->getDom();
149 $newContent = self::saveComponent(
150 $doc->saveHTML(),
151 $selector,
152 $updateProps
153 );
154 // first clear dom
155 foreach ($doc->getChildNodesArray() as $node)
156 {
157 $node->getParentNode()->removeChild($node);
158 }
159 // and load new content
160 $doc->loadHTML($newContent);
161 }
162 }
163 }
164
172 public static function prepareManifest(\Bitrix\Landing\Block $block, array $manifest, array &$manifestFull = array())
173 {
174 if (
175 !isset($manifest['extra']['editable']) ||
176 !is_array($manifest['extra']['editable'])
177 )
178 {
179 return null;
180 }
181 else
182 {
183 $editable = $manifest['extra']['editable'];
184 }
185
186 if (
187 !isset($manifestFull['attrs']) ||
188 !is_array($manifestFull['attrs'])
189 )
190 {
191 $manifestFull['attrs'] = array();
192 }
193
194 if (
195 !isset($manifestFull['style']) ||
196 !is_array($manifestFull['style'])
197 )
198 {
199 $manifestFull['style'] = array();
200 }
201
202 $manifestFull['disableCache'] = true;
203 $manifest['allowInlineEdit'] = false;
204 $newExtra = array();
205 $originalStyleBlock = isset($manifestFull['style']['block'])
206 ? $manifestFull['style']['block']
207 : array();
208
209 // detect all components in text
210 $components = \PHPParser::parseScript($block->getContent());
211 $classBlock = $block->getBlockClass();
212 foreach ($components as $component)
213 {
214 foreach ($component['DATA']['PARAMS'] as $key => $param)
215 {
216 if (
217 is_string($param)
218 && stripos($param, '={$classBlock->get') !== false
219 && $value = $classBlock->get($key)
220 )
221 {
222 $component['DATA']['PARAMS'][$key] = $value;
223 }
224 }
225 $componentName = $manifest['code'];
226 // when found what need, get actually params from text and props description from component
227 if ($component['DATA']['COMPONENT_NAME'] == $componentName)
228 {
229 // collect props
230 $componentDesc = \CComponentUtil::GetComponentDescr(
231 $component['DATA']['COMPONENT_NAME']
232 );
233 $propsTemplate = @\CComponentUtil::GetTemplateProps(//@fixme
234 $component['DATA']['COMPONENT_NAME'],
235 $component['DATA']['TEMPLATE_NAME'],
236 '',
237 self::$predefineForDynamicProps
238 );
239 if (isset($propsTemplate['PARAMETERS']))
240 {
241 $propsTemplate = $propsTemplate['PARAMETERS'];
242 }
243 $props = @\CComponentUtil::getComponentProps(//@fixme
244 $component['DATA']['COMPONENT_NAME'],
245 self::$predefineForDynamicProps
246 );
247 if (isset($props['PARAMETERS']))
248 {
249 $props = $props['PARAMETERS'];
250 }
251 if (!empty($propsTemplate) && is_array($propsTemplate))
252 {
253 foreach ($propsTemplate as $code => $prop)
254 {
255 $props[$code] = $prop;
256 }
257 }
258 // style block
259 $styleAttrs = array();
260 if (
261 !isset($manifestFull['style']) ||
262 !is_array($manifestFull['style'])
263 )
264 {
265 $manifestFull['style'] = array(
266 'block' => array(),
267 'nodes' => array()
268 );
269 }
270 else if (!isset($manifestFull['style']['nodes']))
271 {
272 $manifestFull['style'] = array(
273 'nodes' => $manifestFull['style']
274 );
275 }
276 $manifestFull['style']['block'] = array_merge(array(
277 'name' => isset($componentDesc['NAME'])
278 ? $componentDesc['NAME']
279 : '',
280 'type' => 'box',
281 'additional' => array(
282 array(
283 'name' => Loc::getMessage('LANDING_NODE_CMP_STYLE_BLOCK'),
284 'attrs' => &$styleAttrs
285 )
286 )
287 ), $originalStyleBlock);
288 foreach ($editable as $field => $fieldItem)
289 {
290 if (isset($props[$field]))
291 {
292 // change node manifest
293 $newExtra[$field] = $props[$field];
294 $newExtra[$field]['VALUE'] = isset($component['DATA']['PARAMS'][$field])
295 ? $component['DATA']['PARAMS'][$field]
296 : '';
297 // add attr
298 if (!isset($manifestFull['attrs'][$componentName]))
299 {
300 $manifestFull['attrs'][$componentName] = array();
301 }
302 $propType = self::transformPropType(array(
303 'name' => isset($fieldItem['name'])
304 ? $fieldItem['name']
305 : $newExtra[$field]['NAME'],
306 'style' => isset($fieldItem['style'])
307 && $fieldItem['style'],
308 'original_type' => 'component',
309 'component_type' => isset($newExtra[$field]['TYPE'])
310 ? $newExtra[$field]['TYPE']
311 : '',
312 'attribute' => $field,
313 'value' => self::preparePropValue(
314 $newExtra[$field]['VALUE'],
315 $fieldItem
316 ),
317 //'original_value' => $newExtra[$field]['VALUE'],
318 'allowInlineEdit' => false
319 ) + $fieldItem, $newExtra[$field]);
320 $newExtra[$field]['ATTRIBUTE_TYPE'] = $propType['type'];
321 if ($propType['style'])
322 {
323 $propType['selector'] = $componentName;
324 $styleAttrs[] = $propType;
325 }
326 else
327 {
328 $manifestFull['attrs'][$componentName][] = $propType;
329 }
330 }
331 }
332 if (empty($styleAttrs))
333 {
334 if ($originalStyleBlock)
335 {
336 $manifestFull['style']['block'] = $originalStyleBlock;
337 }
338 else
339 {
340 unset($manifestFull['style']['block']);
341 }
342 }
343 // all right
344 if (!empty($newExtra))
345 {
346 $manifest['extra'] = $newExtra;
347 return $manifest;
348 }
349 }
350 }
351 return null;
352 }
353
360 protected static function transformPropType(array $item, $prop)
361 {
362 if (isset($prop['TYPE']))
363 {
364 if (
365 $prop['TYPE'] == 'CUSTOM' &&
366 isset($prop['JS_EVENT'])
367 )
368 {
369 $prop['TYPE'] = $prop['TYPE'] . '_' . $prop['JS_EVENT'];
370 }
371
372 switch ($prop['TYPE'])
373 {
374 case 'LIST':
375 {
376 $item['items'] = array();
377 if (isset($prop['MULTIPLE']) && $prop['MULTIPLE'] == 'Y')
378 {
379 $item['type'] = 'multiselect';
380 if (!is_array($item['value']))
381 {
382 $item['value'] = array($item['value']);
383 }
384 }
385 else
386 {
387 $prop['MULTIPLE'] = 'N';
388 $item['type'] = 'dropdown';
389 }
390 if (isset($prop['VALUES']) && is_array($prop['VALUES']))
391 {
392 foreach ($prop['VALUES'] as $code => $val)
393 {
394 $item['items'][] = array(
395 'name' => $val,
396 'value' => $code,
397 'selected' => (
398 $prop['MULTIPLE'] == 'Y' &&
399 in_array($code, $item['value'])
400 ) || $code == $item['value']
401 );
402 }
403 }
404 break;
405 }
406 case 'CHECKBOX':
407 {
408 $item['type'] = 'checkbox';
409 $item['items'] = array(
410 array(
411 'name' => $item['name'],
412 'value' => 'Y',
413 'checked' => $item['value'] == 'Y'
414 )
415 );
416 $item['compact'] = true;
417 unset($item['name']);
418 break;
419 }
420 case 'CUSTOM_initDraggableAddControl':
421 {
422 $item['type'] = 'catalog-view';
423 $item['items'] = array(
424 array('name' => '', 'image' => '/bitrix/images/landing/catalog_images/preset-1.svg', 'value' => '0'),
425 array('name' => '', 'image' => '/bitrix/images/landing/catalog_images/preset-2.svg', 'value' => '1'),
426 array('name' => '', 'image' => '/bitrix/images/landing/catalog_images/preset-3.svg', 'value' => '2'),
427 array('name' => '', 'image' => '/bitrix/images/landing/catalog_images/preset-4.svg', 'value' => '3'),
428 array('name' => '', 'image' => '/bitrix/images/landing/catalog_images/preset-1-4.svg', 'value' => '4'),
429 array('name' => '', 'image' => '/bitrix/images/landing/catalog_images/preset-4-1.svg', 'value' => '5'),
430 array('name' => '', 'image' => '/bitrix/images/landing/catalog_images/preset-6.svg', 'value' => '6'),
431 array('name' => '', 'image' => '/bitrix/images/landing/catalog_images/preset-1-6.svg', 'value' => '7'),
432 array('name' => '', 'image' => '/bitrix/images/landing/catalog_images/preset-6-1.svg', 'value' => '8'),
433 array('name' => '', 'image' => '/bitrix/images/landing/catalog_images/preset-line.svg', 'value' => '9')
434 );
435 $jsArray = \Cutil::jsObjectToPhp($item['value']);
436 $item['value'] = array();
437 if (is_array($jsArray))
438 {
439 foreach ($jsArray as $val)
440 {
441 if (isset($val['VARIANT']))
442 {
443 $item['value'][] = (int)$val['VARIANT'];
444 }
445 }
446 }
447 break;
448 }
449 case 'CUSTOM_initPositionControl':
450 {
451 $item['type'] = 'position';
452 $item['items'] = array(
453 'top-left' => array('content' => '', 'value' => 'top-left'),
454 'top-center' => array('content' => '', 'value' => 'top-center'),
455 'top-right' => array('content' => '', 'value' => 'top-right'),
456 'middle-left' => array('content' => '', 'value' => 'middle-left'),
457 'middle-center' => array('content' => '', 'value' => 'middle-center'),
458 'middle-right' => array('content' => '', 'value' => 'middle-right'),
459 'bottom-left' => array('content' => '', 'value' => 'bottom-left'),
460 'bottom-center' => array('content' => '', 'value' => 'bottom-center'),
461 'bottom-right' => array('content' => '', 'value' => 'bottom-right')
462 );
463 break;
464 }
465 case 'CUSTOM_initDraggableOrderControl':
466 {
467 $item['type'] = 'sortable-list';
468 $item['items'] = array();
469 if (!is_array($item['value']))
470 {
471 $item['value'] = explode(',', $item['value']);
472 }
473 $items = \Cutil::jsObjectToPhp($prop['JS_DATA']);
474 if (is_array($items))
475 {
476 foreach ($items as $code => $val)
477 {
478 $item['items'][] = array(
479 'name' => $val,
480 'value' => $code,
481 'preview' => '/bitrix/images/landing/catalog_images/preview/'.mb_strtolower($code) . '.svg?v3'
482 );
483 }
484 }
485 break;
486 }
487 default:
488 {
489 if (!isset($item['type']) || !$item['type'])
490 {
491 $item['type'] = 'text';
492 }
493 switch ($item['type'])
494 {
495 case 'url':
496 {
497 $item['disableBlocks'] = true;
498 break;
499 }
500 case 'filter':
501 {
502 ob_start();
503 $filterId = 'LANDING_FLT_' . $item['attribute'];
504 \Bitrix\Landing\Manager::getApplication()->includeComponent(
505 'bitrix:main.ui.filter',
506 '',
507 array(
508 'THEME' => \Bitrix\Main\UI\Filter\Theme::BORDER,
509 'FILTER_ID' => $filterId,
510 'FILTER' => isset($item['fields'])
511 ? $item['fields']
512 : array(),
513 'DISABLE_SEARCH' => true,
514 'ENABLE_LABEL' => true
515 )
516 );
517 $item['html'] = ob_get_clean();
518 $item['filterId'] = $filterId;
519 break;
520 }
521 default:
522 {
523 $item['placeholder'] = '';
524 }
525 }
526 break;
527 }
528 }
529 }
530
531 return $item;
532 }
533
540 protected static function preparePropValue($value, $prop)
541 {
542 if (isset($prop['type']))
543 {
544 switch ($prop['type'])
545 {
546 case 'url':
547 {
548 if ($value && isset($prop['entityType']))
549 {
550 // @todo: make this more universal
551 if (
552 $prop['entityType'] == 'element' &&
553 $value != '={$elementCode}' &&
554 $value != '={$elementId}'
555 )
556 {
557 $value = '#catalogElement' . $value;
558 }
559 else if (
560 $prop['entityType'] == 'section' &&
561 $value != '={$sectionCode}' &&
562 $value != '={$sectionId}'
563 )
564 {
565 $value = '#catalogSection' . $value;
566 }
567 }
568 }
569 }
570 }
571 return $value;
572 }
573
580 protected static function transformPropValue($value, $prop)
581 {
582 if (!is_array($value))
583 {
584 $value = \CUtil::jsObjectToPhp($value);
585 }
586
587 if (isset($prop['TYPE']))
588 {
589 if (
590 $prop['TYPE'] == 'CUSTOM' &&
591 isset($prop['JS_EVENT'])
592 )
593 {
594 $prop['TYPE'] = $prop['TYPE'] . '_' . $prop['JS_EVENT'];
595 }
596 if (
597 isset($prop['MULTIPLE']) &&
598 $prop['MULTIPLE'] == 'Y' &&
599 !is_array($value)
600 )
601 {
602 $value = array($value);
603 }
604
605 switch ($prop['TYPE'])
606 {
607 case 'CHECKBOX':
608 {
609 if (is_array($value))
610 {
611 $value = array_shift($value);
612 }
613 if ($value != 'Y')
614 {
615 $value = 'N';
616 }
617 break;
618 }
619 case 'CUSTOM_initDraggableAddControl':
620 {
621 $newValue = array();
622 if (is_array($value))
623 {
624 foreach ($value as $val)
625 {
626 $newValue[] = array(
627 'VARIANT' => $val,
628 'BIG_DATA' => false
629 );
630 }
631 }
632 $value = \CUtil::phpToJsObject($newValue);
633 break;
634 }
635 case 'CUSTOM_initDraggableOrderControl':
636 {
637 if (is_array($value))
638 {
639 $value = implode(',', $value);
640 }
641 break;
642 }
643 default:
644 {
645 if (isset($prop['ATTRIBUTE_TYPE']))
646 {
647 switch ($prop['ATTRIBUTE_TYPE'])
648 {
649 case 'url':
650 {
651 if (preg_match('/^#landing([\d]+)$/', $value, $matches))
652 {
653 $lansing = \Bitrix\Landing\Landing::createInstance($matches[1], [
654 'skip_blocks' => true
655 ]);
656 if ($lansing->exist())
657 {
658 $value = $lansing->getPublicUrl();
659 }
660 }
661 else if (preg_match('/^#catalog(Element|Section)([\d]+)$/', $value, $matches))
662 {
663 $value = $matches[2];
664 }
665 break;
666 }
667 }
668 }
669 }
670 }
671 }
672
673 return $value;
674 }
675
683 public static function getIblockURL($elementId, $urlType)
684 {
685 return \Bitrix\Landing\PublicAction\Utils::getIblockURL($elementId, $urlType);
686 }
687
694 public static function getIblockParams($key = false)
695 {
696 static $params = array();
697
698 if (empty($params))
699 {
700 $params['id'] = \Bitrix\Main\Config\Option::get('crm', 'default_product_catalog_id');
701 $params['type'] = 'CRM_PRODUCT_CATALOG';
702 $params['default_product'] = false;
703 }
704
705 if ($key === false)
706 {
707 return $params;
708 }
709 else
710 {
711 return isset($params[$key]) ? $params[$key] : null;
712 }
713 }
714
721 public static function getNode(\Bitrix\Landing\Block $block, $selector)
722 {
723 $data = array();
724 $manifest = $block->getManifest();
725
726 // gets common attrs
727 if (isset($manifest['attrs'][$selector]))
728 {
729 $allowedProps = $manifest['attrs'][$selector];
730 foreach ($allowedProps as $attr)
731 {
732 if (!self::checkPhpCode($attr['value']))
733 {
734 $data[$attr['attribute']] = $attr['value'];
735 }
736 }
737 }
738
739 // gets attrs from style block
740 if (
741 isset($manifest['style']['block']['additional']) &&
742 is_array($manifest['style']['block']['additional'])
743 )
744 {
745 foreach ($manifest['style']['block']['additional'] as $item)
746 {
747 if (
748 isset($item['attrs']) &&
749 is_array($item['attrs'])
750 )
751 {
752 foreach ($item['attrs'] as $attr)
753 {
754 if (!self::checkPhpCode($attr['value']))
755 {
756 $data[$attr['attribute']] = $attr['value'];
757 }
758 }
759 }
760 }
761 }
762
763 return $data;
764 }
765}
static getIblockParams($key=false)
static getIblockURL($elementId, $urlType)
static prepareManifest(\Bitrix\Landing\Block $block, array $manifest, array &$manifestFull=array())
static setPredefineForDynamicProps(array $additionalVals)
Definition component.php:30
static transformPropValue($value, $prop)
static preparePropValue($value, $prop)
static transformPropType(array $item, $prop)
static getNode(\Bitrix\Landing\Block $block, $selector)
static saveComponent($content, $code, array $params)
Definition component.php:45
static saveNode(\Bitrix\Landing\Block $block, $selector, array $data)
static loadMessages($file)
Definition loc.php:64
static getMessage($code, $replace=null, $language=null)
Definition loc.php:29