Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
landing.php
1<?php
2namespace Bitrix\Landing;
3
5use \Bitrix\Main\Application;
7use \Bitrix\Main\Event;
8use \Bitrix\Main\EventResult;
9use \Bitrix\Main\Page\Asset;
10use \Bitrix\Main\Localization\Loc;
11use \Bitrix\Main\ModuleManager;
12
13Loc::loadMessages(__FILE__);
14
16{
20 protected const META_KEYS = [
21 'CREATED_BY_ID', 'MODIFIED_BY_ID', 'DATE_CREATE',
22 'DATE_MODIFY', 'DATE_PUBLIC', 'INITIATOR_APP_CODE', 'VIEWS', 'TPL_CODE',
23 'ACTIVE', 'PUBLIC', 'SITE_CODE', 'SITE_SPECIAL', 'RULE',
24 'SITE_VERSION', 'SITE_LANG', 'SITE_TPL_CODE'
25 ];
26
30 protected const META_KEYS_MODIFIABLE = [
31 'DATE_MODIFY', 'DATE_PUBLIC', 'ACTIVE', 'PUBLIC'
32 ];
33
38 public static $internalClass = 'LandingTable';
39
44 protected static $enabledUpdate = true;
45
50 protected static $checkUniqueAddress = true;
51
56 protected static $checkDelete = true;
57
62 protected static $editMode = false;
63
68 protected static $previewMode = false;
69
74 protected static $variables = array();
75
80 protected static $dynamicFilterId = 0;
81
86 protected static $dynamicElementId = 0;
87
92 protected static $siteCode = '';
93
98 protected $mainInstance = true;
99
104 protected $metaData = array();
105
110 protected $blocks = array();
111
116 protected $id = 0;
117
122 protected $title = '';
123
128 protected $code = '';
129
134 protected $xmlId = '';
135
140 protected $siteRow = [];
141
146 protected $siteId = 0;
147
152 protected $siteTitle = '';
153
158 protected $domainId = 0;
159
164 protected $folderId = 0;
165
170 protected $tplId = 0;
171
176 protected $tplType = 'landing';
177
182 protected $active = false;
183
188 protected $error = null;
189
194 protected $rights = [];
195
200 protected $checkPermissions = true;
201
206 protected $version = 1;
207
212 protected $disableLinkPreview = false;
213
219 protected function __construct($id, $params = array())
220 {
221 $id = intval($id);
222 $this->error = new Error;
223 $filter = array(
224 'ID' => $id
225 );
226 if (
227 isset($params['force_deleted']) &&
228 $params['force_deleted'] === true
229 )
230 {
231 $filter['=DELETED'] = ['Y', 'N'];
232 $filter['=SITE.DELETED'] = ['Y', 'N'];
233 }
234 if (
235 isset($params['check_permissions']) &&
236 $params['check_permissions'] === false
237 )
238 {
239 $filter['CHECK_PERMISSIONS'] = 'N';
240 $this->checkPermissions = false;
241 }
242 if (
243 isset($params['disable_link_preview']) &&
244 $params['disable_link_preview'] === true
245 )
246 {
247 $this->disableLinkPreview = true;
248 }
249
250 if ($id)
251 {
252 $landing = self::getList(array(
253 'select' => array(
254 '*',
255 'SITE_TPL_ID' => 'SITE.TPL_ID',
256 'SITE_TPL_CODE' => 'SITE.TPL_CODE',
257 'SITE_CODE' => 'SITE.CODE',
258 'SITE_TYPE' => 'SITE.TYPE',
259 'SITE_SPECIAL' => 'SITE.SPECIAL',
260 'SITE_TITLE' => 'SITE.TITLE',
261 'SITE_VERSION' => 'SITE.VERSION',
262 'SITE_LANG' => 'SITE.LANG',
263 'DOMAIN_ID' => 'SITE.DOMAIN_ID',
264 'SITE_LANDING_ID_INDEX' => 'SITE.LANDING_ID_INDEX'
265 ),
266 'filter' => $filter
267 ))->fetch();
268 }
269 // check landing folder if exists
270 if (!empty($landing['FOLDER_ID']))
271 {
272 $breadCrumbs = Folder::getBreadCrumbs($landing['FOLDER_ID'], $landing['SITE_ID']);
273 foreach ($breadCrumbs as $crumb)
274 {
275 if ($crumb['DELETED'] === 'Y')
276 {
277 $id = 0;
278 break;
279 }
280 }
281 }
282 if ($id && isset($landing) && is_array($landing))
283 {
284 /*
285 * $this->getEditMode()
286 * @todo return if no access
287 */
288 // get base data
289 self::$siteCode = $landing['SITE_TYPE'];
290 $this->title = $landing['TITLE'];
291 $this->code = $landing['CODE'];
292 $this->xmlId = $landing['XML_ID'];
293 $this->id = (int)$landing['ID'];
294 $this->version = (int)$landing['VERSION'];
295 $this->siteId = (int)$landing['SITE_ID'];
296 $this->siteTitle = $landing['SITE_TITLE'];
297 $this->domainId = (int)$landing['DOMAIN_ID'];
298 $this->folderId = (int)$landing['FOLDER_ID'];
299 $this->active = $landing['ACTIVE'] == 'Y';
300 if ($this->checkPermissions)
301 {
302 $this->rights = Rights::getOperationsForSite(
303 $this->siteId
304 );
305 }
306 $this->siteRow = [
307 'TPL_ID' => $landing['SITE_TPL_ID'],
308 'LANDING_ID_INDEX' => $landing['SITE_LANDING_ID_INDEX']
309 ];
310 $this->tplId = $landing['TPL_ID'] > 0
311 ? $landing['TPL_ID']
312 : (
313 $landing['SITE_TPL_ID'] > 0
314 ? $landing['SITE_TPL_ID']
315 : 0
316 );
317 if (isset($params['is_area']) && $params['is_area'])
318 {
319 $this->mainInstance = false;
320 }
321 if ($landing['SITE_TPL_ID'] > 0 && !$landing['TPL_ID'])
322 {
323 $this->tplType = 'site';
324 }
325 // if edit mode - create copy for edit
326 if ($this->getEditMode()/* && $landing['PUBLIC'] == 'Y'*/)
327 {
328 Block::cloneForEdit($this);
329 }
330 // some update if we need
331 $this->updateVersion();
332 // get available blocks
333 if (
334 !isset($params['skip_blocks']) ||
335 $params['skip_blocks'] !== true
336 )
337 {
338 Block::fillLanding(
339 $this,
340 isset($params['blocks_limit']) ? $params['blocks_limit'] : 0,
341 array(
342 'id' => isset($params['blocks_id']) ? $params['blocks_id'] : 0,
343 'deleted' => isset($params['deleted']) && $params['deleted'] === true
344 )
345 );
346 }
347 // fill meta data
348 foreach (self::META_KEYS as $key)
349 {
350 $this->metaData[$key] = $landing[$key];
351 }
352 }
353 // landing not found
354 else
355 {
356 $this->error->addError(
357 'LANDING_NOT_EXIST',
358 Loc::getMessage('LANDING_NOT_FOUND')
359 );
360 $this->title = Loc::getMessage('LANDING_TITLE_NOT_FOUND');
361 }
362 }
363
369 public function setMetaData(array $metaData): void
370 {
371 foreach ($metaData as $key => $value)
372 {
373 if (in_array($key, self::META_KEYS_MODIFIABLE, true))
374 {
375 $this->metaData[$key] = $value;
376 }
377 }
378 }
379
386 public static function ping($id, $deleted = false)
387 {
388 $returnCheckDelete = false;
389 $filter = [
390 'ID' => $id
391 ];
392
393 if ($deleted)
394 {
395 if (self::$checkDelete)
396 {
397 $returnCheckDelete = true;
398 self::$checkDelete = false;
399 }
400 $filter['=DELETED'] = ['Y', 'N'];
401 }
402
403 $check = self::getList([
404 'select' => [
405 'ID'
406 ],
407 'filter' => $filter
408 ]);
409
410 if ($returnCheckDelete)
411 {
412 self::$checkDelete = true;
413 }
414
415 return (boolean) $check->fetch();
416 }
417
423 public static function setEditMode($mode = true)
424 {
425 self::$editMode = (boolean) $mode;
426 }
427
432 public static function getEditMode()
433 {
434 return self::$editMode;
435 }
436
442 public static function setPreviewMode($mode = true)
443 {
444 self::$previewMode = (boolean) $mode;
445 }
446
451 public static function getPreviewMode()
452 {
453 return self::$previewMode;
454 }
455
460 public static function checkDeleted()
461 {
462 return self::$checkDelete;
463 }
464
469 public static function disableCheckDeleted()
470 {
471 self::$checkDelete = false;
472 }
473
478 public static function enableCheckDeleted()
479 {
480 self::$checkDelete = true;
481 }
482
487 public static function disableUpdate()
488 {
489 self::$enabledUpdate = false;
490 }
491
496 public static function enableUpdate()
497 {
498 self::$enabledUpdate = true;
499 }
500
505 public static function isCheckUniqueAddress(): bool
506 {
507 return self::$checkUniqueAddress;
508 }
509
514 public static function disableCheckUniqueAddress(): void
515 {
516 self::$checkUniqueAddress = false;
517 }
518
523 public static function enableCheckUniqueAddress(): void
524 {
525 self::$checkUniqueAddress = true;
526 }
527
534 public static function createInstance($id, array $params = array())
535 {
536 return new self($id, $params);
537 }
538
544 public static function markDelete(int $id): \Bitrix\Main\Result
545 {
547 {
548 $result = new \Bitrix\Main\Result;
549 $result->addError(
550 new \Bitrix\Main\Error(
551 Loc::getMessage('LANDING_BLOCK_UNABLE_DEL_INC'),
552 'UNABLE_DELETE_INCLUDE'
553 )
554 );
555 return $result;
556 }
557
558 $event = new Event('landing', 'onBeforeLandingRecycle', array(
559 'id' => $id,
560 'delete' => 'Y'
561 ));
562 $event->send();
563
564 foreach ($event->getResults() as $result)
565 {
566 if ($result->getType() == EventResult::ERROR)
567 {
568 $return = new \Bitrix\Main\Result;
569 foreach ($result->getErrors() as $error)
570 {
571 $return->addError(
572 $error
573 );
574 }
575 return $return;
576 }
577 }
578
579 if (($currentScope = Site\Type::getCurrentScopeId()))
580 {
581 Agent::addUniqueAgent('clearRecycleScope', [$currentScope]);
582 }
583
584 $landing = self::createInstance($id, ['skip_blocks' => true]);
585
586 $res = parent::update($id, array(
587 'DELETED' => 'Y'
588 ));
589
590 if ($res->isSuccess())
591 {
592 $landing->clearFolderIndex();
593 }
594
595 return $res;
596 }
597
598
604 public static function markUnDelete($id)
605 {
606 $id = intval($id);
607
608 $event = new Event('landing', 'onBeforeLandingRecycle', array(
609 'id' => $id,
610 'delete' => 'N'
611 ));
612 $event->send();
613
614 foreach ($event->getResults() as $result)
615 {
616 if ($result->getType() == EventResult::ERROR)
617 {
618 $return = new \Bitrix\Main\Result;
619 foreach ($result->getErrors() as $error)
620 {
621 $return->addError(
622 $error
623 );
624 }
625 return $return;
626 }
627 }
628
629 return parent::update($id, array(
630 'DELETED' => 'N'
631 ));
632 }
633
640 public static function delete($id, bool $forceDeleted = false): \Bitrix\Main\Result
641 {
642 $result = new \Bitrix\Main\Entity\DeleteResult();
643 $params = [];
644
645 if ($forceDeleted)
646 {
647 $params['force_deleted'] = true;
648 }
649
650 // first check
651 if (Rights::isOn())
652 {
653 foreach (['draft', 'public'] as $code)
654 {
655 self::setEditMode($code == 'draft');
656 $landing = self::createInstance($id, $params);
657 if ($landing->exist())
658 {
659 foreach ($landing->getBlocks() as $block)
660 {
661 if ($block->getAccess() < $block::ACCESS_X)
662 {
663 $result->addError(
664 new \Bitrix\Main\Error(
665 Loc::getMessage('LANDING_BLOCK_ACCESS_DENIED'),
666 'ACCESS_DENIED'
667 )
668 );
669 return $result;
670 }
671 }
672 }
673 else
674 {
675 if (!$landing->getError()->isEmpty())
676 {
677 $result->addError(
678 $landing->getError()->getErrors()[0]
679 );
680 }
681 return $result;
682 }
683 }
684 }
685
686 // delete blocks
687 $params['skip_blocks'] = true;
688 foreach (array('draft', 'public') as $code)
689 {
690 self::setEditMode($code == 'draft');
691 $landing = self::createInstance($id, $params);
692 if ($landing->exist())
693 {
694 Block::deleteAll($id);
697 }
698 }
699
700 $res = parent::delete($id);
701 if ($res->isSuccess())
702 {
703 $landing->clearFolderIndex();
704 }
705
706 return $res;
707 }
708
714 public static function getHooks($id)
715 {
717 {
718 return [];
719 }
720
721 return Hook::getForLanding($id);
722 }
723
729 public static function getAdditionalFields($id)
730 {
731 $fields = array();
732
733 // now we can get additional fields only from hooks
734 foreach (self::getHooks($id) as $hook)
735 {
736 $fields += $hook->getPageFields();
737 }
738
739 return $fields;
740 }
741
748 public static function getAdditionalFieldsAsArray(int $landingId, bool $skipEmpty = true): array
749 {
750 $hookFiles = Hook::HOOKS_CODES_FILES;
751 $fields = self::getAdditionalFields($landingId);
752
753 foreach ($fields as $key => $field)
754 {
755 $fields[$key] = $field->getValue();
756
757 if ($skipEmpty && !$fields[$key])
758 {
759 unset($fields[$key]);
760 continue;
761 }
762
763 if (in_array($key, $hookFiles))
764 {
765 $fields['~' . $key] = $fields[$key];
766 if (intval($fields[$key]) > 0)
767 {
768 $fields[$key] = File::getFilePath($fields[$key]);
769 }
770 }
771 }
772
773 return $fields;
774 }
775
782 public static function saveAdditionalFields($id, array $data)
783 {
784 // now we can get additional fields only from hooks
786 }
787
793 public static function setVariables(array $vars)
794 {
795 foreach ($vars as $code => $val)
796 {
797 self::$variables[$code] = $val;
798 }
799 }
800
805 public static function getVariables()
806 {
807 return self::$variables;
808 }
809
816 public static function setDynamicParams($filterId, $elementId)
817 {
818 self::$dynamicFilterId = $filterId;
819 self::$dynamicElementId = $elementId;
820 }
821
826 public static function getDynamicFilter()
827 {
828 static $filter = null;
829 if ($filter === null)
830 {
831 $filter = Source\FilterEntity::getFilter(
832 self::$dynamicFilterId
833 );
834 }
835 return $filter;
836 }
837
842 public static function getDynamicElementId()
843 {
844 return self::$dynamicElementId;
845 }
846
851 public static function isDynamicDetailPage()
852 {
853 return self::$dynamicFilterId && self::$dynamicElementId;
854 }
855
863 public function getPreview(?int $id = null, bool $skipCloud = false, ?string $publicUrl = null): ?string
864 {
865 if (
866 !$skipCloud &&
867 Manager::isB24() &&
869 )
870 {
871 if (!$publicUrl)
872 {
873 $publicUrl = $this->getPublicUrl();
874 }
875 return rtrim($publicUrl, '/') . '/preview.jpg';
876 }
877
878 static $hookPics = null;
879
880 if ($hookPics === null)
881 {
882 $hookPics = Hook\Page\MetaOg::getAllImages();
883 }
884
885 if (!$id)
886 {
887 $id = $this->id;
888 }
889
890 if (isset($hookPics[$id]))
891 {
892 $pic = $hookPics[$id];
893 if (intval($pic) > 0)
894 {
895 $pic = File::getFilePath($pic);
896 }
897 return $pic;
898 }
899
900 return Manager::getUrlFromFile('/bitrix/images/landing/nopreview.jpg');
901 }
902
911 public function getPublicUrl($id = false, $absolute = true, $createPubPath = false, &$fullUrl = [])
912 {
913 if ($id === false)
914 {
915 $id = $this->id;
916 }
917
918 $previewMode = self::$previewMode && !$this->disableLinkPreview;
919 $siteKeyCode = Site\Type::getKeyCode();
920 $hostUrl = Domain::getHostUrl();
922 $bitrix24 = Manager::isB24();
923 $bitrix24originalVar = $bitrix24;
924 $disableCloud = Manager::isCloudDisable();
925 $domainDefault = null;
926 $data = array();
927 $res = Landing::getList(array(
928 'select' => array(
929 'ID',
930 'CODE',
931 'RULE',
932 'SITE_ID',
933 'FOLDER_ID',
934 'SITE_ID_INDEX' => 'SITE.LANDING_ID_INDEX',
935 'SITE_PROTOCOL' => 'SITE.DOMAIN.PROTOCOL',
936 'SITE_DOMAIN' => 'SITE.DOMAIN.DOMAIN',
937 'SITE_CODE' => 'SITE.CODE',
938 'SITE_TYPE' => 'SITE.TYPE',
939 'SITE_SMN_ID' => 'SITE.SMN_SITE_ID'
940 ),
941 'filter' => array(
942 'ID' => $id,
943 '=DELETED' => ['Y', 'N'],
944 'CHECK_PERMISSIONS' => 'N'
945 )
946 ));
947 while ($row = $res->fetch())
948 {
949 if ($row['SITE_TYPE'] == 'SMN')
950 {
951 $bitrix24 = false;
952 }
953 else
954 {
955 $bitrix24 = $bitrix24originalVar;
956 }
957 $domainReplace = false;
958 $row['SITE_ID_ORIG'] = $row['SITE_ID'];
959 // build site domain by default
960 if (!$row['SITE_DOMAIN'])
961 {
962 if (!$domainDefault)
963 {
964 $domainDefault = Domain::getList(array(
965 'filter' => array(
966 'ID' => Domain::getCurrentId()
967 )
968 ))->fetch();
969 }
970 if (isset($domainDefault['PROTOCOL']))
971 {
972 $row['SITE_PROTOCOL'] = $domainDefault['PROTOCOL'];
973 }
974 if (isset($domainDefault['DOMAIN']))
975 {
976 $row['SITE_DOMAIN'] = $domainDefault['DOMAIN'];
977 }
978 $domainReplace = true;
979 }
980 // force https
981 if (Manager::isHttps())
982 {
983 $row['SITE_PROTOCOL'] = 'https';
984 }
985 if ($domainReplace || !$bitrix24 || $disableCloud)
986 {
988 null,
989 $row['SITE_SMN_ID'] ? $row['SITE_SMN_ID'] : $siteId,
990 $createPubPath
991 );
992 $pubPath = rtrim($pubPath, '/');
993 }
994 // for create publication path
995 if (!ModuleManager::isModuleInstalled('bitrix24'))
996 {
998 null,
999 $row['SITE_SMN_ID'] ? $row['SITE_SMN_ID'] : $siteId,
1000 $createPubPath
1001 );
1002 }
1003 if (isset($row['SITE_ID']))
1004 {
1005 if ($siteKeyCode == 'CODE')
1006 {
1007 $row['SITE_ID'] = $row['SITE_CODE'];
1008 }
1009 else
1010 {
1011 $row['SITE_ID'] = '/' . $row['SITE_ID'] . '/';
1012 }
1013 }
1014 $publicHash = '';
1015 if ($previewMode)
1016 {
1017 if ($siteKeyCode == 'CODE')
1018 {
1019 $publicHash = Site::getPublicHash(trim($row['SITE_CODE'], '/'), $row['SITE_DOMAIN']);
1020 }
1021 else
1022 {
1023 $publicHash = Site::getPublicHash($row['SITE_ID_ORIG'], $row['SITE_DOMAIN']);
1024 }
1025 }
1026 if ($row['CODE'])
1027 {
1028 $row['CODE'] .= '/';
1029 }
1030 if ($disableCloud)
1031 {
1032 $lastFolderItem = [];
1033 $fullUrl[$row['ID']] = ($absolute ? $hostUrl : '') .
1034 $pubPath .
1035 ($bitrix24 ? $row['SITE_ID'] : '/') .
1036 ($previewMode ? 'preview/' . $publicHash . '/' : '') .
1037 ($row['FOLDER_ID'] ? ltrim(Folder::getFullPath($row['FOLDER_ID'], $row['SITE_ID_ORIG'], $lastFolderItem), '/') : '');
1038 $folderIndex = $row['ID'] == ($lastFolderItem['INDEX_ID'] ?? 0)
1039 ||
1040 !($lastFolderItem['INDEX_ID'] ?? 0)
1041 && ($row['CODE'] ?? null)
1042 && ($lastFolderItem['CODE'] ?? null)
1043 && trim($row['CODE'], '/') === $lastFolderItem['CODE']
1044 ;
1045 $data[$row['ID']] = $fullUrl[$row['ID']] .
1046 (($row['ID'] == $row['SITE_ID_INDEX'] || $folderIndex || $row['RULE']) ? '' : $row['CODE']);
1047 if (!$row['RULE'])
1048 {
1049 $fullUrl[$row['ID']] .= $row['CODE'];
1050 }
1051 }
1052 else
1053 {
1054 $lastFolderItem = [];
1055 $fullUrl[$row['ID']] = (
1056 $absolute
1057 ? (
1058 $row['SITE_PROTOCOL'] . '://' .
1059 $row['SITE_DOMAIN']
1060 )
1061 : ''
1062 ) .
1063 (($domainReplace || !$bitrix24) ? $pubPath : '') .
1064 (($previewMode && !$bitrix24) ? '/preview/' . $publicHash : '') .
1065 (($domainReplace && $bitrix24) ? $row['SITE_ID'] : '/') .
1066 (($previewMode && $bitrix24) ? 'preview/' . $publicHash . '/' : '') .
1067 ($row['FOLDER_ID'] ? ltrim(Folder::getFullPath($row['FOLDER_ID'], $row['SITE_ID_ORIG'], $lastFolderItem), '/') : '');
1068 $folderIndex = $row['ID'] == $lastFolderItem['INDEX_ID'] || !$lastFolderItem['INDEX_ID'] && trim($row['CODE'], '/') === $lastFolderItem['CODE'];
1069 $data[$row['ID']] = $fullUrl[$row['ID']] .
1070 (($row['ID'] == $row['SITE_ID_INDEX'] || $folderIndex || $row['RULE']) ? '' : $row['CODE']);
1071 if (!$row['RULE'])
1072 {
1073 $fullUrl[$row['ID']] .= $row['CODE'];
1074 }
1075 }
1076 }
1077
1078 if (is_array($id))
1079 {
1080 return $data;
1081 }
1082 elseif (!empty($data))
1083 {
1084 return array_pop($data);
1085 }
1086
1087 return false;
1088 }
1089
1096 public static function resolveIdByPublicUrl(string $landingUrl, int $siteId): ?int
1097 {
1098 if (Manager::isB24() && !Manager::isCloudDisable() && Site\Type::isPublicScope())
1099 {
1100 $landingUrl = rtrim(Manager::getPublicationPath($siteId), '/') . '/' . ltrim($landingUrl, '/');
1101 }
1102 $publicationPath = Manager::getPublicationPath();
1103 $componentName = 'bitrix:landing.pub';
1104 $className = \CBitrixComponent::includeComponentClass($componentName);
1105 $demoCmp = new $className;
1106 $demoCmp->initComponent($componentName);
1107 $demoCmp->arParams = [
1108 'PATH' => mb_substr($landingUrl, mb_strlen($publicationPath)),
1109 'DRAFT_MODE' => 'Y',
1110 'SITE_ID' => $siteId,
1111 'SITE_TYPE' => self::getSiteType(),
1112 'CHECK_PERMISSIONS' => 'N',
1113 'NOT_CHECK_DOMAIN' => 'Y',
1114 'NOT_SEND_HTTP_STATUS' => 'Y',
1115 'SKIP_404' => 'Y'
1116 ];
1117 return $demoCmp->detectPage() ?: null;
1118 }
1119
1125 public function view(array $params = array())
1126 {
1127 $blockEditMode = $this->getEditMode();
1128 $editMode = $this->mainInstance && $blockEditMode;
1129
1130 if (!isset($params['parse_link']))
1131 {
1132 $params['parse_link'] = true;
1133 }
1134
1135 if (!isset($params['apply_template']))
1136 {
1137 $params['apply_template'] = true;
1138 }
1139
1140 if (!isset($params['check_permissions']))
1141 {
1142 $params['check_permissions'] = true;
1143 }
1144
1145 if (!$params['check_permissions'])
1146 {
1148 }
1149
1150 // title
1151 if ($this->mainInstance)
1152 {
1154 \htmlspecialcharsbx($this->title)
1155 );
1156 }
1157
1158 // add chain item if need
1159 if ($this->mainInstance)
1160 {
1161 if ($this->folderId)
1162 {
1163 $chains = Folder::getBreadCrumbs($this->folderId, $this->siteId);
1164 foreach ($chains as $chain)
1165 {
1166 Manager::getApplication()->addChainItem(
1167 $chain['TITLE'],
1168 $chain['INDEX_ID'] ? '#landing' . $chain['INDEX_ID'] : '#'
1169 );
1170 }
1171 }
1172 else if (($this->siteRow['LANDING_ID_INDEX'] ?? 0) != $this->id)
1173 {
1174 Manager::getApplication()->addChainItem(
1175 $this->title,
1176 '#landing' . $this->id
1177 );
1178 }
1179 }
1180
1181 // assets
1182 if ($editMode)
1183 {
1184 $options = array(
1185 'site_id' => $this->siteId,
1186 'server_name' => $_SERVER['SERVER_NAME'],
1187 'xml_id' => $this->xmlId,
1188 'blocks' => Block::getRepository(),
1189 'style' => Block::getStyle(),
1190 'attrs' => Block::getAttrs(),
1191 'mainOptions' => [
1192 'saveOriginalFileName' => Option::get('main', 'save_original_file_name') === 'Y'
1193 ],
1194 );
1195 // event for redefine $options
1196 $event = new Event('landing', 'onLandingView', array(
1197 'options' => $options
1198 ));
1199 $event->send();
1200 foreach ($event->getResults() as $result)
1201 {
1202 if ($result->getResultType() != EventResult::ERROR)
1203 {
1204 if (($modified = $result->getModified()))
1205 {
1206 if (isset($modified['options']) && is_array($modified['options']))
1207 {
1208 $options = array_merge($options, $modified['options']);
1209 }
1210 }
1211 }
1212 }
1213 // output js
1214 Asset::getInstance()->addString(
1215 '<script type="text/javascript">' .
1216 'BX.ready(function(){'
1217 . 'if (typeof BX.Landing.Main !== "undefined")'
1218 . '{'
1219 . 'BX.Landing.Env.createInstance(' . \CUtil::phpToJSObject($options, false, false, true) . ');'
1220 . 'BX.Landing.Main.createInstance(' . $this->id . ');'
1221 . '}'
1222 . '});' .
1223 '</script>'
1224 );
1225 }
1226
1227 $content = '';
1228
1229 // templates part - first
1230 if ($params['apply_template'] && $this->mainInstance)
1231 {
1232 if (!TemplateRef::landingIsArea($this->id))
1233 {
1234 $content = $this->applyTemplate();
1235 }
1236 else
1237 {
1238 $content = '<div class="landing-main"' .
1239 ' data-site="' . $this->siteId . '"' .
1240 ' data-landing="' . $this->id . '">' .
1241 '#CONTENT#' .
1242 '</div>';
1243 }
1244 }
1245
1246 // then content
1247 ob_start();
1248 Landing\Seo::beforeLandingView();
1249 foreach ($this->blocks as $block)
1250 {
1251 $block->view($blockEditMode, $this);
1252 }
1253 Landing\Seo::afterLandingView();
1254 if ($this->mainInstance)
1255 {
1256 $this->execHooks();
1257 }
1258 $contentMain = ob_get_contents();
1259 ob_end_clean();
1260
1261 $replace = [];
1262
1263 if (!$content)
1264 {
1265 $content = $contentMain;
1266 }
1267
1268 if (mb_strpos($content, '#CONTENT#') !== false)
1269 {
1270 $replace['#CONTENT#'] = '<a id="workarea"></a>' . $contentMain;
1271 }
1272
1273 if (mb_strpos($content . $contentMain, '#crm') !== false)
1274 {
1275 $replace = array_merge($replace, Connector\Crm::getReplacesForContent($this->siteId, !$blockEditMode));
1276 }
1277
1278 if ($replace)
1279 {
1280 $content = str_replace(
1281 array_keys($replace),
1282 array_values($replace),
1283 $content
1284 );
1285 }
1286
1287 // breadcrumb (see chain_template.php in tpl) and title
1288 if (!$blockEditMode && $this->mainInstance)
1289 {
1290 ob_start();
1291 echo Manager::getApplication()->getNavChain(
1292 false, 0, false, true
1293 );
1294 $breadcrumb = ob_get_contents();
1295 ob_end_clean();
1296 $content = str_replace(
1297 array(
1298 '#breadcrumb#',
1299 '#title#'
1300 ),
1301 array(
1302 $breadcrumb,
1304 ),
1305 $content
1306 );
1307 }
1308
1309 // parse links between landings
1310 if ($params['parse_link'] === true && !$blockEditMode)
1311 {
1312 echo $this->parseLocalUrl($content);
1313 }
1314 else
1315 {
1316 echo $content;
1317 }
1318
1319 if (!$params['check_permissions'])
1320 {
1321 Rights::setOn();
1322 }
1323 }
1324
1329 public function getAreas()
1330 {
1331 if ($this->tplType == 'site')
1332 {
1333 return TemplateRef::getForSite($this->siteId);
1334 }
1335 else
1336 {
1337 return TemplateRef::getForLanding($this->id);
1338 }
1339 }
1340
1346 protected function applyTemplate($content = null)
1347 {
1348 if ($this->tplId)
1349 {
1350 $template = Template::getList(array(
1351 'filter' => array(
1352 'ID' => $this->tplId
1353 )
1354 ))->fetch();
1355 if ($template)
1356 {
1357 $editMode = $this->getEditMode();
1358 if ($template['XML_ID'] == 'empty')
1359 {
1360 $template['CONTENT'] = '<div class="landing-main">' .
1361 $template['CONTENT'] .
1362 '</div>';
1363 }
1364 if ($editMode)
1365 {
1366 $replace = array(
1367 '>#CONTENT#<' => ' data-site="' . $this->siteId .
1368 '" data-landing="' . $this->id .
1369 '">#CONTENT#<',
1370 '#CONTENT#' => $content ? $content : '#CONTENT#'
1371 );
1372 }
1373 else
1374 {
1375 $replace = array(
1376 '#CONTENT#' => $content ? $content : '#CONTENT#'
1377 );
1378 }
1379 // if areas exist, get landings
1380 if ($template['AREA_COUNT'] > 0)
1381 {
1382 foreach ($this->getAreas() as $area => $lid)
1383 {
1384 ob_start();
1385 $landing = self::createInstance($lid, array(
1386 'is_area' => true,
1387 'check_permissions' => false,
1388 'disable_link_preview' => $this->disableLinkPreview
1389 ));
1390 if ($landing->exist())
1391 {
1392 $landing->view();
1393 }
1394 if ($editMode)
1395 {
1396 $rights = Rights::getOperationsForSite($landing->getSiteId());
1397 $replace['>#AREA_' . $area . '#<'] = ' data-site="' . $landing->getSiteId() .
1398 '" data-landing="' . $lid .
1399 '" data-rights="' . implode(',', $rights) .
1400 '">#AREA_' . $area . '#<';
1401 }
1402 $replace['#AREA_' . $area . '#'] = ob_get_contents();
1403 ob_end_clean();
1404 }
1405 }
1406 $content = str_replace(
1407 array_keys($replace),
1408 array_values($replace),
1409 $template['CONTENT']
1410 );
1411 }
1412 }
1413 else if ($this->getEditMode())
1414 {
1415 if (!$content)
1416 {
1417 $content = '#CONTENT#';
1418 }
1419 $content = '<div class="landing-main" ' .
1420 'data-site="' . $this->siteId . '" ' .
1421 'data-landing="' . $this->id . '">' .
1422 $content .
1423 '</div>';
1424 }
1425
1426 return $content;
1427 }
1428
1434 protected function parseLocalUrl(string $content): string
1435 {
1436 $pattern = '/([",\'\;]{1})(page:|block:|user:)?#(landing|block|dynamic|user)([\d\_]+)\@{0,1}([^\'"]*)([",\'\&]{1})/is';
1437 $patternWithoutUser = '/([",\'\;]{1})(page:|block:)?#(landing|block|dynamic)([\d\_]+)\@{0,1}([^\'"]*)([",\'\&]{1})/is';
1438 static $isIframe = null;
1439
1440 if (!self::$editMode && $content)
1441 {
1442 $content = Subtype\Form::prepareFormsToView(
1443 $content
1444 );
1445 }
1446
1447 if ($isIframe === null)
1448 {
1449 $request = Application::getInstance()->getContext()->getRequest();
1450 $isIframe = $request->get('IFRAME') == 'Y';
1451 }
1452
1453 // replace catalog links in preview mode
1454 if (self::$previewMode)
1455 {
1456 $content = preg_replace_callback(
1457 '/href\="(product:)?#catalog(Element|Section)([\d]+)"/i',
1458 function($href)
1459 {
1460 return 'href="' . PublicAction\Utils::getIblockURL(
1461 $href[3],
1462 mb_strtolower($href[2])
1463 ) . '"';
1464 },
1465 $content);
1466 }
1467
1468 $replace = [];
1469
1470 // for form in frames we should insert hidden tag
1471 if ($isIframe)
1472 {
1473 $replace['</form>'] = '<input type="hidden" name="IFRAME" value="Y" /></form>';
1474 }
1475
1476 // fix breadcrumb navigation
1477 if ($this->siteRow['LANDING_ID_INDEX'] > 0)
1478 {
1479 $replace['#system_mainpage'] = '#landing' . $this->siteRow['LANDING_ID_INDEX'];
1480 }
1481
1482 if ($replace)
1483 {
1484 $content = str_replace(
1485 array_keys($replace),
1486 array_values($replace),
1487 $content
1488 );
1489 }
1490
1491 // replace in content
1492 if (preg_match_all($pattern, $content, $matches))
1493 {
1494 $urls = array(
1495 'LANDING' => array(),
1496 'BLOCK' => array(),
1497 'USER' => array(),
1498 'DYNAMIC' => array()
1499 );
1500 for ($i = 0, $c = count($matches[0]); $i < $c; $i++)
1501 {
1502 if (mb_strtoupper($matches[3][$i]) == 'LANDING')
1503 {
1504 $urls['LANDING'][] = $matches[4][$i];
1505 }
1506 else if (mb_strtoupper($matches[3][$i]) == 'DYNAMIC')
1507 {
1508 [$dynamicId, ] = explode('_', $matches[4][$i]);
1509 $urls['DYNAMIC'][] = $dynamicId;
1510 }
1511 else if (mb_strtoupper($matches[3][$i]) == 'USER')
1512 {
1513 $urls['USER'][] = $matches[4][$i];
1514 }
1515 else
1516 {
1517 $urls['BLOCK'][] = $matches[4][$i];
1518 }
1519 }
1520 // get parent landings for blocks
1521 // and public version of blocks too
1522 $anchorsId = array();
1523 $anchorsPublicId = array();
1524 if (!empty($urls['BLOCK']))
1525 {
1526 $urls['BLOCK'] = Block::getRowByBlockId(
1527 $urls['BLOCK'],
1528 array(
1529 'ID', 'LID', 'PARENT_ID', 'ANCHOR'
1530 )
1531 );
1532 foreach ($urls['BLOCK'] as $bid => &$bidRow)
1533 {
1534 if (
1535 !self::$previewMode &&
1536 $bidRow['PARENT_ID']
1537 )
1538 {
1539 $anchorsPublicId[$bid] = $bidRow['PARENT_ID'];
1540 }
1541 else
1542 {
1543 $anchorsId[$bid] = $bidRow['ANCHOR']
1544 ? \htmlspecialcharsbx($bidRow['ANCHOR'])
1545 : Block::getAnchor($bidRow['ID']);
1546 }
1547 $bidRow = $bidRow['LID'];
1548 }
1549 unset($bidRow);
1550 $urls['LANDING'] = array_unique(array_merge(
1551 $urls['LANDING'],
1552 $urls['BLOCK']
1553 ));
1554 }
1555 $urls['LANDING'] = array_unique(array_merge(
1556 $urls['LANDING'],
1557 $urls['DYNAMIC']
1558 ));
1559 // get anchors for public version
1560 if ($anchorsPublicId)
1561 {
1562 $anchorsPublicIdTmp = Block::getRowByBlockId(
1563 $anchorsPublicId,
1564 array(
1565 'ID', 'LID', 'PARENT_ID', 'ANCHOR'
1566 )
1567 );
1568 foreach ($anchorsPublicId as $bid => $bidParent)
1569 {
1570 if (!isset($anchorsPublicIdTmp[$bidParent]))
1571 {
1572 continue;
1573 }
1574 $bidParent = $anchorsPublicIdTmp[$bidParent];
1575 $anchorsPublicId[$bid] = $bidParent['ANCHOR']
1576 ? \htmlspecialcharsbx($bidParent['ANCHOR'])
1577 : Block::getAnchor($bidParent['ID']);
1578 }
1579 }
1580 $anchorsPublicId += $anchorsId;
1581 $landingFull = [];
1582 $lidEncoded = [];
1583 // get landing and blocks urls
1584 if (!empty($urls['LANDING']))
1585 {
1586 $urls['LANDING'] = $this->getPublicUrl(
1587 $urls['LANDING'],
1588 !Connector\Mobile::isMobileHit(),
1589 false,
1590 $landingFull
1591 );
1592 foreach ($urls['LANDING'] as $lid => &$url)
1593 {
1594 $lidEncoded[] = $lid;
1595 $url = \htmlspecialcharsbx($url);
1596 if ($isIframe)
1597 {
1598 $url .= '?IFRAME=Y';
1599 }
1600 }
1601 unset($url);
1602 }
1603 if (!empty($urls['BLOCK']))
1604 {
1605 foreach ($urls['BLOCK'] as $bid => $lid)
1606 {
1607 if (isset($urls['LANDING'][$lid]))
1608 {
1609 if (!in_array($lid, $lidEncoded))
1610 {
1611 $urls['LANDING'][$lid] = \htmlspecialcharsbx($urls['LANDING'][$lid]);
1612 }
1613 $urls['LANDING'][$lid] .= ($isIframe ? '?IFRAME=Y' : '');
1614 $urls['BLOCK'][$bid] = $urls['LANDING'][$lid] . '#' . $anchorsPublicId[$bid];
1615 }
1616 else
1617 {
1618 unset($urls['BLOCK'][$bid]);
1619 }
1620 }
1621 }
1622 // replace urls
1623 if (!empty($urls['LANDING']))
1624 {
1625 krsort($urls['LANDING']);
1626 $content = preg_replace_callback(
1627 $patternWithoutUser,
1628 function($matches) use($urls, $landingFull, $isIframe)
1629 {
1630 $dynamicPart = '';
1631 $matches[3] = mb_strtoupper($matches[3]);
1632 if ($matches[3] == 'DYNAMIC')
1633 {
1634 $matches[3] = 'LANDING';
1635 if (($underPos = mb_strpos($matches[4], '_')) !== false)
1636 {
1637 $dynamicPart = mb_substr($matches[4], $underPos);
1638 $matches[4] = mb_substr($matches[4], 0, $underPos);
1639 }
1640 [$dynamicId, ] = explode('_', $matches[4]);
1641 $matches[4] = $dynamicId;
1642 }
1643 if (isset($urls[$matches[3]][$matches[4]]))
1644 {
1645 if ($dynamicPart)
1646 {
1647 $landingUrl = $urls[$matches[3]][$matches[4]];
1648 if (isset($landingFull[$matches[4]]))
1649 {
1650 $landingUrl = $landingFull[$matches[4]];
1651 }
1652 $url = mb_substr($landingUrl, 0, mb_strlen($landingUrl) - 1);
1653 $url .= $dynamicPart . ($isIframe ? '/?IFRAME=Y' : '/');
1654 }
1655 else
1656 {
1657 $url = $urls[$matches[3]][$matches[4]];
1658 }
1659 return $matches[1] .
1660 $url . $matches[5] .
1661 $matches[6];
1662 }
1663 else
1664 {
1665 return $matches[1] .
1666 '#landing' . $matches[4] . $matches[5] . $dynamicPart .
1667 $matches[6];
1668 }
1669 },
1670 $content
1671 );
1672 $landingUrls = array();
1673 foreach ($urls['LANDING'] as $lid => $url)
1674 {
1675 $landingUrls['@#landing' . $lid.'@'] = $url;
1676 }
1677 }
1678 // replace user urls
1679 if (!empty($urls['USER']))
1680 {
1681 $patternForPseudoUrlUser = '/data-pseudo-url="{\S*(user:)?#user([\d\_]+)\S*}"/is';
1682 $content = preg_replace_callback(
1683 $patternForPseudoUrlUser,
1684 function($matches)
1685 {
1686 $url = "'" . Domain::getHostUrl() . '/company/personal/user/' . $matches[2] . "/'";
1687 return 'onClick="BX.SidePanel.Instance.open('. $url . ')" ';
1688 },
1689 $content
1690 );
1691 $patternForUser = '/(user:)?#(user)([\d\_]+)/is';
1692 $content = preg_replace_callback(
1693 $patternForUser,
1694 function($matches)
1695 {
1696 return Domain::getHostUrl() . '/company/personal/user/' . $matches[3] . '/';
1697 },
1698 $content
1699 );
1700 }
1701 }
1702
1703 return $content;
1704 }
1705
1710 protected function execHooks()
1711 {
1712 $hooksExec = array();
1713
1714 foreach (Hook::getForSite($this->siteId) as $hook)
1715 {
1716 if ($hook->enabled())
1717 {
1718 $hook = $this->prepareHook($hook);
1719 $hooksExec[$hook->getCode()] = $hook;
1720 }
1721 }
1722
1723 foreach (Hook::getForLanding($this->id) as $hook)
1724 {
1725 if ($hook->enabled())
1726 {
1727 $hooksExec[$hook->getCode()] = $hook;
1728 }
1729 }
1730
1731 foreach ($hooksExec as $hook)
1732 {
1733 if (
1734 !$this->getEditMode() ||
1735 $hook->enabledInEditMode()
1736 )
1737 {
1738 $hook->exec();
1739 }
1740 }
1741 }
1742
1743 protected function prepareHook($hook)
1744 {
1745 if ($hook->getCode() === 'GMAP')
1746 {
1747 $hook->setSiteId($this->siteId);
1748 }
1749
1750 return $hook;
1751 }
1752
1757 public function exist()
1758 {
1759 return $this->id > 0;
1760 }
1761
1766 public function isActive()
1767 {
1768 return $this->active;
1769 }
1770
1775 public function getId()
1776 {
1777 return $this->id;
1778 }
1779
1784 public function getXmlId()
1785 {
1786 return $this->xmlId;
1787 }
1788
1793 public function getTitle()
1794 {
1795 return $this->title;
1796 }
1797
1802 public function getCode(): string
1803 {
1804 return $this->code;
1805 }
1806
1811 public function getMeta()
1812 {
1813 return $this->metaData;
1814 }
1815
1820 public function canEdit()
1821 {
1822 if (!$this->checkPermissions)
1823 {
1824 return true;
1825 }
1826 return in_array(Rights::ACCESS_TYPES['edit'], $this->rights);
1827 }
1828
1833 public function canPublication()
1834 {
1835 if (!$this->checkPermissions)
1836 {
1837 return true;
1838 }
1839 return in_array(Rights::ACCESS_TYPES['public'], $this->rights);
1840 }
1841
1846 public function canDelete()
1847 {
1848 if (!$this->checkPermissions)
1849 {
1850 return true;
1851 }
1852 return in_array(Rights::ACCESS_TYPES['delete'], $this->rights);
1853 }
1854
1859 public function getFolderId()
1860 {
1861 return $this->folderId;
1862 }
1863
1868 public function getSiteId()
1869 {
1870 return $this->siteId;
1871 }
1872
1877 public function getSiteTitle()
1878 {
1879 return $this->siteTitle;
1880 }
1881
1886 public function getDomainId()
1887 {
1888 return $this->domainId;
1889 }
1890
1895 public static function getSiteType()
1896 {
1897 return self::$siteCode;
1898 }
1899
1904 public function getSmnSiteId(): ?string
1905 {
1906 if ($this->siteId)
1907 {
1908 $res = Site::getList(array(
1909 'select' => array(
1910 'SMN_SITE_ID'
1911 ),
1912 'filter' => array(
1913 'ID' => $this->siteId
1914 )
1915 ));
1916 if ($row = $res->fetch())
1917 {
1918 return $row['SMN_SITE_ID'];
1919 }
1920 }
1921
1922 return null;
1923 }
1924
1929 public function getBlocks()
1930 {
1931 return $this->blocks;
1932 }
1933
1939 public function getBlockById($id)
1940 {
1941 $id = intval($id);
1942 return isset($this->blocks[$id])
1943 ? $this->blocks[$id]
1944 : null;
1945 }
1946
1952 public function addBlockToCollection(\Bitrix\Landing\Block $block)
1953 {
1954 if ($block->exist())
1955 {
1956 $this->blocks[$block->getId()] = $block;
1957 }
1958 }
1959
1964 public function getError()
1965 {
1966 return $this->error;
1967 }
1968
1973 public function getErrorMain(): ?\Bitrix\Main\Error
1974 {
1975 if ($this->error)
1976 {
1977 $error = $this->error->getFirstError();
1978 return new \Bitrix\Main\Error(
1979 $error->getMessage(),
1980 $error->getCode()
1981 );
1982 }
1983 return null;
1984 }
1985
1990 public function touch()
1991 {
1992 static $touched = [];
1993
1994 if (isset($touched[$this->id]))
1995 {
1996 return;
1997 }
1998
1999 $touched[$this->id] = true;
2000
2001 if (self::update($this->id, ['PUBLIC' => 'N'])->isSuccess())
2002 {
2003 Site::touch($this->siteId);
2004 }
2005 }
2006
2011 public function updateVersion()
2012 {
2013 $needUpdate = false;
2014 // double hooks: public and draft
2015 if ($this->version <= 1)
2016 {
2017 $needUpdate = true;
2018 $this->version = 2;
2019 $hookEditMode = Hook::getEditMode();
2020 if (!$hookEditMode)
2021 {
2022 Hook::setEditMode(true);
2023 }
2024 Hook::publicationSite($this->siteId);
2025 Hook::publicationLanding($this->id);
2026 if (!$hookEditMode)
2027 {
2028 Hook::setEditMode(false);
2029 }
2030 }
2031 // block assets
2032 if ($this->version <= 2)
2033 {
2034 $needUpdate = true;
2035 $this->version = 3;
2036 Assets\PreProcessing\Icon::processingLanding($this->id);
2037 Assets\Manager::rebuildWebpackForLanding($this->id);
2038 }
2039 if ($this->version <= 3)
2040 {
2041 $needUpdate = true;
2042 $this->version = 4;
2043 Assets\PreProcessing\Font::processingLanding($this->id);
2044 }
2045 if ($this->version <= 4)
2046 {
2047 $needUpdate = true;
2048 $this->version = 5;
2049 Hook\Page\ThemeFonts::migrateFromTypoThemes($this->id, $this->siteId);
2050 }
2051 if ($this->version <= 5)
2052 {
2053 // fix 126641
2054 $needUpdate = true;
2055 $this->version = 6;
2056 Assets\PreProcessing\Icon::processingLanding($this->id);
2057 Assets\Manager::rebuildWebpackForLanding($this->id);
2058 }
2059 if ($this->version <= 6)
2060 {
2061 $needUpdate = true;
2062 Update\Block\Buttons::updateLanding($this->id);
2063 Update\Block\FontWeight::updateLanding($this->id);
2064 $this->version = 7;
2065 }
2066 if ($this->version <= 7)
2067 {
2068 $needUpdate = true;
2069 Assets\PreProcessing\Icon::processingLanding($this->id);
2070 Assets\Manager::rebuildWebpackForLanding($this->id);
2071 $this->version = 8;
2072 }
2073 if ($this->version <= 9)
2074 {
2075 // +1 version for reupdate in hotfix
2076 $needUpdate = true;
2077 Subtype\Form::updateLandingToEmbedForms($this->id);
2078 Assets\Manager::rebuildWebpackForLanding($this->id);
2079 $this->version = 10;
2080 }
2081 if ($this->version <= 10)
2082 {
2083 $needUpdate = true;
2084 Update\Block\DuplicateImages::updateLanding($this->id);
2085
2086 $this->version = 11;
2087 }
2088 if ($needUpdate)
2089 {
2091 self::update($this->id, [
2092 'VERSION' => $this->version,
2093 'DATE_MODIFY' => false,
2094 'MODIFIED_BY_ID' => false
2095 ]);
2096 Rights::setOn();
2097 }
2098 }
2099
2105 public function publication($blockId = null): bool
2106 {
2107 if ($this->canPublication())
2108 {
2109 return Mutator::landingPublication($this, $blockId);
2110 }
2111 return false;
2112 }
2113
2118 public function fakePublication(): bool
2119 {
2120 if ($this->canPublication())
2121 {
2122 return Mutator::landingPublication($this, null, true);
2123 }
2124 return false;
2125 }
2126
2131 public function unpublic()
2132 {
2133 static $siteUpdated = [];
2134
2135 $res = parent::update($this->id, array(
2136 'ACTIVE' => 'N',
2137 'PUBLIC' => 'N',
2138 'DATE_MODIFY' => false
2139 ));
2140 if ($res->isSuccess())
2141 {
2142 if (
2143 !in_array($this->siteId, $siteUpdated) &&
2145 )
2146 {
2147 $siteUpdated[] = $this->siteId;
2148 Site::update($this->siteId, array());
2149 }
2150 // send event
2151 $event = new Event('landing', 'onLandingAfterUnPublication', array(
2152 'id' => $this->getId()
2153 ));
2154 $event->send();
2155 return true;
2156 }
2157 else
2158 {
2159 $this->error->addFromResult($res);
2160 return false;
2161 }
2162 }
2163
2171 public function addBlock(string $code, array $data = array(), bool $saveInLastUsed = false)
2172 {
2173 if (!$this->canEdit())
2174 {
2175 $this->error->addError(
2176 'ACCESS_DENIED',
2177 Loc::getMessage('LANDING_BLOCK_ACCESS_DENIED')
2178 );
2179 return false;
2180 }
2181
2182 if (!isset($data['PUBLIC']))
2183 {
2184 $data['PUBLIC'] = $this::$editMode ? 'N' : 'Y';
2185 }
2186
2187 $block = Block::createFromRepository($this, $code, $data);
2188
2189 if ($block)
2190 {
2191 if ($saveInLastUsed)
2192 {
2193 Block::markAsUsed($code);
2194 }
2195
2196 $this->touch();
2197 $this->addBlockToCollection($block);
2198
2199 if (History::isActive())
2200 {
2201 $history = new History($this->id, History::ENTITY_TYPE_LANDING);
2202 $history->push('ADD_BLOCK', ['block' => $block]);
2203 }
2204
2205 return $block->getId();
2206 }
2207
2208 return false;
2209 }
2210
2216 public function deleteBlock($id)
2217 {
2218 $id = intval($id);
2219 if (isset($this->blocks[$id]))
2220 {
2221 $result = $this->blocks[$id]->unlink();
2222 $this->error->copyError(
2223 $this->blocks[$id]->getError()
2224 );
2225 if ($result)
2226 {
2227 unset($this->blocks[$id]);
2228 }
2229 $this->touch();
2230 return $result;
2231 }
2232 else
2233 {
2234 $this->error->addError(
2235 'BLOCK_NOT_FOUND',
2236 Loc::getMessage('LANDING_BLOCK_NOT_FOUND')
2237 );
2238 return false;
2239 }
2240 }
2241
2248 public function markDeletedBlock($id, $mark)
2249 {
2250 $id = intval($id);
2251 if (!isset($this->blocks[$id]))
2252 {
2253 $this->blocks[$id] = new Block($id);
2254 }
2255
2256 if (
2257 isset($this->blocks[$id]) &&
2258 $this->blocks[$id]->exist() &&
2259 $this->blocks[$id]->getLandingId() == $this->getId()
2260 )
2261 {
2262 if ($this->blocks[$id]->getAccess() >= $this->blocks[$id]::ACCESS_X)
2263 {
2264 $this->blocks[$id]->markDeleted($mark);
2265 if (!$mark)
2266 {
2267 Assets\PreProcessing::blockUndeleteProcessing(
2268 $this->blocks[$id]
2269 );
2270 }
2271 if ($this->blocks[$id]->save())
2272 {
2273 if ($mark)
2274 {
2275 if (History::isActive())
2276 {
2277 $history = new History($this->id, History::ENTITY_TYPE_LANDING);
2278 $history->push('REMOVE_BLOCK', ['block' => $this->blocks[$id]]);
2279 }
2280
2281 unset($this->blocks[$id]);
2282 }
2283 else
2284 {
2285 $this->addBlockToCollection(
2286 $this->blocks[$id]
2287 );
2288 }
2289 $this->touch();
2290 return true;
2291 }
2292 else
2293 {
2294 $this->error->copyError(
2295 $this->blocks[$id]->getError()
2296 );
2297 }
2298 }
2299 else
2300 {
2301 $this->error->addError(
2302 'ACCESS_DENIED',
2303 Loc::getMessage('LANDING_BLOCK_ACCESS_DENIED')
2304 );
2305 return false;
2306 }
2307 }
2308 else
2309 {
2310 $this->error->addError(
2311 'BLOCK_NOT_FOUND',
2312 Loc::getMessage('LANDING_BLOCK_NOT_FOUND')
2313 );
2314 return false;
2315 }
2316
2317 return false;
2318 }
2319
2326 protected function transferBlock($id, $lid)
2327 {
2328 $id = intval($id);
2329 if (isset($this->blocks[$id]))
2330 {
2331 $result = $this->blocks[$id]->changeLanding($lid);
2332 $this->error->copyError($this->blocks[$id]->getError());
2333 if ($result)
2334 {
2335 unset($this->blocks[$id]);
2336 }
2337 return $result;
2338 }
2339 else
2340 {
2341 $this->error->addError(
2342 'BLOCK_NOT_FOUND',
2343 Loc::getMessage('LANDING_BLOCK_NOT_FOUND')
2344 );
2345 return false;
2346 }
2347 }
2348
2353 public function resortBlocks()
2354 {
2355 uasort($this->blocks, function($a, $b)
2356 {
2357 if ($a->getSort() == $b->getSort())
2358 {
2359 return ($a->getId() < $b->getId()) ? -1 : 1;
2360 }
2361 return ($a->getSort() < $b->getSort()) ? -1 : 1;
2362 });
2363 $sort = 0;
2364 foreach ($this->blocks as $id => $block)
2365 {
2366 $block->saveSort($sort);
2367 $sort += 500;
2368 }
2369 }
2370
2377 protected function sortBlock(int $id, string $action): bool
2378 {
2379 $id = intval($id);
2380 if (isset($this->blocks[$id]))
2381 {
2382 $blocks = array_keys($this->blocks);
2383 for ($i = 0, $c = count($blocks); $i < $c; $i++)
2384 {
2385 if ($blocks[$i] == $id)
2386 {
2387 // change sort between two blocks
2388 $targetKey = $i + ($action === 'up' ? -1 : 1);
2389 if (isset($blocks[$targetKey]))
2390 {
2391 $thisBlock = $this->blocks[$id];
2392 $targetBlock = $this->blocks[$blocks[$targetKey]];
2393 $thisBlockSort = $thisBlock->getSort();
2394 $targetBlockSort = $targetBlock->getSort();
2395
2396 $thisBlock->setSort($targetBlockSort);
2397 $targetBlock->setSort($thisBlockSort);
2398 $res1 = $thisBlock->save();
2399 $res2 = $targetBlock->save();
2400
2401 $this->error->copyError($thisBlock->getError());
2402 $this->error->copyError($targetBlock->getError());
2403
2404 if ($res1 || $res2)
2405 {
2406 $this->touch();
2407 }
2408
2409 return $res1 && $res2;
2410 }
2411
2412 $this->error->addError(
2413 'BLOCK_WRONG_SORT',
2414 Loc::getMessage('LANDING_BLOCK_WRONG_SORT')
2415 );
2416
2417 return false;
2418 }
2419 }
2420 }
2421 else
2422 {
2423 $this->error->addError(
2424 'BLOCK_NOT_FOUND',
2425 Loc::getMessage('LANDING_BLOCK_NOT_FOUND')
2426 );
2427 }
2428
2429 return false;
2430 }
2431
2437 public function upBlock(int $id): bool
2438 {
2439 if ($this->sortBlock($id, 'up'))
2440 {
2441 if (History::isActive())
2442 {
2443 $history = new History($this->id, History::ENTITY_TYPE_LANDING);
2444 $history->push('SORT_BLOCK', [
2445 'block' => $id,
2446 'lid' => $this->getId(),
2447 'up' => true,
2448 ]);
2449 }
2450
2451 return true;
2452 }
2453
2454 return false;
2455 }
2456
2462 public function downBlock(int $id): bool
2463 {
2464 if ($this->sortBlock($id, 'down'))
2465 {
2466 if (History::isActive())
2467 {
2468 $history = new History($this->id, History::ENTITY_TYPE_LANDING);
2469 $history->push('SORT_BLOCK', [
2470 'block' => $id,
2471 'lid' => $this->getId(),
2472 'up' => false,
2473 ]);
2474 }
2475
2476 return true;
2477 }
2478
2479 return false;
2480 }
2481
2488 protected function activateBlock($id, $action)
2489 {
2490 $id = intval($id);
2491 if (isset($this->blocks[$id]))
2492 {
2493 if ($this->blocks[$id]->setActive($action == 'show'))
2494 {
2495 if ($res = $this->blocks[$id]->save())
2496 {
2497 $this->touch();
2498 }
2499 }
2500 $this->error->copyError($this->blocks[$id]->getError());
2501 return $res;
2502 }
2503 else
2504 {
2505 $this->error->addError(
2506 'BLOCK_NOT_FOUND',
2507 Loc::getMessage('LANDING_BLOCK_NOT_FOUND')
2508 );
2509 return false;
2510 }
2511 }
2512
2518 public function showBlock($id)
2519 {
2520 return $this->activateBlock($id, 'show');
2521 }
2522
2528 public function hideBlock($id)
2529 {
2530 return $this->activateBlock($id, 'hide');
2531 }
2532
2539 public function favoriteBlock(int $id, array $meta = []): ?int
2540 {
2541 $bewBlockId = $this->copyBlock($id, $id);
2542
2543 if ($bewBlockId > 0)
2544 {
2545 if (
2546 $this->blocks[$bewBlockId]->changeLanding(0) &&
2547 $this->blocks[$bewBlockId]->changeFavoriteMeta($meta)
2548 )
2549 {
2550 Block::markAsUsed($this->blocks[$bewBlockId]->getCode() . '@' . $bewBlockId);
2551 \Bitrix\Landing\Block::clearRepositoryCache();
2552 if ($meta['preview'] ?? null)
2553 {
2554 File::deleteFromBlock($id, $meta['preview']);
2555 }
2556 }
2557 else
2558 {
2559 $this->error->copyError($this->blocks[$bewBlockId]->getError());
2560 }
2561 return $bewBlockId;
2562 }
2563
2564 return null;
2565 }
2566
2572 public function unFavoriteBlock(int $blockId): bool
2573 {
2574 $block = new Block($blockId);
2575 if (!$block || empty($block->getMeta()['FAVORITE_META']))
2576 {
2577 $this->error->addError(
2578 'BLOCK_NOT_FOUND',
2579 Loc::getMessage('LANDING_BLOCK_NOT_FOUND')
2580 );
2581 return false;
2582 }
2583
2584 if (
2585 $block->getAccess() < Block::ACCESS_X
2586 || (int)$block->getMeta()['CREATED_BY_ID'] !== Manager::getUserId()
2587 )
2588 {
2589 $this->error->addError(
2590 'ACCESS_DENIED',
2591 Loc::getMessage('LANDING_BLOCK_ACCESS_DENIED')
2592 );
2593 return false;
2594 }
2595
2596 if (BlockTable::delete($blockId)->isSuccess())
2597 {
2598 File::deleteFromBlock($blockId);
2599 Block::removeAsUsed($block->getCode() . '@' . $block->getId());
2600 Block::clearRepositoryCache();
2601 return true;
2602 }
2603
2604 return false;
2605 }
2606
2613 protected function changeParentOfBlock($block, $params)
2614 {
2615 $block = intval($block);
2616 $move = isset($params['MOVE']) && $params['MOVE'];
2617 $afterId = isset($params['AFTER_ID']) ? (int)$params['AFTER_ID'] : 0;
2618 $fromLandingRow = Block::getRowByBlockId($block, ['ID', 'LID', 'SITE_TYPE' => 'LANDING.SITE.TYPE']);
2619 $fromLandingId = $fromLandingRow['LID'] ?? null;
2620 $currentScopeId = Site\Type::getCurrentScopeId();
2621 $same = $this->id == $fromLandingId;
2622
2623 if ($currentScopeId !== $fromLandingRow['SITE_TYPE'])
2624 {
2625 Site\Type::setScope($fromLandingRow['SITE_TYPE']);
2626 }
2627
2628 if ($same)
2629 {
2630 $fromLanding = clone $this;
2631 }
2632 else
2633 {
2634 $fromLanding = self::createInstance($fromLandingId);
2635 }
2636
2637 // if landing exist and available, get it blocks
2638 if ($this->exist() && $fromLanding->exist())
2639 {
2640 $fromLandingBlocks = $fromLanding->getBlocks();
2641 // if move, just change landing id
2642 if ($move)
2643 {
2644 $res = $fromLanding->transferBlock($block, $this->id);
2645 $this->error->copyError($fromLanding->getError());
2646 if ($res)
2647 {
2648 $newBlock = $fromLandingBlocks[$block];
2649 }
2650 }
2651 // else create copy
2652 else if (isset($fromLandingBlocks[$block]))
2653 {
2654 $srcBlock = $fromLandingBlocks[$block];
2655 $newBlock = Block::createFromRepository(
2656 $this,
2657 $srcBlock->getCode(),
2658 array(
2659 'ACTIVE' => $srcBlock->isActive() ? 'Y' : 'N',
2660 'DESIGNED' => $srcBlock->isDesigned() ? 'Y' : 'N',
2661 'ACCESS' => $srcBlock->getAccess(),
2662 'SORT' => $srcBlock->getSort(),
2663 'CONTENT' => $srcBlock->getContent(),
2664 'SOURCE_PARAMS' => $srcBlock->getDynamicParams(),
2665 'PUBLIC' => 'N'
2666 ));
2667 // we should save original content after all callbacks
2668 $newBlock->saveContent(
2669 $srcBlock->getContent()
2670 );
2671 $newBlock->save();
2672 // copy files
2673 if ($newBlock)
2674 {
2676 $srcBlock->getId(),
2677 $newBlock->getId()
2678 );
2679 }
2680 }
2681 // add block to collection and resort
2682 if (isset($newBlock) && $newBlock)
2683 {
2684 if ($afterId > 0 && isset($this->blocks[$afterId]))
2685 {
2686 $targetBlock = $this->blocks[$afterId];
2687 }
2688 else
2689 {
2690 $blocksTmp = array_values($this->blocks);
2691 $targetBlock = array_pop($blocksTmp);
2692 }
2693 if ($targetBlock)
2694 {
2695 $newBlock->setSort($targetBlock->getSort() + 1);
2696 }
2697 $this->addBlockToCollection($newBlock);
2698 $this->resortBlocks();
2699 // search index
2700 $newBlock->save();
2701 }
2702 //change dates
2703 if ($this->error->isEmpty())
2704 {
2705 if ($move && !$same)
2706 {
2707 $fromLanding->touch();
2708 }
2709 }
2710 }
2711
2712 $this->error->copyError($fromLanding->getError());
2713
2714 if ($currentScopeId !== $fromLandingRow['SITE_TYPE'])
2715 {
2716 Site\Type::setScope($currentScopeId);
2717 }
2718
2719 if ($this->error->isEmpty())
2720 {
2721 $this->touch();
2722 }
2723
2724 return isset($newBlock) ? $newBlock->getId() : null;
2725 }
2726
2733 public function copyBlock($id, $afterId)
2734 {
2735 $blockId = $this->changeParentOfBlock($id, array(
2736 'MOVE' => false,
2737 'AFTER_ID' => $afterId
2738 ));
2739 if (!$blockId)
2740 {
2741 $this->error->addError(
2742 'BLOCK_NOT_FOUND',
2743 Loc::getMessage('LANDING_BLOCK_NOT_FOUND')
2744 );
2745 }
2746 return $blockId;
2747 }
2748
2756 public function copyAllBlocks($lid, $replaceLinks = true, array &$references = [])
2757 {
2758 $landing = self::createInstance($lid);
2759
2760 if ($this->exist() && $landing->exist())
2761 {
2762 $oldNew = array();
2763 // copy blocks
2764 foreach ($landing->getBlocks() as $block)
2765 {
2766 $newBlock = Block::createFromRepository(
2767 $this,
2768 $block->getCode(),
2769 array(
2770 'ACTIVE' => $block->isActive() ? 'Y' : 'N',
2771 'DESIGNED' => $block->isDesigned() ? 'Y' : 'N',
2772 'PUBLIC' => $block->isPublic() ? 'Y' : 'N',
2773 'ACCESS' => $block->getAccess(),
2774 'SORT' => $block->getSort(),
2775 'CONTENT' => $block->getContent(),
2776 'SOURCE_PARAMS' => $block->getDynamicParams()
2777 ));
2778 if ($newBlock)
2779 {
2780 $oldNew[$block->getId()] = $newBlock;
2781 $references[$block->getId()] = $newBlock->getId();
2782 $this->addBlockToCollection($newBlock);
2783 }
2784 }
2785 // replace old id of blocks to the new one and clone files
2786 foreach ($this->getBlocks() as $block)
2787 {
2788 $content = $block->getContent();
2789 foreach ($oldNew as $oldId => $newBlock)
2790 {
2791 // clone files
2793 $newBlock->getId(),
2794 File::getFilesFromBlockContent($oldId, $content)
2795 );
2796 // replace ids
2797 if ($replaceLinks)
2798 {
2799 $content = str_replace(
2800 '#block' . $oldId,
2801 '#block' . $newBlock->getId(),
2802 $content
2803 );
2804 $block->saveContent($content);
2805 }
2806 $block->save();
2807 }
2808 }
2809 $this->touch();
2810 }
2811
2812 $this->error->copyError($this->getError());
2813 $this->error->copyError($landing->getError());
2814 }
2815
2820 public function clearFolderIndex(): void
2821 {
2822 if ($this->folderId)
2823 {
2824 $resFolder = Folder::getList([
2825 'select' => [
2826 'ID'
2827 ],
2828 'filter' => [
2829 'ID' => $this->folderId,
2830 'INDEX_ID' => $this->id
2831 ]
2832 ]);
2833 if ($resFolder->fetch())
2834 {
2835 Folder::update($this->folderId, [
2836 'INDEX_ID' => null
2837 ]);
2838 }
2839 }
2840 }
2841
2847 private function canPublicAfterCopy(): bool
2848 {
2849 $siteId = $this->getSiteId();
2850 $folderId = $this->getFolderId();
2851
2852 // if permissions enough
2853 if (!$this->canPublication())
2854 {
2855 return false;
2856 }
2857
2858 // in root, we can
2859 if (!$folderId)
2860 {
2861 return true;
2862 }
2863
2864 // check all folders above the page
2865 $crumbs = Folder::getBreadCrumbs($folderId, $siteId);
2866 foreach ($crumbs as $crumb)
2867 {
2868 // if folder is active, we don't care about
2869 if ($crumb['ACTIVE'] === 'Y')
2870 {
2871 continue;
2872 }
2873
2874 // check active pages in each folder above
2875 $res = self::getList([
2876 'select' => [
2877 'ID'
2878 ],
2879 'filter' => [
2880 '=ACTIVE' => 'Y',
2881 'FOLDER_ID' => $crumb['ID'],
2882 ],
2883 'limit' => 1
2884 ]);
2885 if ($res->fetch())
2886 {
2887 // if such folder exists we cant public any folder
2888 return false;
2889 }
2890
2891 // check active folders in folders above
2892 $res = Folder::getList([
2893 'select' => [
2894 'ID'
2895 ],
2896 'filter' => [
2897 '=ACTIVE' => 'Y',
2898 'PARENT_ID' => $crumb['ID'],
2899 ],
2900 'limit' => 1
2901 ]);
2902 if ($res->fetch())
2903 {
2904 // if such folder exists we cant public any folder
2905 return false;
2906 }
2907 }
2908
2909 // all folders are active or not exists active pages
2910 return true;
2911 }
2912
2919 public function move(?int $toSiteId = null, ?int $toFolderId = null): bool
2920 {
2921 if (!$this->exist())
2922 {
2923 return false;
2924 }
2925
2926 if (!$toSiteId)
2927 {
2928 $toSiteId = $this->getSiteId();
2929 }
2930
2931 $rightsSite = Rights::getOperationsForSite($toSiteId);
2932 if (!in_array(Rights::ACCESS_TYPES['edit'], $rightsSite))
2933 {
2934 $this->error->addError(
2935 'ACCESS_DENIED',
2936 Loc::getMessage('LANDING_SITE_ACCESS_DENIED')
2937 );
2938 return false;
2939 }
2940
2941 if (!$this->canDelete())
2942 {
2943 $this->error->addError(
2944 'DELETE_ACCESS_DENIED',
2945 Loc::getMessage('LANDING_DELETE_ACCESS_DENIED')
2946 );
2947 return false;
2948 }
2949
2950 $result = self::update($this->id, [
2951 'ACTIVE' => 'N',
2952 'PUBLIC' => 'N',
2953 'CODE' => $this->code,
2954 'SITE_ID' => $toSiteId,
2955 'FOLDER_ID' => $toFolderId
2956 ]);
2957
2958 if ($result->isSuccess())
2959 {
2960 $this->clearFolderIndex();
2961 if ($this->active && $this->canPublicAfterCopy($toFolderId))
2962 {
2963 $this->publication();
2964 }
2965 }
2966
2967 $this->error->addFromResult($result);
2968
2969 return $result->isSuccess();
2970 }
2971
2980 public function copy(?int $toSiteId = null, ?int $toFolderId = null, bool $withoutBlocks = false, bool $skipSystem = false): ?int
2981 {
2982 if ($this->exist())
2983 {
2984 $landingRow = Landing::getList([
2985 'filter' => [
2986 'ID' => $this->id
2987 ]
2988 ])->fetch();
2989 $folderId = null;
2990 if (!$toSiteId)
2991 {
2992 $toSiteId = $this->getSiteId();
2993 }
2994 if ($toFolderId !== null)
2995 {
2996 $folderId = $toFolderId;
2997 }
2998 // check if folder in the same site
2999 if ($folderId)
3000 {
3001 $folderRow = Site::getFolder($folderId);
3002 if (intval($folderRow['SITE_ID'] ?? null) !== $toSiteId)
3003 {
3004 $folderId = null;
3005 }
3006 }
3007 // add 'copy' to new page?
3008 $addCopyMark = !!Landing::getList([
3009 'select' => [
3010 'ID'
3011 ],
3012 'filter' => [
3013 '=TITLE' => $landingRow['TITLE'],
3014 '=DELETED' => 'N',
3015 'FOLDER_ID' => $folderId,
3016 'SITE_ID' => $toSiteId,
3017 ]
3018 ])->fetch();
3019 // create new page
3020 $res = Landing::add([
3021 'CODE' => $landingRow['CODE'],
3022 'ACTIVE' => 'N',
3023 'PUBLIC' => 'N',
3024 'TITLE' => $addCopyMark
3025 ? $landingRow['TITLE'] . ' ' . Loc::getMessage('LANDING_COPY_SUFFIX')
3026 : $landingRow['TITLE'],
3027 'SYS' => $skipSystem ? 'N' : $landingRow['SYS'],
3028 'XML_ID' => $landingRow['XML_ID'],
3029 'TPL_CODE' => $landingRow['TPL_CODE'],
3030 'INITIATOR_APP_CODE' => $landingRow['INITIATOR_APP_CODE'],
3031 'DESCRIPTION' => $landingRow['DESCRIPTION'],
3032 'TPL_ID' => $landingRow['TPL_ID'],
3033 'SITE_ID' => $toSiteId,
3034 'SITEMAP' => $landingRow['SITEMAP'],
3035 'FOLDER_ID' => $folderId,
3036 'RULE' => ''
3037 ]);
3038 // landing allready create, just copy the blocks
3039 if ($res->isSuccess())
3040 {
3042 $landingNew = Landing::createInstance($res->getId());
3043 if ($landingNew->exist())
3044 {
3045 if (!$withoutBlocks)
3046 {
3047 $landingNew->copyAllBlocks($this->id);
3048 }
3049 // copy hook data
3051 $this->id,
3052 $landingNew->getId()
3053 );
3054 // copy files
3056 $this->id,
3057 $landingNew->getId()
3058 );
3059 // copy template refs
3060 if (($refs = TemplateRef::getForLanding($this->id)))
3061 {
3062 TemplateRef::setForLanding($landingNew->getId(), $refs);
3063 }
3064 // publication if needed
3065 if ($landingRow['ACTIVE'] === 'Y' && $landingNew->canPublicAfterCopy($toFolderId))
3066 {
3067 $landingNew->publication();
3068 }
3069 return $landingNew->getId();
3070 }
3071 $this->error->copyError($landingNew->getError());
3072 }
3073 else
3074 {
3075 $this->error->addFromResult($res);
3076 }
3077 }
3078
3079 return null;
3080 }
3081
3088 public function moveBlock($id, $afterId)
3089 {
3090 $blockId = $this->changeParentOfBlock($id, array(
3091 'MOVE' => true,
3092 'AFTER_ID' => $afterId
3093 ));
3094 if (!$blockId)
3095 {
3096 $this->error->addError(
3097 'BLOCK_NOT_FOUND',
3098 Loc::getMessage('LANDING_BLOCK_NOT_FOUND')
3099 );
3100 }
3101 return $blockId;
3102 }
3103
3110 public static function update($id, $fields = array())
3111 {
3112 if (self::$enabledUpdate)
3113 {
3114 return parent::update($id, $fields);
3115 }
3116 else
3117 {
3118 return new \Bitrix\Main\Result;
3119 }
3120 }
3121
3129 public static function addByTemplate(int $siteId, string $code, array $fields = []): \Bitrix\Main\Entity\AddResult
3130 {
3131 $result = new \Bitrix\Main\Entity\AddResult;
3132
3133 // get type by siteId
3134 $res = Site::getList([
3135 'select' => [
3136 'TYPE'
3137 ],
3138 'filter' => [
3139 'ID' => $siteId
3140 ]
3141 ]);
3142 if (!($site = $res->fetch()))
3143 {
3144 $result->addError(new \Bitrix\Main\Error(
3145 'SITE_ERROR',
3146 Loc::getMessage('LANDING_SITE_ERROR')
3147 ));
3148 return $result;
3149 }
3150
3151 // get landing if specified
3152 if ($fields['ID'] ?? null)
3153 {
3154 $res = self::getList([
3155 'select' => [
3156 'ID', 'FOLDER_ID', 'FOLDER', 'ACTIVE'
3157 ],
3158 'filter' => [
3159 'SITE_ID' => $siteId,
3160 'ID' => $fields['ID']
3161 ]
3162 ]);
3163 if (!($landing = $res->fetch()))
3164 {
3165 $result->addError(new \Bitrix\Main\Error(
3166 'LANDING_ERROR',
3167 Loc::getMessage('LANDING_NOT_FOUND')
3168 ));
3169 return $result;
3170 }
3171 if ($landing['FOLDER'] === 'Y')
3172 {
3173 $landing['FOLDER_ID'] = $landing['ID'];
3174 }
3175 }
3176
3177 // include the component
3178 $componentName = 'bitrix:landing.demo';
3179 $className = \CBitrixComponent::includeComponentClass($componentName);
3181 $demoCmp = new $className;
3182 $demoCmp->initComponent($componentName);
3183 $demoCmp->arParams = [
3184 'TYPE' => $fields['SITE_TYPE'] ?? (($site['TYPE'] == 'STORE' || $site['TYPE'] == 'SMN') ? 'PAGE' : $site['TYPE']),
3185 'SITE_ID' => $siteId,
3186 'SITE_WORK_MODE' => 'N',
3187 'DISABLE_REDIRECT' => 'Y',
3188 'DONT_LEAVE_FRAME' => 'N',
3189 'FOLDER_ID' => $landing['FOLDER_ID'] ?? $fields['FOLDER_ID'] ?? 0,
3190 'META' => $fields
3191 ];
3192 if (
3193 isset($fields['PREPARE_BLOCKS'], $fields['PREPARE_BLOCKS_DATA'])
3194 && $fields['PREPARE_BLOCKS'] === true
3195 && is_array($fields['PREPARE_BLOCKS_DATA'])
3196 )
3197 {
3198 $demoCmp->arParams['PREPARE_BLOCKS_DATA'] = $fields['PREPARE_BLOCKS_DATA'];
3199 }
3200
3201 // ... and create the page by component's method
3202 $landingId = $demoCmp->createPage($siteId, $code);
3203
3204 // prepare success or failure
3205 if ($landingId)
3206 {
3207 $result->setId($landingId);
3208 if (($landing['ACTIVE'] ?? 'N') === 'Y')
3209 {
3210 Landing::createInstance($landingId)->publication();
3211 }
3212 }
3213 else
3214 {
3215 foreach ($demoCmp->getErrors() as $code => $title)
3216 {
3217 $result->addError(new \Bitrix\Main\Error($code, $title));
3218 }
3219 }
3220
3221 return $result;
3222 }
3223}
static addUniqueAgent(string $funcName, array $params=[], int $time=7200, ?int $nextExecDelay=null)
Definition agent.php:27
static getReplacesForContent(int $siteId, bool $attributesReplace=true)
Definition crm.php:241
static getCurrentId()
Definition domain.php:148
static copyLandingFiles($from, $to)
Definition file.php:559
static addToBlock(int $blockId, $fileId, bool $temp=false)
Definition file.php:305
static deleteFromAsset(int $assetId, $fileId=[])
Definition file.php:456
static copyBlockFiles($from, $to)
Definition file.php:570
static deleteFromBlock($blockId, $fileId=array())
Definition file.php:363
static deleteFromLanding($lid, $fileId=array())
Definition file.php:293
static getFilesFromBlockContent($blockId, $content)
Definition file.php:374
static getFilePath($fileId)
Definition file.php:600
static getFullPath(int $folderId, ?int $siteId=null, array &$lastFolder=[])
Definition folder.php:226
static getBreadCrumbs(int $folderId, ?int $siteId=null)
Definition folder.php:134
static getEditMode()
Definition hook.php:241
static publicationSite($siteId)
Definition hook.php:443
static getForLanding($id)
Definition hook.php:275
const HOOKS_CODES_FILES
Definition hook.php:45
static publicationLanding($lid)
Definition hook.php:453
static copyLanding($from, $to)
Definition hook.php:427
static getForSite($id)
Definition hook.php:251
static setEditMode(bool $mode=true)
Definition hook.php:232
static saveForLanding(int $id, array $data)
Definition hook.php:793
__construct($id, $params=array())
Definition landing.php:219
static getDynamicFilter()
Definition landing.php:826
static getHooks($id)
Definition landing.php:714
static disableCheckDeleted()
Definition landing.php:469
static setPreviewMode($mode=true)
Definition landing.php:442
moveBlock($id, $afterId)
Definition landing.php:3088
static setVariables(array $vars)
Definition landing.php:793
setMetaData(array $metaData)
Definition landing.php:369
static getAdditionalFieldsAsArray(int $landingId, bool $skipEmpty=true)
Definition landing.php:748
addBlockToCollection(\Bitrix\Landing\Block $block)
Definition landing.php:1952
applyTemplate($content=null)
Definition landing.php:1346
static update($id, $fields=array())
Definition landing.php:3110
static markUnDelete($id)
Definition landing.php:604
transferBlock($id, $lid)
Definition landing.php:2326
move(?int $toSiteId=null, ?int $toFolderId=null)
Definition landing.php:2919
static setEditMode($mode=true)
Definition landing.php:423
static getAdditionalFields($id)
Definition landing.php:729
static isDynamicDetailPage()
Definition landing.php:851
static getDynamicElementId()
Definition landing.php:842
static disableCheckUniqueAddress()
Definition landing.php:514
unFavoriteBlock(int $blockId)
Definition landing.php:2572
view(array $params=array())
Definition landing.php:1125
static markDelete(int $id)
Definition landing.php:544
sortBlock(int $id, string $action)
Definition landing.php:2377
static isCheckUniqueAddress()
Definition landing.php:505
markDeletedBlock($id, $mark)
Definition landing.php:2248
changeParentOfBlock($block, $params)
Definition landing.php:2613
static ping($id, $deleted=false)
Definition landing.php:386
static resolveIdByPublicUrl(string $landingUrl, int $siteId)
Definition landing.php:1096
getPreview(?int $id=null, bool $skipCloud=false, ?string $publicUrl=null)
Definition landing.php:863
activateBlock($id, $action)
Definition landing.php:2488
static setDynamicParams($filterId, $elementId)
Definition landing.php:816
copy(?int $toSiteId=null, ?int $toFolderId=null, bool $withoutBlocks=false, bool $skipSystem=false)
Definition landing.php:2980
favoriteBlock(int $id, array $meta=[])
Definition landing.php:2539
static enableCheckDeleted()
Definition landing.php:478
static createInstance($id, array $params=array())
Definition landing.php:534
static saveAdditionalFields($id, array $data)
Definition landing.php:782
addBlock(string $code, array $data=array(), bool $saveInLastUsed=false)
Definition landing.php:2171
copyBlock($id, $afterId)
Definition landing.php:2733
getPublicUrl($id=false, $absolute=true, $createPubPath=false, &$fullUrl=[])
Definition landing.php:911
publication($blockId=null)
Definition landing.php:2105
static enableCheckUniqueAddress()
Definition landing.php:523
parseLocalUrl(string $content)
Definition landing.php:1434
copyAllBlocks($lid, $replaceLinks=true, array &$references=[])
Definition landing.php:2756
static getApplication()
Definition manager.php:71
static getPublicationPath($siteCode=null, $siteId=null, $createPubPath=false)
Definition manager.php:396
static setPageTitle($title, $single=false)
Definition manager.php:211
static getUrlFromFile($file)
Definition manager.php:1067
static landingPublication(Landing $landing, $_591201104=null, bool $_1981551946=false)
Definition mutator.php:1
static hasAccessForLanding($landingId, $accessType)
Definition rights.php:578
static getOperationsForSite($siteId)
Definition rights.php:518
static getPublicHash($id, $domain=null)
Definition site.php:937
static touch(int $id)
Definition site.php:1593
static getFolder(int $folderId, string $accessLevel=Rights::ACCESS_TYPES['read'])
Definition site.php:1408
static setForLanding($id, array $data=array())
static loadMessages($file)
Definition loc.php:64
static getMessage($code, $replace=null, $language=null)
Definition loc.php:29
static getList(array $parameters=array())
addError(Error $error)
Definition result.php:50