Current Path : /var/www/www-root/data/www/info.monolith-realty.ru/bitrix/components/bitrix/landing.demo/ |
Current File : /var/www/www-root/data/www/info.monolith-realty.ru/bitrix/components/bitrix/landing.demo/class.php |
<?php if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) { die(); } use Bitrix\Landing\Site; use Bitrix\Landing\Landing; use Bitrix\Landing\Manager; use Bitrix\Landing\Syspage; use Bitrix\Landing\Demos; use Bitrix\Landing\Template; use Bitrix\Landing\TemplateRef; use Bitrix\Landing\Rights; use Bitrix\Landing\Landing\Cache; use Bitrix\Landing\Hook\Page\Settings; use Bitrix\Landing\Site\Type; use Bitrix\Highloadblock; use Bitrix\Main\Localization\Loc; use Bitrix\Main\ModuleManager; use Bitrix\Main\UI\PageNavigation; use Bitrix\Main\Web\HttpClient; use Bitrix\Main\Web\Json; use Bitrix\Main\Loader; use Bitrix\Main\Config\Option; use Bitrix\Main\UI\Filter; use Bitrix\Iblock; use Bitrix\Main; use Bitrix\Main\Event; use Bitrix\Main\EventResult; use Bitrix\Main\Type\Date; use Bitrix\Main\Type\DateTime; use Bitrix\Crm\Integration\UserConsent; use Bitrix\Main\Web\Uri; use Bitrix\Rest\Marketplace\Client; \CBitrixComponent::includeComponentClass('bitrix:landing.base'); class LandingSiteDemoComponent extends LandingBaseComponent { /** * Count items per page. */ const COUNT_PER_PAGE = 29; // /** // * Days count during which templates marked as 'new'. // */ // const LABEL_NEW_PERIOD_DAY = 120; /** * Tag for managed cache. */ const DEMO_TAG = 'landing_demo'; /** * Path with demo templates data for site. */ const DEMO_DIR_SITE = 'site'; /** * Path with demo templates data for page. */ const DEMO_DIR_PAGE = 'page'; const DEMO_TYPES_FILTER = [ 'PAGE' => 'page', 'STORE' => 'shop', 'KNOWLEDGE' => 'knowledgeBase', ]; protected const FILTER_ID = 'LANDING_FLT_DEMO'; /** * Remote repository url. */ const REMOTE_REPOSITORY_URL = 'https://preview.bitrix24.site/rest/1/gvsn3ngrn7vb4t1m/'; /** * Steps constant for catalog import. */ const STEP_STATUS_ERROR = 'ERROR'; const STEP_STATUS_CONTINUE = 'CONTINUE'; const STEP_STATUS_COMPLETE = 'COMPLETE'; const STEP_ID_CREATE_CATALOG = 'CREATE_CATALOG'; const STEP_ID_HIGHLOADBLOCK = 'CREATE_HIGHLOADBLOCK'; const STEP_ID_PREPARE_CRM_CATALOG = 'CRM_CATALOG'; const STEP_ID_XML_IMPORT = 'XML_IMPORT'; const STEP_ID_ADDITIONAL_UPDATE = 'ADDITIONAL'; const STEP_ID_REINDEX = 'REINDEX'; const STEP_ID_CATALOG_REINDEX = 'CATALOG_REINDEX'; const STEP_ID_FINAL = 'FINAL'; private $catalogStepList = [ //self::STEP_ID_CREATE_CATALOG, self::STEP_ID_HIGHLOADBLOCK, self::STEP_ID_PREPARE_CRM_CATALOG, self::STEP_ID_XML_IMPORT, self::STEP_ID_ADDITIONAL_UPDATE, self::STEP_ID_CATALOG_REINDEX, self::STEP_ID_FINAL ]; private const IMPORT_CATALOG_ERROR_ID = 'IMPORT_CATALOG_DATA'; private const IBLOCK_AUTODETECT = 'AUTODETECT'; public const SHOWCASE_CLOTHES = 'clothes'; public const SHOWCASE_FASHION = 'fashion'; public const SHOWCASE_DEFAULT = self::SHOWCASE_CLOTHES; private $showcaseList = []; /** @var string */ private $showcaseId; /** @var array */ private $showcase; /** * On template creation we can add callbacks from white list */ protected const ALLOWED_CALLBACKS = [ '\Bitrix\Landing\Subtype\Form::setSpecialFormToBlock', ]; /** * First call createPage. * @var bool */ protected $firstCreatePage = true; /** * Relative url for new site. * @var string */ protected $urlTpl = '/#rand#/'; /** * Landing old ids for version 3. * @var array */ protected $oldIds = []; /** * Predefined additional fields. * @var array */ protected $presetAdditionalFields = []; /** * Gets remote templates from repository. * @var bool */ protected $getRemoteTemplates = false; /** * Different layouts for pages. * @var array */ protected $pagesLayouts = []; // Needed to import demo data. /** @var bool */ protected $bitrix24Included; /** @var bool */ protected $iblockIncluded; /** @var bool */ protected $catalogIncluded; /** @var bool */ protected $crmIncluded; /** * Redirect to the landing. * @param int $landingId Landing id. * @return boolean If error. */ protected function redirectToLanding($landingId) { if ( isset($this->arParams['DISABLE_REDIRECT']) && $this->arParams['DISABLE_REDIRECT'] == 'Y' ) { return true; } $landing = Landing::createInstance($landingId, [ 'skip_blocks' => true, 'check_permissions' => false, ]); if ($landing->exist()) { $siteId = $landing->getSiteId(); $redirect = str_replace( array('#site_show#', '#landing_edit#'), array($siteId, $landingId), $this->arParams['PAGE_URL_LANDING_VIEW'] ); $uriEdit = new Uri($redirect); $uriEdit->addParams([ 'IFRAME' => ($this->arParams['DONT_LEAVE_FRAME'] != 'Y') ? 'N' : 'Y' ]); \localRedirect($uriEdit->getUri(), true); } else { $this->setErrors($landing->getError()->getErrors()); return false; } return true; } /** * Preset additional fields before create. * @param array $fields Additional fields. * @return void */ public function setAdditionalFields(array $fields) { $this->presetAdditionalFields = $fields; } /** * Prepare additional fields for page. * @param array $data Data array. * @param bool $request Get data from request. * @return array */ protected function prepareAdditionalFieldsPage($data, $request = true) { $data = $this->prepareAdditionalFields($data, $request); // todo: theme_custom_color now is not using, can remove? if ($this->request('theme') || $this->request('theme_custom_color')) { $color = $this->request('theme_custom_color') ?: $this->request('theme'); $color = $this->prepareColor($color); unset($data['ADDITIONAL_FIELDS']['THEME_CODE']); $data['ADDITIONAL_FIELDS']['THEME_COLOR'] = $color; if ($this->arParams['SITE_ID'] > 0) { $data['ADDITIONAL_FIELDS']['THEME_USE'] = 'Y'; } else { $data['ADDITIONAL_FIELDS']['THEME_USE'] = 'N'; } } if ($this->request('theme_use_site')) { $color = $this->request('theme_use_site'); $color = $this->prepareColor($color); unset($data['ADDITIONAL_FIELDS']['THEME_CODE']); $data['ADDITIONAL_FIELDS']['THEME_COLOR'] = $color; $data['ADDITIONAL_FIELDS']['THEME_USE'] = 'N'; } return $data; } /** * Prepare additional fields for site. * @param array $data Data array. * @return array */ protected function prepareAdditionalFieldsSite($data) { // For SITE always add theme from request. // It is may be original theme, or user change $data = $this->prepareAdditionalFields($data, false); if ($this->request('theme') || $this->request('theme_custom_color')) { $color = $this->request('theme_custom_color') ?: $this->request('theme'); $color = $this->prepareColor($color); unset($data['ADDITIONAL_FIELDS']['THEME_CODE']); $data['ADDITIONAL_FIELDS']['THEME_COLOR'] = $color; } return $data; } /** * Prepare array of additional data. * @param array $data Data item array. * @param bool $request Get data from request. * @return array */ protected function prepareAdditionalFields($data, $request = true) { if ( !isset($data['ADDITIONAL_FIELDS']) || !is_array($data['ADDITIONAL_FIELDS']) ) { $data['ADDITIONAL_FIELDS'] = array(); } // title / description was changed in preview if ($request) { $title = isset($this->arParams['META']['TITLE']) ? $this->arParams['META']['TITLE'] : $this->request('title'); $description = isset($this->arParams['META']['DESCRIPTION']) ? $this->arParams['META']['DESCRIPTION'] : $this->request('description'); if ($title) { $data['ADDITIONAL_FIELDS']['METAOG_TITLE'] = $title; $data['ADDITIONAL_FIELDS']['METAMAIN_TITLE'] = $title; } if ($description) { $data['ADDITIONAL_FIELDS']['METAOG_DESCRIPTION'] = $description; $data['ADDITIONAL_FIELDS']['METAMAIN_DESCRIPTION'] = $description; } } // from predefined fields if ($this->presetAdditionalFields) { foreach ($this->presetAdditionalFields as $key => $value) { $data['ADDITIONAL_FIELDS'][$key] = $value; } } return $data; } /** * Prepare array of main data. * @param array $data Data item array. * @param bool $request Get data from request. * @return array */ protected function prepareMainFields(array $data, $request = true) { if ($request) { $title = isset($this->arParams['META']['TITLE']) ? $this->arParams['META']['TITLE'] : $this->request('title'); if ($title) { $data['TITLE'] = $title; } } return $data; } /** * Get template manifest. * @param int $id Template id. * @return array */ protected function getTemplateManifest($id) { if ($id < 0) { $http = new HttpClient; $res = $http->get( $this::REMOTE_REPOSITORY_URL . 'landing_cloud.cloud.getAppItemManifest?' . 'user_lang=' . LANGUAGE_ID . '&id=' . (-1 * $id) ); if ($res) { $res = Json::decode($res); } if (isset($res['result']['MANIFEST'])) { return $res['result']['MANIFEST']; } return []; } $res = Demos::getList(array( 'select' => array( 'MANIFEST', 'APP_CODE' ), 'filter' => array( 'ID' => $id ) )); if ($row = $res->fetch()) { $manifest = unserialize($row['MANIFEST'], ['allowed_classes' => false]); if ($manifest) { $manifest['app_code'] = $row['APP_CODE']; } return $manifest; } return array(); } /** * Create one page in site. * @param int $siteId Site id. * @param string $code Page code. * @param \Bitrix\Landing\Landing $landing Landing instance after create. * @return boolean|int Id of new landing. */ public function createPage($siteId, $code, &$landing = null) { $demo = $this->getDemoPage($code); $siteId = intval($siteId); if (is_string($code) && isset($demo[$code])) { $initiatorAppCode = null; // get from rest if ($demo[$code]['REST'] > 0) { $demo[$code]['DATA'] = $this->getTemplateManifest( $demo[$code]['REST'] ); if ($demo[$code]['DATA']) { $initiatorAppCode = $demo[$code]['DATA']['app_code']; } } if (!($data = $demo[$code]['DATA'])) { $this->addError('WRONG_DATA', 'Wrong data'); return false; } $pageData = $this->prepareMainFields( $data['fields'], $this->firstCreatePage ); $pageData = $this->prepareAdditionalFieldsPage( $pageData, $this->firstCreatePage ); $pageData['SITE_ID'] = $siteId; $pageData['ACTIVE'] = 'N'; $pageData['PUBLIC'] = 'N'; $pageData['SYS'] = ($demo[$code]['ACTIVE'] == 'Y') ? 'N' : 'Y'; $pageData['TPL_CODE'] = $code; $pageData['XML_ID'] = $data['name'] . '|' . $code; // localization $pageData = $this->translate( $pageData, $demo[$code]['LANG'] ?? null ); $pageData['ADDITIONAL_FIELDS'] = $this->translate( $pageData['ADDITIONAL_FIELDS'], $demo[$code]['LANG'] ?? null ); // folder if ( isset($this->arParams['ACTION_FOLDER']) && $this->request($this->arParams['ACTION_FOLDER']) ) { $pageData['FOLDER_ID'] = $this->request( $this->arParams['ACTION_FOLDER'] ); } else if ($this->arParams['FOLDER_ID']) { $pageData['FOLDER_ID'] = $this->arParams['FOLDER_ID']; } if ($initiatorAppCode) { $pageData['INITIATOR_APP_CODE'] = $initiatorAppCode; } // add Landing::setEditMode(); $res = Landing::add($pageData); // and fill each page with blocks if ($res->isSuccess()) { $landingId = $res->getId(); $this->oldIds[$data['old_id']] = $landingId; $landing = Landing::createInstance($landingId); if ($landing->exist()) { $sort = 0; $blocks = array(); $blocksIds = array(); $blocksCodes = array(); $blocksAccess = array(); if ($this->arParams['DONT_LEAVE_FRAME'] === 'Y' && $pageData['FOLDER_ID']) { $indexEmpty = \Bitrix\Landing\Folder::getList([ 'select' => [ 'ID' ], 'filter' => [ 'ID' => $pageData['FOLDER_ID'], 'INDEX_ID' => false ] ])->fetch(); if ($indexEmpty) { Site::updateFolder( $landing->getSiteId(), $pageData['FOLDER_ID'], ['INDEX_ID' => $landing->getId()] ); } } if ($demo[$code]['LOCK_DELETE'] ?? false) { \Bitrix\Landing\Lock::lockDeleteLanding($landingId); } if (isset($data['layout']['code'])) { $this->pagesLayouts[$landingId] = $data['layout']; } if (!is_array($data['items'])) { $data['items'] = []; } foreach ($data['items'] as $k => $block) { if (is_array($block)) { if ( isset($this->arParams['PREPARE_BLOCKS_DATA']) && is_array($this->arParams['PREPARE_BLOCKS_DATA']) && array_key_exists($block['code'], $this->arParams['PREPARE_BLOCKS_DATA']) ) { $block['prepare_block_data'] = $this->arParams['PREPARE_BLOCKS_DATA'][$block['code']]; } if ($data['version'] >= 2) { // support rest blocks if ( isset($block['repo_block']['app_code']) && isset($block['repo_block']['xml_id']) ) { $repoBlock = \Bitrix\Landing\Repo::getList(array( 'select' => array( 'ID' ), 'filter' => array( '=APP_CODE' => $block['repo_block']['app_code'], '=XML_ID' => $block['repo_block']['xml_id'] ) ))->fetch(); if ($repoBlock) { $block['code'] = 'repo_' . $repoBlock['ID']; } } if (!isset($block['code'])) { continue; } $blocksCodes[$k] = $block['code']; $block['old_id'] = $block['old_id'] ?? \randString(10); $blockData = [ 'PUBLIC' => 'N', 'SORT' => $sort, 'XML_ID' => $block['old_id'], 'ANCHOR' => isset($block['anchor']) ? $block['anchor'] : '', ]; if (isset($block['prepare_block_data'])) { $blockData['PREPARE_BLOCK_DATA'] = $block['prepare_block_data']; } $blockId = $landing->addBlock( $block['code'], $blockData, ); if (isset($block['access'])) { $blocksAccess[$blockId] = $block['access']; } $blocksIds[$block['old_id']] = $blockId; $sort += 500; $blocks[$blockId] = $k; } else { $block['PUBLIC'] = 'N'; $block['XML_ID'] = strtolower(\randString(10)); $blockId = $landing->addBlock( isset($block['CODE']) ? $block['CODE'] : $k, $block ); $blocks[$k] = $blockId; } } else { $blockId = $landing->addBlock($block, array( 'PUBLIC' => 'N', )); $blocks[$block] = $blockId; } } $blockReplace = []; foreach ($blocksIds as $oldId => $newId) { $blockReplace['\'#block' . $oldId . '\''] = '\'#block' . $newId . '\''; $blockReplace['"#block' . $oldId . '"'] = '"#block' . $newId . '"'; } // redefine content of blocks foreach ($landing->getBlocks() as $k => $block) { $manifest = $block->getManifest(); if (!$manifest) { continue; } $updated = false; if ($data['version'] == 3) { if (isset($data['items'][$blocks[$k]])) { $newData = $data['items'][$blocks[$k]]; // update cards if (isset($newData['cards']) && is_array($newData['cards'])) { $updated = true; $block->updateCards( $newData['cards'] ); } // update style if ( isset($newData['style']) && is_array($newData['style']) && ( !empty($manifest['style']['block']) || !empty($manifest['style']['nodes']) ) ) { $updatedStyles = []; foreach ($newData['style'] as $selector => $classes) { if ($selector == '#wrapper') { $selector = '#' . $block->getAnchor($block->getId()); } $updated = true; foreach ((array)$classes as $clPos => $clVal) { $selectorUpd = $selector . '@' . $clPos; if (!in_array($selectorUpd, $updatedStyles)) { $updatedStyles[] = $selectorUpd; $block->setClasses(array( $selectorUpd => array( 'classList' => (array)$clVal ) )); } } } } // update nodes if (isset($newData['nodes']) && !empty($newData['nodes'])) { $updated = true; $block->updateNodes($newData['nodes']); } // update menu if (isset($newData['menu']) && !empty($newData['menu'])) { $updated = true; $block->updateNodes($newData['menu']); } // update attrs if (isset($newData['attrs']) && !empty($newData['attrs'])) { $updated = true; if (isset($newData['attrs']['#wrapper'])) { $newData['attrs']['#' . $block->getAnchor($block->getId())] = $newData['attrs']['#wrapper']; unset($newData['attrs']['#wrapper']); } $block->setAttributes($newData['attrs']); } // dynamic if (isset($newData['dynamic']) && is_array($newData['dynamic'])) { $block->saveDynamicParams($newData['dynamic']); } // callbacks if (isset($newData['callbacks'])) { if ( isset($newData['callbacks']['afterAdd']['method']) && is_callable($newData['callbacks']['afterAdd']['method']) && in_array( $newData['callbacks']['afterAdd']['method'], self::ALLOWED_CALLBACKS, true ) ) { array_unshift($newData['callbacks']['afterAdd']['params'], $block); call_user_func_array( $newData['callbacks']['afterAdd']['method'], $newData['callbacks']['afterAdd']['params'] ); } } } } else if ($data['version'] == 2) { if (isset($data['items'][$blocks[$k]])) { $newData = $data['items'][$blocks[$k]]; // adjustParams cards if (isset($newData['cards']) && is_array($newData['cards'])) { foreach ($newData['cards'] as $selector => $count) { $changed = false; $block->adjustCards($selector, $count, $changed); if ($changed) { $updated = true; } } } // update style if (isset($newData['style']) && is_array($newData['style']) && !empty($newData['style'])) { foreach ($newData['style'] as $selector => $classes) { if ($selector == '#wrapper') { $selector = '#' . $block->getAnchor($block->getId()); } $updated = true; $block->setClasses(array( $selector => array( 'classList' => array_unique($classes) ) )); } } // update nodes if (isset($newData['nodes']) && !empty($newData['nodes'])) { $updated = true; $block->updateNodes($newData['nodes']); } // update attrs if (isset($newData['attrs']) && !empty($newData['attrs'])) { $updated = true; $block->setAttributes($newData['attrs']); } } } // replace links and some content $content = $block->getContent(); foreach ($blocks as $blockCode => $blockId) { if ($data['version'] == 3) { $count = 0; $content = str_replace( array_keys($blockReplace), array_values($blockReplace), $content, $count ); if ($count) { $updated = true; } } else if ($data['version'] == 2) { $count = 0; $content = str_replace( '@block[' . $blocksCodes[$blockId] . ']', $blockCode, $content, $count ); if ($count) { $updated = true; } } else { $count = 0; $content = str_replace( '@block[' . $blockCode . ']', $blockId, $content, $count ); if ($count) { $updated = true; } } if (isset($data['replace']) && is_array($data['replace'])) { foreach ($data['replace'] as $find => $replace) { $count = 0; $content = str_replace( $find, $replace, $content, $count ); if ($count) { $updated = true; } } } } if (mb_strpos($content, '#TITLE#') !== false) { $updated = true; $content = str_replace( '#TITLE#', \htmlspecialcharsbx($block->getMeta()['LANDING_TITLE']), $content ); } if ($updated) { $block->saveContent($content); $block->save(); } if ( isset($blocksAccess[$block->getId()]) && $blocksAccess[$block->getId()] != \Bitrix\Landing\Block::ACCESS_X ) { \Bitrix\Landing\Internals\BlockTable::update( $block->getId(), [ 'ACCESS' => $blocksAccess[$block->getId()] ] ); } } $this->firstCreatePage = false; return $landing->getId(); } else { $this->setErrors($landing->getError()->getErrors()); return false; } } else { $this->setErrors($res->getErrors()); return false; } } return false; } /** * Get domain id for new site. * @deprecated since 20.0.0 * @return int|string */ protected function getDomainId() { return Type::getDomainId(); } /** * Create demo page for preview. * @param string $code Code of page. * @param array $template Template data. * @return string */ public function getUrlPreview($code, $template = []): string { if (!is_string($code)) { return ''; } if ($this->isRepo()) { return ''; } $url = ''; //template data if (isset($template['PREVIEW_URL'])) { $url = $template['PREVIEW_URL']; } // first detect from rest elseif (($codePos = mb_strrpos($code, '@')) !== false) { $appCode = mb_substr($code, 0, $codePos); $xmlId = mb_substr($code, $codePos + 1); if ($appCode == 'local') { $appCode = ''; } $res = Demos::getList(array( 'select' => array( 'PREVIEW_URL' ), 'filter' => array( '=ACTIVE' => 'Y', '=SHOW_IN_LIST' => 'Y', '=TYPE' => $this->arParams['TYPE'], '=APP_CODE' => $appCode, '=XML_ID' => $xmlId ) )); if ($row = $res->fetch()) { $url = $row['PREVIEW_URL']; } } // default from preview.bitrix24.site else { if (isset($template['DATA']['parent'])) { $code = $template['DATA']['parent']; } $code = str_replace('/', '_', $code); if ( $this->arParams['TYPE'] == Type::SCOPE_CODE_KNOWLEDGE || $this->arParams['TYPE'] == Type::SCOPE_CODE_GROUP ) { $previewSubDir = '/pub/kb/'; } else { $previewSubDir = '/pub/site/'; } $url = 'https://preview.bitrix24.site' . $previewSubDir . $code; } $availableLangs = ['ru', 'de', 'en', 'br', 'fr', 'la', 'pl', 'ua']; $lang = in_array(LANGUAGE_ID, $availableLangs, true) ? LANGUAGE_ID : 'en'; $uri = new Uri($url); $uri->addParams(['user_lang' => $lang]); return $uri->getUri(); } /** * Binding site if, if binding params specified. * @param int $siteId Site id. * @return void */ protected function bindingSite($siteId) { if (empty($siteId)) { return; } $this->arParams['BINDING_TYPE'] = mb_strtoupper($this->arParams['BINDING_TYPE']); if ($this->arParams['BINDING_TYPE'] == 'GROUP') { $binding = new \Bitrix\Landing\Binding\Group( intval(trim($this->arParams['BINDING_ID'])) ); $binding->bindSite($siteId); } else if ($this->arParams['BINDING_TYPE'] == 'MENU') { $binding = new \Bitrix\Landing\Binding\Menu( trim($this->arParams['BINDING_ID']) ); if (!$binding->isForbiddenBindingAction()) { $binding->bindSite($siteId); } } } /** * Create site or page by template. * @param string $code Demo site code. * @param mixed $additional Data from form. * @return boolean */ public function actionSelect($code, $additional = null) { // create page in the site if ( $this->arParams['SITE_WORK_MODE'] != 'Y' && $this->arParams['SITE_ID'] > 0 ) { $landingId = $this->createPage( $this->arParams['SITE_ID'], $code ); if ($landingId) { return $this->redirectToLanding($landingId); } else { return false; } } // else create site and pages into $demo = $this->getDemoSite(); if (isset($demo[$code])) { // get from rest if ($demo[$code]['REST']) { $demo[$code]['DATA'] = $this->getTemplateManifest( $demo[$code]['REST'] ); } if (!($data = $demo[$code]['DATA'])) { $this->addError('WRONG_DATA', 'Wrong data'); return false; } $version = $data['version']; $siteData = $this->prepareMainFields($data['fields'], true); $siteData = $this->prepareAdditionalFieldsSite($siteData); $siteData['ACTIVE'] = 'N'; if (isset($siteData['TITLE'])) { $siteData['CODE'] = \CUtil::translit( $siteData['TITLE'], LANGUAGE_ID ); } else { $siteData['CODE'] = str_replace( '#rand#', mb_strtolower(\randString(5)), $this->urlTpl ); } $siteData['LANG'] = Manager::getZone(); $siteData['TPL_CODE'] = $code; $siteData['XML_ID'] = $data['name'] . '|' . $code; $siteData['TYPE'] = $this->arParams['TYPE']; $pageIndex = $siteData['LANDING_ID_INDEX'] ?? ''; $page404 = $siteData['LANDING_ID_404'] ?? ''; // localization $siteData = $this->translate( $siteData, $demo[$code]['LANG'] ?? null ); $siteData['ADDITIONAL_FIELDS'] = $this->translate( $siteData['ADDITIONAL_FIELDS'], $demo[$code]['LANG'] ?? null ); // first create site if ($this->arParams['SITE_WORK_MODE'] == 'Y') { $siteId = $this->arParams['SITE_ID']; } else { if (self::checkAllowDemoData($siteData)) { $settings = Settings::getDataForSite(); // if shop section exist, save for site $this->initShowcaseList(); $sectionXmlId = null; if (!empty($additional) && is_array($additional)) { if (!empty($additional['section'])) { $sectionXmlId = $additional['section']; } } $sectionId = $this->getParentCatalogSectionId($settings['IBLOCK_ID'], $sectionXmlId); if ($sectionId !== null) { $siteData['ADDITIONAL_FIELDS']['SETTINGS_SECTION_ID'] = $sectionId; } unset($sectionId); // agreement if(!$settings['AGREEMENT_ID'] && Loader::includeModule('crm')) { $siteData['ADDITIONAL_FIELDS']['SETTINGS_AGREEMENT_ID'] = UserConsent::getDefaultAgreementId(); } } // need rewrite CRM-button code from repo $buttons = \Bitrix\Landing\Hook\Page\B24button::getButtons(); $buttons = array_keys($buttons); if (isset($buttons[0])) { $siteData['ADDITIONAL_FIELDS']['B24BUTTON_CODE'] = $buttons[0]; } // if portal have no buttons - set none else { $siteData['ADDITIONAL_FIELDS']['B24BUTTON_CODE'] = 'N'; } if ($data['singleton'] ?? false) { Manager::enableFeatureTmp( Manager::FEATURE_CREATE_SITE ); } if (in_array(Manager::getZone(), ['es', 'de', 'fr', 'it', 'pl', 'uk'])) { $siteData['ADDITIONAL_FIELDS']['COOKIES_USE'] = 'Y'; } $siteData['ADDITIONAL_FIELDS']['SETTINGS_USE_ENHANCED_ECOMMERCE'] = 'N'; $res = Site::add($siteData); Manager::disableFeatureTmp( Manager::FEATURE_CREATE_SITE ); $siteId = $res->getId(); $this->bindingSite($siteId); } if ($siteId) { \Bitrix\Landing\Rights::setGlobalOff(); $siteData['ID'] = $siteId; $forSiteUpdate = array(); $firstLandingId = false; if ($demo[$code]['LOCK_DELETE'] ?? false) { \Bitrix\Landing\Lock::lockDeleteSite($siteId); } if ( !isset($data['syspages']) || !is_array($data['syspages']) ) { $data['syspages'] = array(); } // check system pages for unique foreach (Syspage::get($siteId) as $sysCode => $sysItem) { if (isset($data['syspages'] [$sysCode])) { unset($data['syspages'] [$sysCode]); } } // then create pages $landings = array(); if (empty($data['items'])) { $data['items'][] = $code; } /** @var Landing $landingInstance */ $landingInstance = null; Landing::disableUpdate(); Landing::disableCheckUniqueAddress(); foreach ($data['items'] as $page) { $landingId = $this->createPage( $siteData['ID'], $demo[$code]['APP_CODE'] ? $demo[$code]['APP_CODE'] . '@' . $page : $page, $landingInstance ); if (!$landingId) { continue; } elseif (!$firstLandingId) { $firstLandingId = $landingId; } $landings[$page] = $landingId; } Landing::enableUpdate(); Landing::enableCheckUniqueAddress(); // publication after create if ($landingInstance !== null && $demo[$code]['PUBLICATION']) { $landingInstance->publication(); } $landingReplace = []; foreach ($this->oldIds as $oldId => $newId) { $landingReplace['\'#landing' . $oldId . '\''] = '\'#landing' . $newId . '\''; $landingReplace['"#landing' . $oldId . '"'] = '"#landing' . $newId . '"'; $landingReplaceDynamic['#landing' . $oldId] = '#landing' . $newId; } // update site for some fields if (isset($landings[$pageIndex]) && count($landings) > 1) { $forSiteUpdate['LANDING_ID_INDEX'] = $landings[$pageIndex]; } if (isset($landings[$page404])) { $forSiteUpdate['LANDING_ID_404'] = $landings[$page404]; } // redefine content of pages foreach ($landings as $landCode => $landId) { $landing = Landing::createInstance($landId); if ($landing->exist()) { \Bitrix\Landing\Hook::indexLanding($landId); foreach ($landing->getBlocks() as $block) { $updated = false; $content = $block->getContent(); foreach ($landings as $landCode => $landId) { $count = 0; if ($version == 3) { $content = str_replace( array_keys($landingReplace), array_values($landingReplace), $content, $count ); // dynamic part $dynamicParams = $block->getDynamicParams(); if ($dynamicParams) { $block->saveDynamicParams( $dynamicParams, [ 'linkReplace' => $landingReplaceDynamic ] ); } if ( (is_string($data['type']) && $data['type'] !== 'KNOWLEDGE') || ( is_array($data['type']) && !in_array('KNOWLEDGE', $data['type'], true) ) ) { $content = str_replace( '@landing[' . $landCode . ']', $landId, $content, $count ); } } else { $content = str_replace( '@landing[' . $landCode . ']', $landId, $content, $count ); } if ($count) { $updated = true; } } if ($updated) { $block->saveContent($content); $block->save(); } } } } // set layout $tplsXml = array(); $res = Template::getList(array( 'select' => array( 'ID', 'XML_ID' ) )); while ($row = $res->fetch()) { $tplsXml[$row['XML_ID']] = $row['ID']; } // for site if ( isset($data['layout']['code']) && isset($tplsXml[$data['layout']['code']]) ) { $ref = array(); if (isset($data['layout']['ref'])) { foreach ((array)$data['layout']['ref'] as $ac => $aLidCode) { if (isset($landings[$aLidCode])) { $ref[$ac] = $landings[$aLidCode]; } } } $forSiteUpdate['TPL_ID'] = $tplsXml[$data['layout']['code']]; TemplateRef::setForSite( $siteData['ID'], $ref ); } // and for pages if ($this->pagesLayouts) { foreach ($this->pagesLayouts as $landingId => $layout) { if (isset($tplsXml[$layout['code']])) { Landing::update($landingId, [ 'TPL_ID' => $tplsXml[$layout['code']] ]); if (isset($layout['ref'])) { $ref = []; foreach ((array)$layout['ref'] as $ac => $aLidCode) { if (isset($landings[$aLidCode])) { $ref[$ac] = $landings[$aLidCode]; } } if ($ref) { TemplateRef::setForLanding( $landingId, $ref ); } } } } } // set pages to folders if (isset($data['folders']) && is_array($data['folders'])) { foreach ($data['folders'] as $folderCode => $folderPages) { if (!is_array($folderPages)) { continue; } if (!in_array($folderCode, $folderPages)) { $folderPages[] = $folderCode; } // create folder $folderId = null; $folderIndexId = null; if (isset($landings[$folderCode])) { $res = Landing::getList([ 'select' => [ 'TITLE', 'SITE_ID', 'ID' ], 'filter' => [ 'ID' => $landings[$folderCode] ] ]); if ($page = $res->fetch()) { $folderIndexId = $page['ID']; $folderId = Site::addFolder($page['SITE_ID'], [ 'TITLE' => $page['TITLE'] ])->getId(); } } if (!$folderId) { continue; } // set pages to the folder foreach ($folderPages as $pageCode) { if (isset($landings[$pageCode])) { Landing::update($landings[$pageCode], array( 'FOLDER_ID' => $folderId )); if ($folderIndexId == $landings[$pageCode]) { \Bitrix\Landing\Folder::update($folderId, [ 'INDEX_ID' => $folderIndexId ]); } } } } } // create system refs foreach ($data['syspages'] as $sysCode => $pageCode) { if (isset($landings[$pageCode])) { Syspage::set( $siteData['ID'], $sysCode, $landings[$pageCode] ); } } // update site if need if ($forSiteUpdate) { Site::update($siteData['ID'], $forSiteUpdate); } \Bitrix\Landing\Rights::setGlobalOn(); // send events $event = new \Bitrix\Main\Event('landing', 'onAfterDemoCreate', array( 'id' => $siteData['ID'], 'code' => $code )); $event->send(); $this->redirectToLanding($firstLandingId); } else { $this->setErrors($res->getErrors()); return false; } return true; } return false; } /** * Returns true, if allow create store data. * * @param array $demo * @return bool */ private static function checkAllowDemoData(array $demo): bool { if (!Manager::isB24()) { return false; } if (!isset($demo['TYPE'])) { return false; } return (is_array($demo['TYPE']) ? in_array('STORE', $demo['TYPE']) : $demo['TYPE'] == 'STORE'); } /** * Create store step. * @param string $code Step code. * @param mixed $additional * @return array */ private function stepperStore(string $code, $additional = null): array { $result = [ 'STATUS' => self::STEP_STATUS_COMPLETE, 'MESSAGE' => '', 'FINAL' => true, 'PROGRESS' => 0 ]; $demo = $this->getDemoSite(); if (!is_string($code) || !isset($demo[$code])) { return $result; } if (self::checkAllowDemoData($demo[$code])) { $config = []; if (!empty($additional) && is_array($additional)) { $showcaseId = $additional['SHOWCASE_ID'] ?? null; if (is_string($showcaseId)) { $this->setCurrentShowcaseId($showcaseId); } $iblockId = (int)$additional['IBLOCK_ID'] ?? 0; if ($iblockId > 0) { $config['IBLOCK_ID'] = $iblockId; //TODO: no working now } } $internalResult = $this->createCatalogStep($code, $config); if ($internalResult['FINAL']) { if ($internalResult['STATUS'] == self::STEP_STATUS_ERROR) { $result = $internalResult; } else { $result['MESSAGE'] = $internalResult['MESSAGE']; } $result['PROGRESS'] = 100; } else { $result['STATUS'] = self::STEP_STATUS_CONTINUE; $result['MESSAGE'] = $internalResult['MESSAGE']; $result['FINAL'] = false; $result['PROGRESS'] = $internalResult['PROGRESS']; } } return $result; } /** * Final create store step. * @param string $code Step code. * @param null $additional * @return string */ private function stepperStoreFinalUrl($code, $additional = null): string { $uriSelect = new Uri($this->currentRequest->getRequestUri()); $params = array( 'action' => 'select', 'param' => $code, 'sessid' => bitrix_sessid(), 'additional' => [ 'section' => $this->getCurrentShowcaseSectionXmlId(), ] ); $post = $this->currentRequest->getPostList(); if (!$post->isEmpty()) { $params += $post->toArray(); } $uriSelect->deleteParams(array('sessid', 'stepper', 'action', 'param', 'additional', 'code', 'start')); $uriSelect->addParams($params); unset($post); unset($params); return $uriSelect->getUri(); } /** * Localize the array. * @param array $item Item for localization * @param array $lang Localization array. * @return array */ protected function translate(array $item, $lang) { if ( isset($lang['lang']) && isset($lang['lang_original']) && is_array($lang['lang']) ) { // detect translated messages $translate = null; $langPortal = LANGUAGE_ID; if (in_array($langPortal, ['ru', 'kz', 'by'])) { $langPortal = 'ru'; } $langArray = $lang['lang']; $langOrig = $lang['lang_original']; if (isset($langArray[$langPortal])) { $translate = $langArray[$langPortal]; } else if ( $langOrig != $langPortal && isset($langArray['en']) ) { $translate = $langArray['en']; } if ($translate) { foreach ($item as &$val) { if ( !is_array($val) && isset($translate[$val]) ) { $val = $translate[$val]; } } } } return $item; } /** * Gets demo templates. * @param string $subDir Subdir for data dir. * @param string $code Item code. * @return array */ protected function getDemo($subDir, $code = null) { static $data = array(); static $applicationItems = []; $eventFunc = function($data) use($subDir, $code, &$applicationItems) { // region modify data if (!empty($data)) { // todo: need check singleton? if ($subDir === self::DEMO_DIR_SITE) { // make some items disable, if they are singleton $res = Site::getList([ 'select' => [ 'XML_ID', 'TPL_CODE' ], 'filter' => [ '=TYPE' => $this->arParams['TYPE'], '!==XML_ID' => null, 'CHECK_PERMISSIONS' => 'N' ], 'group' => [ 'XML_ID' ] ]); while ($row = $res->fetch()) { if (!$row['TPL_CODE']) { if (mb_strpos($row['XML_ID'], '|') !== false) { [, $row['TPL_CODE']] = explode('|', $row['XML_ID']); } } if ( isset($data[$row['TPL_CODE']]) && $data[$row['TPL_CODE']]['SINGLETON'] ) { $data[$row['TPL_CODE']]['AVAILABLE'] = false; } if ( isset($data[$row['TPL_CODE']]['DATA']['site_group_item']) && $data[$row['TPL_CODE']]['DATA']['site_group_item'] === 'Y' && isset($data[$row['TPL_CODE']]['DATA']['site_group_parent']) && ($siteGroupParent = $data[$row['TPL_CODE']]['DATA']['site_group_parent']) && isset($data[$siteGroupParent]) && $data[$siteGroupParent]['SINGLETON'] ) { $data[$siteGroupParent]['AVAILABLE'] = false; } } unset($res, $row); } if ($code) { $data = [$code => $data[$code] ?? null]; } } $siteTemplateId = Manager::getTemplateId( Manager::getMainSiteId() ); if ($code) { $xmlId = mb_substr($code, mb_strrpos($code, '@') + 1); $appCode = mb_substr($code, 0, mb_strrpos($code, '@')); } else { $xmlId = $appCode = null; } // endregion // region fill from APPs if (!($this->arResult['IS_SEARCH'] ?? false)) { $res = Demos::getList([ 'select' => [ 'ID', 'APP_CODE', 'XML_ID', 'TYPE', 'TITLE', 'ACTIVE', 'DESCRIPTION', 'LANG', 'PREVIEW', 'PREVIEW2X', 'PREVIEW3X', 'DATE_CREATE', ], 'filter' => [ '=ACTIVE' => 'Y', '=TYPE' => $this->arParams['TYPE'], '=TPL_TYPE' => ($subDir == $this::DEMO_DIR_SITE) ? Demos::TPL_TYPE_SITE : Demos::TPL_TYPE_PAGE, $code ? [ '=XML_ID' => $xmlId, '=APP_CODE' => $appCode, ] : [ '=SHOW_IN_LIST' => 'Y', ], Manager::isTemplateIdSystem($siteTemplateId) ? [ 'LOGIC' => 'OR', ['=SITE_TEMPLATE_ID' => $siteTemplateId], ['=SITE_TEMPLATE_ID' => false], ] : [ ['=SITE_TEMPLATE_ID' => $siteTemplateId], ], ], 'order' => [ 'ID' => 'asc', ], ]); while ($row = $res->fetch()) { $lang = $row['LANG'] ? (array)unserialize($row['LANG'], ['allowed_classes' => false]) : []; if (!$row['APP_CODE']) { $row['APP_CODE'] = 'local'; } $key = $row['APP_CODE'] . '@' . $row['XML_ID']; $data = array( $key => $this->translate(array( 'ID' => $key, 'XML_ID' => $row['XML_ID'], 'TYPE' => mb_strtoupper($row['TYPE']), 'TITLE' => $row['TITLE'], 'ACTIVE' => $row['ACTIVE'], 'AVAILABLE' => true, 'SECTION' => [],//@todo 'DESCRIPTION' => $row['DESCRIPTION'], // 'SORT' => self::matchFullSort($key, self::DEMO_SORT_SCOPE_REST, $row['DATE_CREATE']->getTimeStamp()), 'PREVIEW' => $row['PREVIEW'], 'PREVIEW2X' => $row['PREVIEW2X'], 'PREVIEW3X' => $row['PREVIEW3X'], 'APP_CODE' => $row['APP_CODE'], 'REST' => $row['ID'], 'LANG' => $lang, 'TIMESTAMP' => $row['DATE_CREATE']->getTimeStamp(), 'DESIGNED_BY' => [], 'DATA' => [], ), $lang), ) + $data; } } //endregion // send events $event = new \Bitrix\Main\Event('landing', 'onDemosGetRepository', array( 'data' => $data )); $event->send(); foreach ($event->getResults() as $result) { if ($result->getType() != \Bitrix\Main\EventResult::ERROR) { if (($modified = $result->getModified())) { if (isset($modified['data'])) { $data = $modified['data']; } } } } return $data; }; /** * Attention! method also used into * \Bitrix\Landing\PublicAction\Demos::getFilesList */ if (!isset($data[$subDir])) { // system cache begin $cache = new \CPHPCache(); $cacheTime = 3600; $cacheStarted = false; $siteId = Manager::getMainSiteId(); $siteTemplateId = Manager::getTemplateId($siteId); $cacheId = 'demo_manifest'; $cacheId .= $subDir . $cacheStarted . $this->arParams['TYPE']; $cacheId .= $siteTemplateId . LANGUAGE_ID; $cacheId .= $code ?? 'all'; $cacheId .= ($this->arParams['SITE_ID'] ?? 0) > 0 ? 'onePage' : 'multiPage'; $cacheId .= $this->getFilterToString(); $navigation = $this->getLastNavigation(); $cacheId .= $navigation ? $navigation->getCurrentPage() : 1; $extParams = self::getExtDemoPerms(); foreach($extParams as $param) { $cacheId .= $param; } // market checks $marketPrefix = 'market'; $marketIdDelimiter = '/'; $isNeedMarket = ($this->arParams['SKIP_REMOTE'] ?? 'N') !== 'Y' && (!$code || mb_strpos($code, $marketPrefix . $marketIdDelimiter) === 0) && $this->arParams['TYPE'] === 'PAGE' ; if ($isNeedMarket) { $hasMarket = Loader::includeModule('rest') && is_callable(['\Bitrix\Rest\Marketplace\Client', 'getSiteList']) ; if (!$hasMarket) { $this->setErrors(new Bitrix\Main\Error(Loc::getMessage('LANDING_TPL_REPO_NOT_INSTALL'))); } } $cacheId .= ($isNeedMarket && $hasMarket) ? 'Market_v2' : 'NoMarket'; // nfr - without cache $cachePath = 'landing/demo'; if ( $cache->initCache($cacheTime, $cacheId, $cachePath) && (int)Option::get('bitrix24', 'partner_id', 0) === 0 ) { $data = $cache->getVars(); $navigation->setRecordCount($data['navigation']['recordCount'] ?? 0); if (!empty($data[$subDir])) { return $eventFunc($data[$subDir]); } } if ($cache->startDataCache($cacheTime, $cacheId, $cachePath)) { $cacheStarted = true; if (Cache::isCaching()) { Manager::getCacheManager()->startTagCache($cachePath); Manager::getCacheManager()->registerTag(self::DEMO_TAG); } } $data[$subDir] = []; $data['navigation'] = ['recordCount' => 0]; $siteTypeDef = Site::getDefaultType(); $siteTypeCurr = $this->arParams['TYPE']; // region get LOCAL if (!($this->arResult['IS_SEARCH'] ?? false)) { $pathLocal = '/bitrix/components/bitrix/landing.demo/data/' . $subDir;//@todo make better $path = Manager::getDocRoot() . $pathLocal; $localDirectories = []; $localTemplates = [ 'empty', 'empty-multipage', 'wiki-dark', 'wiki-light', 'store_v3', 'store-chats-dark', 'clothes', 'store-mini-catalog', 'store-mini-one-element', 'search-result', 'search-result2', 'search-result3-dark', 'news-detail', 'requisites', ]; foreach ($localTemplates as $template) { $descPath = $path . '/' . $template . '/.description.php'; if (file_exists($descPath)) { $localDirectories[] = $template; } elseif (($handleSubdir = opendir($path . '/' . $template))) { while ((($entrySubdir = readdir($handleSubdir)) !== false)) { if ($entrySubdir != '.' && $entrySubdir != '..') { $descPath = $path . '/' . $template . '/' . $entrySubdir . '/.description.php'; if (file_exists($descPath)) { $localDirectories[] = $template . '/' . $entrySubdir; } } } } } foreach ($localDirectories as $dir) { $itemData = include $path . '/' . $dir . '/.description.php'; if (!isset($itemData['type'])) { $itemData['type'] = $siteTypeDef; } $itemData['type'] = array_map('strtoupper', (array)$itemData['type']); if (in_array($siteTypeCurr, $itemData['type']) && isset($itemData['name'])) { if (!isset($itemData['fields']) || !is_array($itemData['fields'])) { $itemData['fields'] = array(); } if (!isset($itemData['items']) || !is_array($itemData['items'])) { $itemData['items'] = array(); } if (!isset($itemData['version'])) { $itemData['version'] = 1; } // predefined $itemData['fields']['ACTIVE'] = 'Y'; if (!isset($itemData['fields']['TITLE'])) { $itemData['fields']['TITLE'] = $itemData['name']; } $itemData['old_id'] = $itemData['old_id'] ?? rand(1, 1000); $data[$subDir][$dir] = array( 'ID' => $dir, 'XML_ID' => $dir, 'TYPE' => $itemData['type'], 'TITLE' => $itemData['name'], 'ACTIVE' => $itemData['active'] ?? true, 'PUBLICATION' => $itemData['publication'] ?? false, 'LOCK_DELETE' => $itemData['lock_delete'] ?? false, 'AVAILABLE' => $itemData['available'] ?? true, 'SINGLETON' => $itemData['singleton'] ?? false, 'SECTION' => isset($itemData['section']) ? (array)$itemData['section'] : [], 'DESCRIPTION' => $itemData['description'] ?? '', 'PREVIEW' => file_exists($path . '/' . $dir . '/preview.jpg') ? Manager::getUrlFromFile($pathLocal . '/' . $dir . '/preview.jpg') : '', 'PREVIEW2X' => file_exists($path . '/' . $dir . '/preview@2x.jpg') ? Manager::getUrlFromFile($pathLocal . '/' . $dir . '/preview@2x.jpg') : '', 'PREVIEW3X' => file_exists($path . '/' . $dir . '/preview@3x.jpg') ? Manager::getUrlFromFile($pathLocal . '/' . $dir . '/preview@3x.jpg') : '', 'APP_CODE' => '', 'REST' => 0, 'DATA' => $itemData, ); } } } // endregion // region get from zip repository if ($isNeedMarket && $hasMarket) { $query = [ 'pageSize' => $navigation ? $navigation->getPageSize() : self::COUNT_PER_PAGE, 'page' => $navigation ? $navigation->getCurrentPage() : 1, 'siteType' => self::DEMO_TYPES_FILTER[$siteTypeCurr] ?? 'page', ]; if ($this->arParams['SITE_ID'] > 0) { $query['onePage'] = 'Y'; } if ($code) { $query['code'] = preg_replace(['/^\w+\//i', '/\/\w+$/i'], '', $code); unset($query['onePage'], $query['pageSize'], $query['page']); } // filter $query = array_merge($query, $this->getQueryFromFilter()); $siteList = Client::getSiteList($query); if (is_array($siteList) && is_array($siteList['ITEMS'] ?? null)) { $fakeRecordCount = $siteList['PAGES'] * $navigation->getPageSize(); $navigation->setRecordCount($fakeRecordCount); $data['navigation']['recordCount'] = $fakeRecordCount; foreach ($siteList['ITEMS'] as $site) { $key = implode( $marketIdDelimiter, [ $marketPrefix, $site['APP_CODE'] ] ); if ($code && ($code !== $key)) { continue; } $data[$subDir][$key] = [ 'ID' => $key, 'XML_ID' => '', 'TYPE' => $this->arParams['TYPE'], 'TITLE' => $site['NAME'], 'ACTIVE' => true, 'AVAILABLE' => true, 'SECTION' => $site['SECTION'] ?? [], 'DESCRIPTION' => $site['DESCRIPTION'] ?? $site['APP_SHORT_DESC'], 'THEME_COLOR' => $site['THEME_COLOR'] ?? null, 'PREVIEW' => $site['PREVIEW'] ?? '', 'PREVIEW2X' => $site['PREVIEW_2X'] ?? '', 'PREVIEW3X' => $site['PREVIEW_3X'] ?? '', 'PREVIEW_URL' => $site['URL'] ?? '', 'ZIP_ID' => $site['ID'] ?? '', 'APP_CODE' => $site['APP_CODE'] ?? '', 'DATA' => $site['DATA'] ?? [], 'IS_NEW' => $site['IS_NEW'], 'REST' => 0, 'LANG' => $site['LANG'] ?? LANGUAGE_ID, 'LABELS' => $site['LABELS'] ?? null, ]; if (is_array($site['TAGS']) && in_array('krayt', $site['TAGS'], true)) { $data[$subDir][$key]['DESIGNED_BY'] = 'KRAYT'; } if (is_array($site['TAGS']) && in_array('delobot', $site['TAGS'], true)) { $data[$subDir][$key]['DESIGNED_BY'] = 'DELOBOT'; } } } } // endregion // to change template list by additional params $data[$subDir] = $this->applyExtDemoPerms($data[$subDir]); // system cache end if ($cacheStarted) { $cache->endDataCache($data); if (Cache::isCaching()) { Manager::getCacheManager()->EndTagCache(); } } } return $eventFunc($data[$subDir]); } protected static function getExtDemoPerms(): array { $params = []; $params[] = 'b24partner' . Option::get('landing', 'b24partner', 'N'); // chats can be exist not always if ($chatsEnabled = (Manager::isB24() && ModuleManager::isModuleInstalled('salescenter'))) { $params[] = 'storeChatsY'; } return $params; } protected function applyExtDemoPerms(array $data): array { // not for repo if ($this->isRepo()) { return $data; } // templates for PARTNERS if ( Option::get('landing', 'b24partner', 'N') == 'Y' && $partnerId = Option::get('bitrix24', 'partner_id', 0) ) { if (isset($data['bitrix24'])) { $data['bitrix24']['DATA']['replace']['#partner_id#'] = $partnerId; } if (isset($data['sydney'])) { $data['sydney']['DATA']['replace']['#partner_id#'] = $partnerId; } } else { if (isset($data['bitrix24'])) { unset($data['bitrix24']); } if (isset($data['sydney'])) { unset($data['sydney']); } } // template for STORES IN CHAT if (!(Manager::isB24() && ModuleManager::isModuleInstalled('salescenter'))) { foreach ($data as $code => $value) { if (mb_strpos($code, 'store-chats') !== false) { unset($data[$code]); } } } return $data; } /** * Gets demo site templates. * @param string|null $code Item code. * @return array */ public function getDemoSite(?string $code = null): array { return $this->getDemo($this::DEMO_DIR_SITE, $code); } /** * Gets demo page templates. * @param string $code Item code. * @return array */ public function getDemoPage($code = null) { return $this->getDemo($this::DEMO_DIR_PAGE, $code); } /** * Checking site or page activity depending on portal zone * Format: * $zones['ONLY_IN'] - show site only in these zones * $zones['EXCEPT'] - not show site, if zone in this list * @param array $zones Zones array. * @return bool */ public static function checkActive(array $zones = array()): bool { $result = true; if (!empty($zones)) { $currentZone = Manager::getZone(); if ( isset($zones['ONLY_IN']) && is_array($zones['ONLY_IN']) && !empty($zones['ONLY_IN']) && !in_array($currentZone, $zones['ONLY_IN']) ) { $result = false; } if ( isset($zones['EXCEPT']) && is_array($zones['EXCEPT']) && !empty($zones['EXCEPT']) && in_array($currentZone, $zones['EXCEPT']) ) { $result = false; if ( $currentZone === 'ru' && !Loader::includeModule('bitrix24') && (file_exists($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/lang/ua")) ) { $result = true; } } } return $result; } private function createCatalog(?int $iblockId = null): ?array { if ($this->bitrix24Included) { if (!$this->crmIncluded) { $this->addError( self::IMPORT_CATALOG_ERROR_ID, Loc::getMessage('LANDING_CMP_LD_ERR_CRM_IS_ABSENT') ); return null; } $iblockId = (int)\CCrmCatalog::EnsureDefaultExists(); } else { if ($iblockId === null) { return [ 'PRODUCT_IBLOCK_ID' => self::IBLOCK_AUTODETECT, 'OFFER_IBLOCK_ID' => self::IBLOCK_AUTODETECT, ]; } } return $this->getCatalogInfo($iblockId); } private function getCatalogInfo(int $iblockId): ?array { if ($iblockId <= 0) { $this->addError( self::IMPORT_CATALOG_ERROR_ID, Loc::getMessage('LANDING_CMP_LD_ERR_BAD_IBLOCK_ID') ); return null; } $row = Iblock\IblockTable::getList([ 'select' => ['ID'], 'filter' => ['=ID' => $iblockId], ])->fetch(); if (empty($row)) { $this->addError( self::IMPORT_CATALOG_ERROR_ID, Loc::getMessage('LANDING_CMP_LD_ERR_IBLOCK_IS_ABSENT') ); return null; } $catalog = \CCatalogSku::GetInfoByProductIBlock($iblockId); if (empty($catalog)) { $this->addError( self::IMPORT_CATALOG_ERROR_ID, Loc::getMessage('LANDING_CMP_LD_ERR_IBLOCK_IS_NOT_CATALOG') ); return null; } if ( $catalog['CATALOG_TYPE'] !== \CCatalogSku::TYPE_FULL && $catalog['CATALOG_TYPE'] !== \CCatalogSku::TYPE_PRODUCT ) { $this->addError( self::IMPORT_CATALOG_ERROR_ID, Loc::getMessage('LANDING_CMP_LD_ERR_CATALOG_IS_NOT_SKU_PARENT') ); return null; } return [ 'PRODUCT_IBLOCK_ID' => $catalog['PRODUCT_IBLOCK_ID'], 'OFFER_IBLOCK_ID' => $catalog['IBLOCK_ID'], ]; } /** * Create some highloadblocks. * @return void */ public static function createHLblocks(): void { if (!Loader::includeModule('highloadblock')) { return; } $xmlPath = '/bitrix/components/bitrix/landing.demo/data/xml'; // demo data $sort = 0; $colorValues = array(); $colors = []; $colors['PURPLE'] = [ 'XML_ID' => 'purple', 'PATH' => 'colors_files/iblock/0d3/0d3ef035d0cf3b821449b0174980a712.jpg', 'FILE_NAME' => 'purple.jpg', 'FILE_TYPE' => 'image/jpeg', 'TITLE' => '' ]; $colors['BROWN'] = [ 'XML_ID' => 'brown', 'PATH' => 'colors_files/iblock/f5a/f5a37106cb59ba069cc511647988eb89.jpg', 'FILE_NAME' => 'brown.jpg', 'FILE_TYPE' => 'image/jpeg', 'TITLE' => '' ]; $colors['SEE'] = [ 'XML_ID' => 'see', 'PATH' => 'colors_files/iblock/f01/f01f801e9da96ae5a7f26aae01255f38.jpg', 'FILE_NAME' => 'see.jpg', 'FILE_TYPE' => 'image/jpeg', 'TITLE' => '' ]; $colors['BLUE'] = [ 'XML_ID' => 'blue', 'PATH' => 'colors_files/iblock/c1b/c1ba082577379bdc75246974a9f08c8b.jpg', 'FILE_NAME' => 'blue.jpg', 'FILE_TYPE' => 'image/jpeg', 'TITLE' => '' ]; $colors['ORANGERED'] = [ 'XML_ID' => 'orangered', 'PATH' => 'colors_files/iblock/0ba/0ba3b7ecdef03a44b145e43aed0cca57.jpg', 'FILE_NAME' => 'orangered.jpg', 'FILE_TYPE' => 'image/jpeg', 'TITLE' => '' ]; $colors['REDBLUE'] = [ 'XML_ID' => 'redblue', 'PATH' => 'colors_files/iblock/1ac/1ac0a26c5f47bd865a73da765484a2fa.jpg', 'FILE_NAME' => 'redblue.jpg', 'FILE_TYPE' => 'image/jpeg', 'TITLE' => '' ]; $colors['RED'] = [ 'XML_ID' => 'red', 'PATH' => 'colors_files/iblock/0a7/0a7513671518b0f2ce5f7cf44a239a83.jpg', 'FILE_NAME' => 'red.jpg', 'FILE_TYPE' => 'image/jpeg', 'TITLE' => '' ]; $colors['GREEN'] = [ 'XML_ID' => 'green', 'PATH' => 'colors_files/iblock/b1c/b1ced825c9803084eb4ea0a742b2342c.jpg', 'FILE_NAME' => 'green.jpg', 'FILE_TYPE' => 'image/jpeg', 'TITLE' => '' ]; $colors['WHITE'] = [ 'XML_ID' => 'white', 'PATH' => 'colors_files/iblock/b0e/b0eeeaa3e7519e272b7b382e700cbbc3.jpg', 'FILE_NAME' => 'white.jpg', 'FILE_TYPE' => 'image/jpeg', 'TITLE' => '' ]; $colors['BLACK'] = [ 'XML_ID' => 'black', 'PATH' => 'colors_files/iblock/d7b/d7bdba8aca8422e808fb3ad571a74c09.jpg', 'FILE_NAME' => 'black.jpg', 'FILE_TYPE' => 'image/jpeg', 'TITLE' => '' ]; $colors['PINK'] = [ 'XML_ID' => 'pink', 'PATH' => 'colors_files/iblock/1b6/1b61761da0adce93518a3d613292043a.jpg', 'FILE_NAME' => 'pink.jpg', 'FILE_TYPE' => 'image/jpeg', 'TITLE' => '' ]; $colors['AZURE'] = [ 'XML_ID' => 'azure', 'PATH' => 'colors_files/iblock/c2b/c2b274ad2820451d780ee7cf08d74bb3.jpg', 'FILE_NAME' => 'azure.jpg', 'FILE_TYPE' => 'image/jpeg', 'TITLE' => '' ]; $colors['JEANS'] = [ 'XML_ID' => 'jeans', 'PATH' => 'colors_files/iblock/24b/24b082dc5e647a3a945bc9a5c0a200f0.jpg', 'FILE_NAME' => 'jeans.jpg', 'FILE_TYPE' => 'image/jpeg', 'TITLE' => '' ]; $colors['FLOWERS'] = [ 'XML_ID' => 'flowers', 'PATH' => 'colors_files/iblock/64f/64f32941a654a1cbe2105febe7e77f33.jpg', 'FILE_NAME' => 'flowers.jpg', 'FILE_TYPE' => 'image/jpeg', 'TITLE' => '' ]; $colors['DARKBLUE'] = [ 'XML_ID' => 'darkblue', 'PATH' => 'colors_files/iblock/84a/84afl562rq429820451d780ee7cf08d7.png', 'FILE_NAME' => 'darkblue.png', 'FILE_TYPE' => 'image/png', 'TITLE' => '' ]; $colors['DARKGREEN'] = [ 'XML_ID' => 'darkgreen', 'PATH' => 'colors_files/iblock/87f/87f5d3ad34562rq429820451d780ee7c.png', 'FILE_NAME' => 'darkgreen.png', 'FILE_TYPE' => 'image/png', 'TITLE' => '' ]; $colors['GREY'] = [ 'XML_ID' => 'grey', 'PATH' => 'colors_files/iblock/90c/90c274ad2820451d780ee7cf08d74bb3.png', 'FILE_NAME' => 'grey.png', 'FILE_TYPE' => 'image/png', 'TITLE' => '' ]; $colors['YELLOW'] = [ 'XML_ID' => 'yellow', 'PATH' => 'colors_files/iblock/99a/99a082dc5e647a3a945bc9a5c0a200f0.png', 'FILE_NAME' => 'yellow.png', 'FILE_TYPE' => 'image/png', 'TITLE' => '' ]; $colors['ORANGE'] = [ 'XML_ID' => 'orange', 'PATH' => 'colors_files/iblock/a0d/a0ddba8aca8422e808fb3ad571a74c09.png', 'FILE_NAME' => 'orange.png', 'FILE_TYPE' => 'image/png', 'TITLE' => '' ]; foreach (array_keys($colors) as $index) { $colors[$index]['TITLE'] = Loc::getMessage('LANDING_CMP_COLOR_'.$index); } Main\Type\Collection::sortByColumn($colors, ['TITLE' => SORT_ASC]); foreach($colors as $row) { $sort += 100; $colorValues[] = [ 'UF_NAME' => $row['TITLE'], 'UF_FILE' => [ 'name' => $row['FILE_NAME'], 'type' => $row['FILE_TYPE'], 'tmp_name' => Manager::getDocRoot().$xmlPath.'/hl/'.$row['PATH'] ], 'UF_SORT' => $sort, 'UF_DEF' => '0', 'UF_XML_ID' => $row['XML_ID'] ]; } $sort = 0; $brandValues = array(); $brands = array( 'Company1' => 'brands_files/cm-01.png', 'Company2' => 'brands_files/cm-02.png', 'Company3' => 'brands_files/cm-03.png', 'Company4' => 'brands_files/cm-04.png', 'Brand1' => 'brands_files/bn-01.png', 'Brand2' => 'brands_files/bn-02.png', 'Brand3' => 'brands_files/bn-03.png', ); foreach ($brands as $brandName => $brandFile) { $sort += 100; $brandValues[] = array( 'UF_NAME' => $brandName, 'UF_FILE' => array ( 'name' => mb_strtolower($brandName).'.jpg', 'type' => 'image/jpeg', 'tmp_name' => Manager::getDocRoot() . $xmlPath . '/hl/' . $brandFile ), 'UF_SORT' => $sort, 'UF_XML_ID' => mb_strtolower($brandName) ); } // some tables $tables = array( 'eshop_color_reference' => array( 'name' => 'ColorReference', 'fields' => array( array( 'FIELD_NAME' => 'UF_NAME', 'USER_TYPE_ID' => 'string', 'XML_ID' => 'UF_COLOR_NAME' ), array( 'FIELD_NAME' => 'UF_FILE', 'USER_TYPE_ID' => 'file', 'XML_ID' => 'UF_COLOR_FILE' ), array( 'FIELD_NAME' => 'UF_SORT', 'USER_TYPE_ID' => 'double', 'XML_ID' => 'UF_COLOR_SORT' ), array( 'FIELD_NAME' => 'UF_DEF', 'USER_TYPE_ID' => 'boolean', 'XML_ID' => 'UF_COLOR_DEF' ), array( 'FIELD_NAME' => 'UF_XML_ID', 'USER_TYPE_ID' => 'string', 'XML_ID' => 'UF_XML_ID' ) ), 'values' => $colorValues ), 'eshop_brand_reference' => array( 'name' => 'BrandReference', 'fields' => array( array( 'FIELD_NAME' => 'UF_NAME', 'USER_TYPE_ID' => 'string', 'XML_ID' => 'UF_BRAND_NAME' ), array( 'FIELD_NAME' => 'UF_FILE', 'USER_TYPE_ID' => 'file', 'XML_ID' => 'UF_BRAND_FILE' ), array( 'FIELD_NAME' => 'UF_SORT', 'USER_TYPE_ID' => 'double', 'XML_ID' => 'UF_BRAND_SORT' ), array( 'FIELD_NAME' => 'UF_XML_ID', 'USER_TYPE_ID' => 'string', 'XML_ID' => 'UF_XML_ID' ) ), 'values' => $brandValues ) ); // create tables and fill with demo-data foreach ($tables as $tableName => &$table) { $tableId = null; // if this hl isn't exist $res = Highloadblock\HighloadBlockTable::getList([ 'select' => [ 'ID', 'NAME', 'TABLE_NAME', ], 'filter' => [ '=NAME' => $table['name'], '=TABLE_NAME' => $tableName ] ]); $row = $res->fetch(); unset($res); if (empty($row)) { // add new hl block $result = Highloadblock\HighloadBlockTable::add(array( 'NAME' => $table['name'], 'TABLE_NAME' => $tableName )); if ($result->isSuccess()) { $sort = 100; $tableId = $result->getId(); // add fields $userField = new \CUserTypeEntity; foreach ($table['fields'] as $field) { $field['ENTITY_ID'] = 'HLBLOCK_' . $tableId; $res = \CUserTypeEntity::getList( array(), array( 'ENTITY_ID' => $field['ENTITY_ID'], 'FIELD_NAME' => $field['FIELD_NAME'] ) ); if (!$res->Fetch()) { $field['SORT'] = $sort; $userField->Add($field); $sort += 100; } } } } else { $tableId = (int)$row['ID']; } // add data if (!empty($tableId)) { $hldata = Highloadblock\HighloadBlockTable::getById($tableId)->fetch(); $hlentity = Highloadblock\HighloadBlockTable::compileEntity($hldata); $entityClass = $hlentity->getDataClass(); foreach ($table['values'] as $item) { $rowColor = $entityClass::getList([ 'select' => ['ID'], 'filter' => [ '=UF_XML_ID' => $item['UF_XML_ID'] ], ])->fetch(); if (empty($rowColor)) { $entityClass::add($item); } } } } } /** * Create catalog step. * @param string $xmlcode Step code. * @param array $config Execute config. * @return array */ private function createCatalogStep(string $xmlcode, array $config = []): array { $result = [ 'STATUS' => self::STEP_STATUS_ERROR, 'MESSAGE' => '', 'FINAL' => true, 'PROGRESS' => 0 ]; if ( !$this->iblockIncluded || !$this->catalogIncluded ) { $result['MESSAGE'] = Loc::getMessage('LANDING_CMP_ERROR_MASTER_NO_SERVICE'); return $result; } $showcaseId = $this->getCurrentShowcaseId(); if (empty($showcaseId)) { $result['STATUS'] = self::STEP_STATUS_COMPLETE; return $result; } $showcase = $this->getCurrentShowcase(); $parentXmlId = $showcase['XML_LIST'][0]; $offerXmlId = $showcase['XML_LIST'][1]; if ($this->bitrix24Included) { \CBitrix24::createIblockDemodataFileBucket(); } $stepConfig = []; // TODO: add IBLOCK_LIST support $this->initStepStorage($stepConfig); $result['STATUS'] = self::STEP_STATUS_CONTINUE; $result['FINAL'] = false; switch ($this->getCurrentStep()) { case self::STEP_ID_CREATE_CATALOG: $this->createCatalog(); $this->nextStep(); $result['PROGRESS'] = 15; break; case self::STEP_ID_HIGHLOADBLOCK: $this->createHLblocks(); $this->nextStep(); $result['MESSAGE'] = Loc::getMessage('LANDING_CMP_LD_MESS_DATA_PREPARE'); $result['PROGRESS'] = 50; break; case self::STEP_ID_PREPARE_CRM_CATALOG: $this->transferCrmCatalogXmlId(); $this->nextStep(); $result['MESSAGE'] = Loc::getMessage('LANDING_CMP_LD_MESS_DATA_PREPARE'); $result['PROGRESS'] = 100; break; case self::STEP_ID_XML_IMPORT: $importResult = $this->importXmlFile(); $result['MESSAGE'] = $importResult['MESSAGE']; $result['PROGRESS'] = $importResult['PROGRESS']; if ($result['PROGRESS'] > 100) { $result['PROGRESS'] = $result['PROGRESS'] % 100; } if ($importResult['FINAL']) { if ($importResult['STATUS'] == self::STEP_STATUS_ERROR) { $result['STATUS'] = self::STEP_STATUS_ERROR; $result['FINAL'] = true; } else { $this->nextStep(); } } unset($importResult); break; case self::STEP_ID_ADDITIONAL_UPDATE: $this->updateImportedIblocks( (int)$this->getXmlIblockId($parentXmlId), (int)$this->getXmlIblockId($offerXmlId) ); $this->nextStep(); $result['MESSAGE'] = Loc::getMessage('LANDING_CMP_LD_MESS_CATALOG_UPDATE'); $result['PROGRESS'] = 50; break; case self::STEP_ID_CATALOG_REINDEX: $this->reindexCatalog( (int)$this->getXmlIblockId($parentXmlId), (int)$this->getXmlIblockId($offerXmlId) ); $this->nextStep(); $result['MESSAGE'] = Loc::getMessage('LANDING_CMP_LD_MESS_CATALOG_UPDATE'); $result['PROGRESS'] = 100; break; case self::STEP_ID_FINAL: $result = [ 'STATUS' => self::STEP_STATUS_COMPLETE, 'MESSAGE' => Loc::getMessage('LANDING_CMP_LD_MESS_IMPORT_COMPLETE'), 'FINAL' => true, 'PROGRESS' => 100 ]; break; default: $result['MESSAGE'] = Loc::getMessage('LANDING_CMP_LD_ERROR_UNKNOWN_STEP_ID'); $result['STATUS'] = self::STEP_STATUS_ERROR; $result['FINAL'] = true; break; } if ($result['FINAL']) { $this->destroyStepStorage(); } return $result; } /** * Base executable method. * @return void */ public function executeComponent() { $init = $this->init(); if (!$init) { parent::executeComponent(); return; } $this->initRequiredModules(); $this->getRemoteTemplates = true; $application = Manager::getApplication(); set_time_limit(300); $this->checkParam('SITE_ID', 0); $this->checkParam('FOLDER_ID', 0); $this->checkParam('TYPE', ''); $this->checkParam('SKIP_REMOTE', 'N'); $this->checkParam('FILTER', []); \Bitrix\Landing\Hook::setEditMode(true); Type::setScope($this->arParams['TYPE']); // check access if ($this->arParams['SITE_ID'] > 0) { $hasAccess = Rights::hasAccessForSite( $this->arParams['SITE_ID'], Rights::ACCESS_TYPES['edit'] ); } else { $hasAccess = Rights::hasAdditionalRight( Rights::ADDITIONAL_RIGHTS['create'] ); } if (!$hasAccess) { $init = false; $this->addError('ACCESS_DENIED', '', true); } // if all ok if ($init) { $this->checkParam('ACTION_FOLDER', 'folderId'); $this->checkParam('PAGE_URL_SITES', ''); $this->checkParam('PAGE_URL_LANDING_VIEW', ''); $this->checkParam('SITE_WORK_MODE', 'N'); $this->checkParam('DONT_LEAVE_FRAME', 'N'); $this->checkParam('BINDING_TYPE', ''); $this->checkParam('BINDING_ID', ''); // save frame state in ajax requests $this->arResult['IS_AJAX'] = $this->isAjax(); $this->arResult['IS_FRAME'] = $this->request('IFRAME') === 'Y' || $this->request('IS_FRAME') === 'Y'; // Filter $this->arResult['FILTER_URI'] = $this->getUri( [ 'IS_AJAX' => 'Y', 'IS_FRAME' => $this->arResult['IS_FRAME'] ? 'Y' : 'N' ], ['IFRAME', 'IFRAME_TYPE'] ); if ( $this->arParams['TYPE'] === 'PAGE' && !$this->request('action') ) { $this->arResult['FILTER_FIELDS'] = self::getFilterFields(); $this->arResult['FILTER_ID'] = self::FILTER_ID . '_' . $this->arParams['TYPE']; $this->arResult['FILTER_PRESETS'] = self::getFilterPresets(); $this->arResult['FILTER_OPTIONS'] = new Filter\Options( $this->arResult['FILTER_ID'], $this->arResult['FILTER_PRESETS'] ); $this->arResult['FILTER'] = $this->arResult['FILTER_OPTIONS']->getFilter(); } $this->arResult['IS_SEARCH'] = isset($this->arResult['FILTER']) && is_array($this->arResult['FILTER']) && !empty($this->arResult['FILTER']) ; // init nav $this->arResult['NAV_URI'] = $this->arResult['IS_FRAME'] ? $this->getUri(['IFRAME' => 'Y', 'IFRAME_TYPE' => 'SIDE_SLIDER'], ['IS_AJAX', 'IS_FRAME']) : $this->getUri([], ['IS_AJAX', 'IS_FRAME']) ; $this->lastNavigation = new PageNavigation(self::NAVIGATION_ID); $this->lastNavigation->allowAllRecords(false) ->setPageSize($this::COUNT_PER_PAGE) ->initFromUri(); if ( $this->arParams['SITE_ID'] > 0 && $this->arParams['SITE_WORK_MODE'] != 'Y' ) { $this->arResult['DEMO'] = $this->getDemoPage(); $this->arResult['LIMIT_REACHED'] = false; } else { $this->arResult['DEMO'] = $this->getDemoSite(); $this->arResult['LIMIT_REACHED'] = !Manager::checkFeature( Manager::FEATURE_CREATE_SITE, [ 'type' => $this->arParams['TYPE'] ] ); } // check external preview (additional step on preview click) $event = new Event('landing', 'onBuildTemplatePreviewUrl'); $event->send(); foreach ($event->getResults() as $result) { if ($result->getType() != EventResult::ERROR) { if ($externalPreview = $result->getModified()) { foreach ((array)$externalPreview as $code => $url) { if (isset($this->arResult['DEMO'][$code])) { $this->arResult['DEMO'][$code]['EXTERNAL_URL'] = $url; } } } } } // may be in future we will use sections, // but now sections used only for system things foreach ($this->arResult['DEMO'] as $code => $item) { if ($item['SECTION'] || !$item['ACTIVE']) { unset($this->arResult['DEMO'][$code]); } } $this->arResult['NAVIGATION'] = $this->getLastNavigation(); } $action = $this->request('stepper'); $param = $this->request('param'); $additional = $this->request('additional'); $stepper = 'stepper'.$action; $stepperFinalUrl = 'stepper'.$action.'FinalUrl'; if ($action && is_callable([$this, $stepper]) && is_callable([$this, $stepperFinalUrl])) { if (!check_bitrix_sessid()) { \localRedirect($this->getUri()); } else { $this->initShowcase(); if ($this->request('start') === 'Y') { $settings = Settings::getDataForSite(); // if shop section exist, save for site, else make import $sectionId = $this->getParentCatalogSectionId( $settings['IBLOCK_ID'], $this->getCurrentShowcaseSectionXmlId() ); if ($sectionId !== null) { $result = [ 'status' => 'final', 'message' => '', 'url' => $this->{$stepperFinalUrl}($param, $additional) ]; $application->restartBuffer(); echo Main\Web\Json::encode($result); die(); } } /** @var array $result */ $stepperResult = $this->{$stepper}($param, $additional); switch ($stepperResult['STATUS']) { case self::STEP_STATUS_CONTINUE: $result = [ 'status' => 'continue', 'message' => $stepperResult['MESSAGE'], 'progress' => $stepperResult['PROGRESS'] ]; $application->restartBuffer(); echo Main\Web\Json::encode($result); die(); break; case self::STEP_STATUS_ERROR: $this->addError('CALLBACK_ERROR', $stepperResult['MESSAGE']); break; case self::STEP_STATUS_COMPLETE: $result = [ 'status' => 'final', 'message' => $stepperResult['MESSAGE'], 'progress' => $stepperResult['PROGRESS'], 'url' => $this->{$stepperFinalUrl}($param, $additional) ]; $application->restartBuffer(); echo Main\Web\Json::encode($result); die(); break; default: \localRedirect($this->getUri()); break; } } } parent::executeComponent(); } protected function initRequiredModules(): void { $this->bitrix24Included = Loader::includeModule('bitrix24'); $this->iblockIncluded = Loader::includeModule('iblock'); $this->catalogIncluded = Loader::includeModule('catalog'); $this->crmIncluded = Loader::includeModule('crm'); } private static function changeProductPropertyXmlId(int $iblockId): void { $list = [ ['CODE' => 'NEWPRODUCT', 'XML_ID' => 'af49d0e309af4fac506a8a228000efc5'], ['CODE' => 'SALELEADER', 'XML_ID' => '103'], ['CODE' => 'SPECIALOFFER', 'XML_ID' => '5'], ['CODE' => 'ARTNUMBER', 'XML_ID' => '10', 'NEW_XML_ID' => 'CML2_ARTICLE'], ['CODE' => 'MANUFACTURER', 'XML_ID' => '12'], ['CODE' => 'MATERIAL', 'XML_ID' => '11'], ['CODE' => 'COLOR', 'XML_ID' => '291'], ['CODE' => 'BLOG_POST_ID', 'XML_ID' => '43'], ['CODE' => 'BLOG_COMMENTS_CNT', 'XML_ID' => '44'], ['CODE' => 'BACKGROUND_IMAGE', 'XML_ID' => '45'], ['CODE' => 'MORE_PHOTO', 'XML_ID' => 'MORE_PHOTO', 'NEW_XML_ID' => 'CML2_PICTURES'] ]; self::changePropertyXmlId($iblockId, $list); unset($list); } private static function changeOfferPropertyXmlId(int $iblockId): void { $list = [ ['CODE' => 'ARTNUMBER', 'XML_ID' => '38', 'NEW_XML_ID' => 'CML2_ARTICLE'], ['CODE' => 'ARTNUMBER', 'XML_ID' => 'ARTNUMBER', 'NEW_XML_ID' => 'CML2_ARTICLE'], ['CODE' => 'SIZES_SHOES', 'XML_ID' => '4510'], ['CODE' => 'SIZES_CLOTHES', 'XML_ID' => '40'], ['CODE' => 'MORE_PHOTO', 'XML_ID' => '39', 'NEW_XML_ID' => 'CML2_PICTURES'], ['CODE' => 'MORE_PHOTO', 'XML_ID' => 'MORE_PHOTO', 'NEW_XML_ID' => 'CML2_PICTURES'], ]; self::changePropertyXmlId($iblockId, $list); unset($list); } private static function changePropertyXmlId(int $iblockId, array $list): void { $xmlCodes = []; $iterator = Iblock\PropertyTable::getList([ 'select' => ['ID', 'XML_ID'], 'filter' => ['=IBLOCK_ID' => $iblockId] ]); while ($row = $iterator->fetch()) { $row['XML_ID'] = (string)$row['XML_ID']; $row['ID'] = (int)$row['ID']; if ($row['XML_ID'] != '') { $xmlCodes[$row['XML_ID']] = $row; } } unset($row, $iterator); foreach ($list as $property) { $iterator = Iblock\PropertyTable::getList([ 'select' => ['ID', 'XML_ID', 'CODE'], 'filter' => [ '=IBLOCK_ID' => $iblockId, '=CODE' => $property['CODE'], '=XML_ID' => $property['XML_ID'] ] ]); $row = $iterator->fetch(); if (!empty($row)) { $newXmlId = $property['NEW_XML_ID'] ?? $property['CODE']; if (isset($xmlCodes[$newXmlId])) { $old = $xmlCodes[$property['XML_ID']]; Iblock\PropertyTable::update( $old['ID'], ['XML_ID' => $old['XML_ID'].'_OLD', 'CODE' => $old['CODE'].'_OLD'] ); } Iblock\PropertyTable::update( $row['ID'], ['XML_ID' => $newXmlId] ); } } unset($row, $iterator); unset($property); unset($xmlCodes); } private static function transferOfferListProperties(int $iblockId): void { $list = [ [ 'CODE' => 'SIZES_SHOES', 'PROPERTY_TYPE' => Iblock\PropertyTable::TYPE_LIST, 'DEFAULT' => 'N', 'VALUES' => [ [ 'VALUE' => '35', 'XML_ID' => 'd5c054b792e65b6f093fa81313570f0b', 'NEW_XML_ID' => 'shoesize35', ], [ 'VALUE' => '36', 'XML_ID' => '07be2c1628d03a7cf0f194eeb3595853', 'NEW_XML_ID' => 'shoesize36', ], [ 'VALUE' => '37', 'XML_ID' => 'bcf799ba1361be1e5c3c8a38aac331d3', 'NEW_XML_ID' => 'shoesize37', ], [ 'VALUE' => '38', 'XML_ID' => '05954c7cb32f164bdf507c34230b547d', 'NEW_XML_ID' => 'shoesize38', ], [ 'VALUE' => '39', 'XML_ID' => 'cbe3a6965734b6cea57ffdf6b0259254', 'NEW_XML_ID' => 'shoesize39', ], [ 'VALUE' => '40', 'XML_ID' => '9f7530be7c4439529be99615cf2cdf1f', 'NEW_XML_ID' => 'shoesize40', ], ], ], [ 'CODE' => 'SIZES_CLOTHES', 'PROPERTY_TYPE' => Iblock\PropertyTable::TYPE_LIST, 'DEFAULT' => 'N', 'VALUES' => [ [ 'VALUE' => 'XS', 'XML_ID' => 'a11f96c3b88d222460d9796067d28b0c', 'NEW_XML_ID' => 'sizeXS', ], [ 'VALUE' => 'S', 'XML_ID' => 'be1079a982cc85bbdfec9b2cffe132c2', 'NEW_XML_ID' => 'sizeS', ], [ 'VALUE' => 'M', 'XML_ID' => 'a2f1730e4dacc24cae7fd200e20ecb15', 'NEW_XML_ID' => 'sizeM', ], [ 'VALUE' => 'L', 'XML_ID' => '309a4b56bb562106fcaffaa45595c200', 'NEW_XML_ID' => 'sizeL', ], [ 'VALUE' => 'XL', 'XML_ID' => '98d8be59b4d50201222aa8fa85410395', 'NEW_XML_ID' => 'sizeXL', ], [ 'VALUE' => 'XXL', 'XML_ID' => '58178408c32af4f9205a5f0d1f16b90c', 'NEW_XML_ID' => 'sizeXXL', ], [ 'VALUE' => 'XXXL', 'XML_ID' => '07249452260df37df35152cef9352bec', 'NEW_XML_ID' => 'sizeXXXL', ], ] ] ]; self::transferListProperties($iblockId, $list); } private static function transferListProperties(int $iblockId, array $list): void { foreach ($list as $row) { $property = Iblock\PropertyTable::getList([ 'select' => ['ID'], 'filter' => [ '=IBLOCK_ID' => $iblockId, '=CODE' => $row['CODE'], '=PROPERTY_TYPE' => $row['PROPERTY_TYPE'], ], ])->fetch(); if (!empty($property)) { $property['ID'] = (int)$property['ID']; if (isset($row['DEFAULT']) && $row['DEFAULT'] === 'N') { $defaultValue = Iblock\PropertyEnumerationTable::getList([ 'select' => ['ID', 'PROPERTY_ID'], 'filter' => [ '=PROPERTY_ID' => $property['ID'], '=DEF' => 'Y' ], ])->fetch(); if (!empty($defaultValue)) { Iblock\PropertyEnumerationTable::update( $defaultValue, ['DEF' => 'N'] ); } } if (!empty($row['VALUES']) && is_array($row['VALUES'])) { foreach ($row['VALUES'] as $item) { $value = Iblock\PropertyEnumerationTable::getList([ 'select' => ['ID'], 'filter' => [ '=PROPERTY_ID' => $property['ID'], '=VALUE' => $item['VALUE'], '=XML_ID' => $item['XML_ID'], ], ])->fetch(); if (!empty($value)) { \CIBlockPropertyEnum::Update( $value['ID'], ['XML_ID' => $item['NEW_XML_ID']] ); } } } } } } /** * Checking iblock by xml id. * @param int $iblockId Iblock id. * @param string $xmlId External code. * @return void */ private static function checkIblockXmlId(int $iblockId, string $xmlId): void { $iterator = Iblock\IblockTable::getList([ 'select' => ['ID', 'XML_ID'], 'filter' => ['=ID' => $iblockId] ]); $row = $iterator->fetch(); unset($iterator); if (!empty($row) && $row['XML_ID'] != $xmlId) { $iblock = new \CIBlock(); $iblock->Update($iblockId, ['XML_ID' => $xmlId]); unset($iblock); } unset($row); } /** * Prepare crm iblocks XML_ID for xml import. * @return void */ private function transferCrmCatalogXmlId() { if (!$this->crmIncluded) { return; } $iblockId = (int)\CCrmCatalog::EnsureDefaultExists(); if ($iblockId > 0) { self::checkIblockXmlId($iblockId, 'FUTURE-1C-CATALOG'); if ($this->bitrix24Included) { self::changeProductPropertyXmlId($iblockId); } } $catalog = \CCatalogSku::GetInfoByProductIBlock($iblockId); if (!empty($catalog)) { self::checkIblockXmlId($catalog['IBLOCK_ID'], 'FUTURE-1C-CATALOG-OFFERS'); if ($this->bitrix24Included) { self::changeOfferPropertyXmlId($catalog['IBLOCK_ID']); self::transferOfferListProperties($catalog['IBLOCK_ID']); } } unset($catalog, $iblockId); } /** * Set base currency for xml. * @return void */ private function setXmlBaseCurrency() { $callback = function(\Bitrix\Main\Event $event) { static $baseCurrency = null; if ($baseCurrency === null) { $baseCurrency = false; if (\Bitrix\Main\Loader::includeModule('currency')) { $baseCurrency = \Bitrix\Currency\CurrencyManager::getBaseCurrency(); } } $result = new \Bitrix\Main\Entity\EventResult; $result->modifyFields(array( 'fields' => array( 'CURRENCY' => $baseCurrency ) )); return $result; }; $eventManager = \Bitrix\Main\EventManager::getInstance(); $eventManager->addEventHandler( 'catalog', 'Bitrix\Catalog\Model\Price::OnBeforeAdd', $callback ); $eventManager->addEventHandler( 'catalog', 'Bitrix\Catalog\Model\Price::OnBeforeUpdate', $callback ); } /** * Xml import with internal steps. * @return array */ private function importXmlFile(): array { $result = [ 'STATUS' => self::STEP_STATUS_CONTINUE, 'MESSAGE' => '', 'FINAL' => true, 'PROGRESS' => 0 ]; $importer = new \CIBlockXmlImport(); $xmlProductCatalog = 'CRM_PRODUCT_CATALOG'; $this->setXmlBaseCurrency(); $xml = $this->getCurrentXml(); $parameters = [ 'FILE' => $this->getCurrentXmlFilePath(), 'IBLOCK_TYPE' => $xmlProductCatalog, 'SITE_LIST' => [SITE_ID], 'MISSING_SECTION_ACTION' => \CIBlockXmlImport::ACTION_NOTHING, 'MISSING_ELEMENT_ACTION' => \CIBlockXmlImport::ACTION_NOTHING, 'INTERVAL' => 20, ]; $config = [ 'USE_CRC' => false, 'PREVIEW_PICTURE_SETTINGS' => false, 'DETAIL_PICTURE_SETTINGS' => false, 'READ_BLOCKSIZE' => 16384, 'IBLOCK_CACHE_MODE' => \CIBlockCMLImport::IBLOCK_CACHE_FREEZE, ]; $importer->init($parameters, $config); if (!$importer->isSuccess()) { $result['STATUS'] = self::STEP_STATUS_ERROR; $result['MESSAGE'] = implode("\n", $importer->getErrors()); return $result; } $importer->run(); $importResult = $importer->getStepResult(); if ($importResult['TYPE'] == \CIBlockXmlImport::RESULT_TYPE_SUCCESS) { if ($importResult['IS_FINAL'] == 'Y') { $this->setXmlIblockId($xml, $importer->getIblockId()); $nextXml = $this->getNextXml(); if ($nextXml === null) { $result = [ 'STATUS' => self::STEP_STATUS_COMPLETE, 'MESSAGE' => Loc::getMessage('LANDING_CMP_LD_MESS_XML_IMPORT_COMPLETE'), 'FINAL' => true, 'PROGRESS' => 100 ]; $this->resetStepParameters(); } else { $this->setCurrentXml($nextXml); $result['MESSAGE'] = $this->importXmlFileResultMessage($xml, true); $result['FINAL'] = false; $result['PROGRESS'] = 100; } } else { $result['MESSAGE'] = $this->importXmlFileResultMessage($xml, false); $result['PROGRESS'] = $this->getCurrentXmlProgress(); $result['FINAL'] = false; } } else { $result['STATUS'] = self::STEP_STATUS_ERROR; $result['MESSAGE'] = $importResult['ERROR']; } unset($importResult); unset($importer); return $result; } /** * Internal updates. * @param int $parentIblock Parent iblock id. * @param int $offerIblock Offers iblock id. * @return void */ private function updateImportedIblocks(int $parentIblock, int $offerIblock): void { // link iblocks $propertyId = \CIBlockPropertyTools::createProperty( $offerIblock, \CIBlockPropertyTools::CODE_SKU_LINK, array('LINK_IBLOCK_ID' => $parentIblock) ); $res = \CCatalog::getList([], ['IBLOCK_ID' => $parentIblock], false, false, ['IBLOCK_ID']); $row = $res->Fetch(); if (empty($row)) { \CCatalog::add(array( 'IBLOCK_ID' => $parentIblock, 'PRODUCT_IBLOCK_ID' => 0, 'SKU_PROPERTY_ID' => 0 )); } $res = \CCatalog::getList([], ['IBLOCK_ID' => $offerIblock], false, false, ['IBLOCK_ID']); if ($res->fetch()) { \CCatalog::update( $offerIblock, array( 'PRODUCT_IBLOCK_ID' => $parentIblock, 'SKU_PROPERTY_ID' => $propertyId ) ); } else { \CCatalog::add(array( 'IBLOCK_ID' => $offerIblock, 'PRODUCT_IBLOCK_ID' => $parentIblock, 'SKU_PROPERTY_ID' => $propertyId )); } unset($res); // additional updates -- common foreach (array($parentIblock, $offerIblock) as $iblockId) { // uniq code $defValueCode = array ( 'UNIQUE' => 'Y', 'TRANSLITERATION' => 'Y', 'TRANS_LEN' => 100, 'TRANS_CASE' => 'L', 'TRANS_SPACE' => '_', 'TRANS_OTHER' => '_', 'TRANS_EAT' => 'Y', 'USE_GOOGLE' => 'N' ); $iblock = new \CIBlock; $iblock->update($iblockId, array( 'FIELDS' => array( 'CODE' => array ( 'IS_REQUIRED' => 'N', 'DEFAULT_VALUE' => $defValueCode ), 'SECTION_CODE' => array ( 'IS_REQUIRED' => 'N', 'DEFAULT_VALUE' => $defValueCode ) ) )); } } /** * Reindex catalog. * @param int $parentIblock Parent iblock id. * @param int $offerIblock Offers iblock id. * @return void */ private function reindexCatalog(int $parentIblock, int $offerIblock): void { $parentSectionId = $this->getParentCatalogSectionId( $parentIblock, $this->getCurrentShowcaseSectionXmlId() ); if ($parentSectionId === null) { return; } $iterator = \CIBlockElement::GetList( ['ID' => 'ASC'], [ 'IBLOCK_ID' => $parentIblock, 'SECTION_ID' => $parentSectionId, 'INCLUDE_SUBSECTIONS' => 'Y', 'CHECK_PERMISSIONS' => 'N' ], false, ['nTopCount' => 1], ['ID', 'IBLOCK_ID'] ); $firstElement = $iterator->Fetch(); unset($iterator); if (empty($firstElement)) { return; } $borderId = (int)$firstElement['ID'] - 1; $iblockId = $offerIblock; $count = \Bitrix\Iblock\ElementTable::getCount(array( '=IBLOCK_ID' => $iblockId, '=WF_PARENT_ELEMENT_ID' => null )); if ($count > 0) { $catalogReindex = new \CCatalogProductAvailable('', 0, 0); $catalogReindex->initStep($count, 0, 0); $catalogReindex->setParams(array( 'IBLOCK_ID' => $iblockId )); $catalogReindex->run(); } // update only for catalog - some magic $iblockId = $parentIblock; $count = \Bitrix\Iblock\ElementTable::getCount(array( '=IBLOCK_ID' => $iblockId, '=WF_PARENT_ELEMENT_ID' => null, '>ID' => $borderId )); if ($count > 0) { $catalogReindex = new \CCatalogProductAvailable('', 0, 0); $catalogReindex->initStep($count, 0, $borderId); $catalogReindex->setParams(array( 'IBLOCK_ID' => $iblockId )); $catalogReindex->run(); } } /** * Init steps in session. * @param array $config Step config * @return void */ private function initStepStorage(array $config = []): void { if ( !isset($_SESSION['LANDING_DEMO_STORAGE']) || !is_array($_SESSION['LANDING_DEMO_STORAGE']) ) { $showcase = $this->getCurrentShowcase(); $initData = [ 'STEP_ID' => reset($this->catalogStepList), 'XML_LIST' => $showcase['XML_LIST'], 'IBLOCK_ID' => array_fill_keys($showcase['XML_LIST'], 0), 'STEP_PARAMETERS' => [] ]; $_SESSION['LANDING_DEMO_STORAGE'] = $initData; } } /** * Gets current step from session. * @return mixed */ private function getCurrentStep() { return $_SESSION['LANDING_DEMO_STORAGE']['STEP_ID']; } /** * Set current step to session. * @param mixed $step Step. * @return void */ private function setCurrentStep($step) { $_SESSION['LANDING_DEMO_STORAGE']['STEP_ID'] = $step; } /** * Go to the next step. * @return void */ private function nextStep() { $index = array_search($this->getCurrentStep(), $this->catalogStepList); if (isset($this->catalogStepList[$index+1])) { $this->setCurrentStep($this->catalogStepList[$index+1]); } } /** * Reset step params. * @return void */ private function resetStepParameters() { $_SESSION['LANDING_DEMO_STORAGE']['STEP_PARAMETERS'] = []; } /** * Get current xml. * @return mixed */ private function getCurrentXml() { if (!isset($_SESSION['LANDING_DEMO_STORAGE']['STEP_PARAMETERS']['CURRENT_XML'])) { $_SESSION['LANDING_DEMO_STORAGE']['STEP_PARAMETERS']['CURRENT_XML'] = [ 'CODE' => reset($_SESSION['LANDING_DEMO_STORAGE']['XML_LIST']), 'PROGRESS' => 0 ]; } return $_SESSION['LANDING_DEMO_STORAGE']['STEP_PARAMETERS']['CURRENT_XML']['CODE']; } /** * Gets next xml. * @return mixed */ private function getNextXml() { $index = array_search($this->getCurrentXml(), $_SESSION['LANDING_DEMO_STORAGE']['XML_LIST']); return $_SESSION['LANDING_DEMO_STORAGE']['XML_LIST'][$index + 1] ?? null; } /** * Set current xml. * @param mixed $xmlId External code. * @return void */ private function setCurrentXml($xmlId) { $_SESSION['LANDING_DEMO_STORAGE']['STEP_PARAMETERS']['CURRENT_XML']['CODE'] = $xmlId; $_SESSION['LANDING_DEMO_STORAGE']['STEP_PARAMETERS']['CURRENT_XML']['PROGRESS'] = 0; } /* * Gets current xml in progress. * @return mixed */ private function getCurrentXmlProgress() { $_SESSION['LANDING_DEMO_STORAGE']['STEP_PARAMETERS']['CURRENT_XML']['PROGRESS'] += 5; return $_SESSION['LANDING_DEMO_STORAGE']['STEP_PARAMETERS']['CURRENT_XML']['PROGRESS']; } /** * Gets xml of iblock id from session. * @param string $xmlId External code. * @return mixed */ private function getXmlIblockId(string $xmlId) { return $_SESSION['LANDING_DEMO_STORAGE']['IBLOCK_ID'][$xmlId]; } /** * Set xml of iblock id to session. * @param string $xmlId External code. * @param int $iblockId Iblock id. * @return void */ private function setXmlIblockId(string $xmlId, int $iblockId) { $_SESSION['LANDING_DEMO_STORAGE']['IBLOCK_ID'][$xmlId] = $iblockId; } /** * Gets result message for different steps. * @param string $xmlId External code. * @param bool $complete Complete step. * @return string */ private function importXmlFileResultMessage(string $xmlId, bool $complete = true): string { if ($complete) { $result = $this->showcase['MESSAGES'][$xmlId]['IMPORT_COMPLETE'] ?? ''; } else { $result = $this->showcase['MESSAGES'][$xmlId]['IMPORT_PROGRESS'] ?? ''; } return $result; } /** * Clear session vars. * @return void. */ private function destroyStepStorage() { if (array_key_exists('LANDING_DEMO_STORAGE', $_SESSION)) { unset($_SESSION['LANDING_DEMO_STORAGE']); } } /** * Gets parent section id for iblock id, if exists. * @param int $iblockId Iblock id. * @param string|null $xmlId Parent section external code. * @return int|null */ private function getParentCatalogSectionId(int $iblockId, ?string $xmlId = null): ?int { if (empty($xmlId)) { $xmlId = $this->showcaseList[self::SHOWCASE_DEFAULT]['SECTION_XML_ID'] ?? null; } if ($xmlId === null) { return null; } $iterator = Iblock\SectionTable::getList([ 'select' => ['ID'], 'filter' => [ '=IBLOCK_ID' => $iblockId, '=XML_ID' => $xmlId, ] ]); $row = $iterator->fetch(); unset($iterator); return (!empty($row) ? (int)$row['ID'] : null); } /** * Checking first symbols # in hex color * @param string $color color in hex format. * @return string */ private function prepareColor(string $color): string { if ($color[0] !== '#') { $color = '#'.$color; } return $color; } private function initShowcase(): void { $this->initShowcaseList(); $this->initCurrentShowcase(); } private function initShowcaseList(): void { $this->showcaseList[self::SHOWCASE_CLOTHES] = [ 'CLOUD_STORAGE' => 'N', 'XML_FOLDER' => 'clothes', 'XML_LIST' => [ 'catalog', 'catalog_sku', ], 'SECTION_XML_ID' => '666', 'MESSAGES' => [ 'catalog' => [ 'IMPORT_PROGRESS' => Loc::getMessage('LANDING_CMP_LD_MESS_XML_IMPORT_CATALOG_PROGRESS'), 'IMPORT_COMPLETE' => Loc::getMessage('LANDING_CMP_LD_MESS_XML_IMPORT_CATALOG_COMPLETE'), ], 'catalog_sku' => [ 'IMPORT_PROGRESS' => Loc::getMessage('LANDING_CMP_LD_MESS_XML_IMPORT_CATALOG_OFFERS_PROGRESS'), 'IMPORT_COMPLETE' => Loc::getMessage('LANDING_CMP_LD_MESS_XML_IMPORT_CATALOG_OFFERS_COMPLETE'), ], ], ]; $this->showcaseList[self::SHOWCASE_FASHION] = [ 'CLOUD_STORAGE' => 'Y', 'XML_FOLDER' => 'fashion', 'XML_LIST' => [ 'products', 'offers', ], 'SECTION_XML_ID' => 'fashion', 'MESSAGES' => [ 'products' => [ 'IMPORT_PROGRESS' => Loc::getMessage('LANDING_CMP_LD_MESS_XML_IMPORT_CATALOG_PROGRESS'), 'IMPORT_COMPLETE' => Loc::getMessage('LANDING_CMP_LD_MESS_XML_IMPORT_CATALOG_COMPLETE'), ], 'offers' => [ 'IMPORT_PROGRESS' => Loc::getMessage('LANDING_CMP_LD_MESS_XML_IMPORT_CATALOG_OFFERS_PROGRESS'), 'IMPORT_COMPLETE' => Loc::getMessage('LANDING_CMP_LD_MESS_XML_IMPORT_CATALOG_OFFERS_COMPLETE'), ], ], ]; } private function getDefaultShowcaseId(): string { return self::SHOWCASE_CLOTHES; } private function initCurrentShowcase(): void { $showcaseId = $this->request('showcaseId'); if ($showcaseId === null) { $showcaseId = $this->getDefaultShowcaseId(); } $this->setCurrentShowcaseId($showcaseId); } private function getCurrentShowcaseId(): ?string { return $this->showcaseId; } private function setCurrentShowcaseId(string $showcaseId): void { if (isset($this->showcaseList[$showcaseId])) { $this->showcaseId = $showcaseId; $this->showcase = $this->showcaseList[$showcaseId]; } } private function getCurrentShowcase(): ?array { return $this->showcase; } private function getCurrentShowcaseSectionXmlId(): ?string { return $this->showcase['SECTION_XML_ID'] ?? null; } private function getCurrentShowcaseXmlFolder(): ?string { return $this->showcase['XML_FOLDER'] ?? null; } private function getCurrentShowcaseCloudStorage(): ?string { return $this->showcase['CLOUD_STORAGE'] ?? null; } private function getCurrentXmlFilePath(): string { $xmlPath = '/bitrix/components/bitrix/landing.demo/data/xml/' .$this->getCurrentShowcaseXmlFolder(); if ($this->getCurrentShowcaseCloudStorage() === 'Y') { $xmlPath .= '/'.($this->bitrix24Included ? 'cloud' : 'box' ); } $currentZone = Manager::getZone(); $subDirLang = in_array($currentZone, ['ru', 'kz', 'by']) ? 'ru' : 'en'; $xmlPath .= '/'.$subDirLang; $xmlPath .= '/'.$this->getCurrentXml().'.xml'; return $xmlPath; } protected static function getFilterFields(): array { $fields = [ 'INSTALLS' => [ 'id' => 'INSTALLS', 'type' => 'list', 'default' => true, 'name' => Loc::getMessage('LANDING_CMP_DEMO_FILTER_INSTALL_COUNT'), 'items' => [ '100' => '1 - 100', '500' => '100 - 500', '3000' => '500 - 3000', '3001' => Loc::getMessage('LANDING_CMP_DEMO_FILTER_MORE_3000'), // '10001' => Loc::getMessage('LANDING_CMP_DEMO_FILTER_MORE_10000'), // todo: now max count is 4800 ], ], 'DATE' => [ 'id' => 'DATE', 'type' => 'list', 'default' => true, 'name' => Loc::getMessage('LANDING_CMP_DEMO_FILTER_DATE_PUBLIC'), 'items' => [ 'today' => Loc::getMessage('LANDING_CMP_DEMO_FILTER_TODAY'), 'week' => Loc::getMessage('LANDING_CMP_DEMO_FILTER_WEEK_AGO'), '2week' => Loc::getMessage('LANDING_CMP_DEMO_FILTER_2WEEK_AGO'), 'earlier' => Loc::getMessage('LANDING_CMP_DEMO_FILTER_LONG_TIME_AGO'), ], ], ]; if (Manager::isB24()) { $fields['PAYMENT'] = [ 'id' => 'PAYMENT', 'type' => 'list', 'default' => true, 'name' => Loc::getMessage('LANDING_CMP_DEMO_FILTER_TMP_TYPE'), 'items' => [ 'free' => Loc::getMessage('LANDING_CMP_DEMO_FILTER_FREE'), 'subscribe' => Loc::getMessage('LANDING_CMP_DEMO_FILTER_PAY'), ], ]; } return $fields; } /** * Gets presets for filter. * @return array */ protected static function getFilterPresets(): array { $presets = [ 'New' => [ 'name' => Loc::getMessage('LANDING_CMP_DEMO_FILTER_PRESET_NEWS'), 'fields' => [ 'DATE' => '2week', ] ], 'Populars' => [ 'name' => Loc::getMessage('LANDING_CMP_DEMO_FILTER_PRESET_POPULAR'), 'fields' => [ 'INSTALLS' => '3000', ] ], ]; if (Manager::isB24()) { $presets['Free'] = [ 'name' => Loc::getMessage('LANDING_CMP_DEMO_FILTER_PRESET_FREE'), 'fields' => [ 'PAYMENT' => 'free', ], ]; $presets['Subscribe'] = [ 'name' => Loc::getMessage('LANDING_CMP_DEMO_FILTER_PRESET_PAY'), 'fields' => [ 'PAYMENT' => 'subscribe', ], ]; } return $presets; } /** * Convert filter to unique string, f.e. for cache unification * @return string */ protected function getFilterToString(): string { $result = ''; $filter = $this->arResult['FILTER'] ?? []; if (is_array($filter) && !empty($filter)) { $keys = array_merge(['FIND'], array_keys(self::getFilterFields())); foreach ($keys as $key) { if ($filter[$key] ?? null) { $result .= "{$key}:{$filter[$key]}_"; } } } return $result; } /** * @return array - query params for getSiteList method */ protected function getQueryFromFilter(): array { $filter = $this->arResult['FILTER'] ?? []; $query = []; if (!empty($filter) && $filter['FILTER_APPLIED']) { // search if ($filter['FIND']) { $query['q'] = $filter['FIND']; } // type if ($filter['PAYMENT'] ?? null) { if ($filter['PAYMENT'] === 'free') { $query['free'] = 'Y'; unset($query['by_subscription']); } elseif ($filter['PAYMENT'] === 'subscribe') { $query['by_subscription'] = 'Y'; unset($query['free']); } } // install count if (($filter['INSTALLS'] ?? null) && $filter['INSTALLS'] !== 'all') { if ($filter['INSTALLS'] === '100') { $query['installs_from'] = 1; $query['installs_to'] = 100; } elseif ($filter['INSTALLS'] === '500') { $query['installs_from'] = 100; $query['installs_to'] = 500; } elseif ($filter['INSTALLS'] === '3000') { $query['installs_from'] = 500; $query['installs_to'] = 3000; } elseif ($filter['INSTALLS'] === '3001') { $query['installs_from'] = 3000; } elseif ($filter['INSTALLS'] === '5000') { $query['installs_from'] = 5000; $query['installs_to'] = 10000; } elseif ($filter['INSTALLS'] === '10001') { $query['installs_from'] = 10000; } } if ($filter['DATE'] ?? null) { $now = new Date(); $toPhpFormat = Date::convertFormatToPhp('DD.MM.YYYY HH:MI:SS'); if ($filter['DATE'] === 'today') { $query['date_public_from'] = $now->add('-1D')->format($toPhpFormat); } elseif ($filter['DATE'] === 'week') { $query['date_public_from'] = $now->add('-7D')->format($toPhpFormat); } elseif ($filter['DATE'] === '2week') { $query['date_public_from'] = $now->add('-14D')->format($toPhpFormat); } elseif ($filter['DATE'] === 'earlier') { $query['date_public_to'] = $now->add('-14D')->format($toPhpFormat); } } } return $query; } }