Your IP : 3.14.248.61


Current Path : /var/www/www-root/data/www/monolith-realty.ru/bitrix/modules/landing/lib/transfer/import/
Upload File :
Current File : /var/www/www-root/data/www/monolith-realty.ru/bitrix/modules/landing/lib/transfer/import/site.php

<?php
namespace Bitrix\Landing\Transfer\Import;

use Bitrix\Landing\Hook\Page\Copyright;
use Bitrix\Landing\Hook\Page\B24button;
use Bitrix\Landing\Rights;
use \Bitrix\Landing\Site as SiteCore;
use \Bitrix\Landing\Landing as LandingCore;
use Bitrix\Landing\Site\Type;
use \Bitrix\Landing\Transfer\AppConfiguration;
use \Bitrix\Landing\Block;
use \Bitrix\Landing\File;
use \Bitrix\Landing\Hook;
use \Bitrix\Landing\Template;
use \Bitrix\Landing\TemplateRef;
use \Bitrix\Landing\Manager;
use \Bitrix\Landing\Syspage;
use \Bitrix\Landing\Internals\BlockTable;
use \Bitrix\Rest\Marketplace;
use \Bitrix\Rest\Configuration;
use \Bitrix\Main\Event;
use \Bitrix\Main\ORM\Data\AddResult;
use \Bitrix\Main\Localization\Loc;
use \Bitrix\Main\ModuleManager;

Loc::loadMessages(__FILE__);

/**
 * Import site from rest
 */
class Site
{
	/**
	 * Returns export url for the site.
	 * @param string $type Site type.
	 * @return string
	 */
	public static function getUrl(string $type): string
	{
		if (!\Bitrix\Main\Loader::includeModule('rest'))
		{
			return '';
		}
		return Marketplace\Url::getConfigurationImportManifestUrl(
			AppConfiguration::PREFIX_CODE . strtolower($type)
		);
	}

	/**
	 * Returns prepare manifest settings for export.
	 * @param Event $event Event instance.
	 * @return array|null
	 */
	public static function getInitManifest(Event $event): ?array
	{
		return [
			'NEXT' => false
		];
	}

	/**
	 * Import site data.
	 * @param array $data Site data.
	 * @param Configuration\Structure $structure Instance for getting files.
	 * @return AddResult
	 */
	protected static function importSite(array $data, Configuration\Structure $structure): AddResult
	{
		$code = isset($data['CODE']) ? $data['CODE'] : null;

		// clear old keys
		$notAllowedKeys = [
			'ID', 'DOMAIN_ID', 'DATE_CREATE', 'DATE_MODIFY',
			'CREATED_BY_ID', 'MODIFIED_BY_ID', 'CODE'
		];
		foreach ($notAllowedKeys as $key)
		{
			if (isset($data[$key]))
			{
				unset($data[$key]);
			}
		}

		// if site path are exist, create random one
		if ($code)
		{
			$check = SiteCore::getList([
				'select' => [
					'ID'
				],
				'filter' => [
					'=CODE' => $code
				]
			]);
			if ($check->fetch())
			{
				$code = null;
			}
		}
		if (!$code)
		{
			$code = strtolower(\randString(10));
		}
		$data['CODE'] = $code;
		$data['ACTIVE'] = 'Y';

		// files
		$files = [];
		foreach (Hook::HOOKS_CODES_FILES as $hookCode)
		{
			if (
				isset($data['ADDITIONAL_FIELDS'][$hookCode]) &&
				$data['ADDITIONAL_FIELDS'][$hookCode] > 0
			)
			{
				$unpackFile = $structure->getUnpackFile($data['ADDITIONAL_FIELDS'][$hookCode]);
				if ($unpackFile)
				{
					$files[] = $data['ADDITIONAL_FIELDS'][$hookCode] = AppConfiguration::saveFile(
						$unpackFile
					);
				}
				else
				{
					unset($data['ADDITIONAL_FIELDS'][$hookCode]);
				}
			}
		}

		$res = SiteCore::add($data);

		// save files to site
		if ($files && $res->isSuccess())
		{
			foreach ($files as $fileId)
			{
				File::addToSite($res->getId(), $fileId);
			}
		}

		return $res;
	}

	/**
	 * Process one export step.
	 * @param Event $event Event instance.
	 * @return array|null
	 */
	public static function nextStep(Event $event): ?array
	{
		$code = $event->getParameter('CODE');
		$content = $event->getParameter('CONTENT');
		$ratio = $event->getParameter('RATIO');
		$contextUser = $event->getParameter('CONTEXT_USER');
		$userId = $event->getParameter('USER_ID');
		$additional = $event->getParameter('ADDITIONAL_OPTION');
		$structure = new Configuration\Structure($contextUser);
		$return = [
			'RATIO' => isset($ratio[$code]) ? $ratio[$code] : [],
			'ERROR_EXCEPTION' => []
		];

		if (!isset($content['~DATA']))
		{
			return null;
		}

		if ($userId)
		{
			Rights::setContextUserId($userId);
		}

		// if all import - add page in current site
		$isPageImport = $return['RATIO']['IS_PAGE_IMPORT'] ?? false;
		// if only current step add page
		$isPageStep = false;
		// if replace landing, not import
		$isReplaceLanding = $additional && (int)($additional['replaceLid'] ?? 0) > 0;
		if (isset($ratio[$code]['SITE_ID']) && (int)$ratio[$code]['SITE_ID'] > 0)
		{
			$isPageStep = true;
		}
		elseif (
			$additional && (int)$additional['siteId'] > 0
		)
		{
			$return['RATIO']['SITE_ID'] = (int)$additional['siteId'];
			$isPageImport = $return['RATIO']['IS_PAGE_IMPORT'] ?? true;
		}

		if ($isReplaceLanding)
		{
			$return['RATIO']['REPLACE_ID'] = (int)$additional['replaceLid'];
		}

		// common ratio params
		$data = self::prepareData($content['~DATA']);
		$data = self::prepareAdditionalFields($data, $additional);
		if ($isReplaceLanding && !$isPageStep)
		{
			$return['RATIO']['ADDITIONAL_FIELDS_SITE'] = $data['ADDITIONAL_FIELDS'];
		}
		if (!isset($return['RATIO']['SPECIAL_PAGES']))
		{
			$return['RATIO']['SPECIAL_PAGES'] = [
				'LANDING_ID_INDEX' => isset($data['LANDING_ID_INDEX']) ? (int)$data['LANDING_ID_INDEX'] : 0,
				'LANDING_ID_404' => isset($data['LANDING_ID_404']) ? (int)$data['LANDING_ID_404'] : 0,
				'LANDING_ID_503' => isset($data['LANDING_ID_503']) ? (int)$data['LANDING_ID_503'] : 0
			];
		}
		$return['RATIO']['IS_PAGE_IMPORT'] = $isPageImport;
		$return['RATIO']['TYPE'] = $data['TYPE'];

		// site import
		if (!$isPageImport && !$isPageStep && !$isReplaceLanding)
		{
			Type::setScope($data['TYPE']);
			$res = self::importSite($data, $structure);
			if ($res->isSuccess())
			{
				$return['RATIO']['BLOCKS'] = [];
				$return['RATIO']['BLOCKS_PENDING'] = [];
				$return['RATIO']['LANDINGS'] = [];
				$return['RATIO']['TEMPLATES'] = [];
				$return['RATIO']['TEMPLATE_LINKING'] = [];
				$return['RATIO']['SITE_ID'] = $res->getId();
				$return['RATIO']['FOLDERS_NEW'] = $data['FOLDERS_NEW'] ?? [];
				$return['RATIO']['SYS_PAGES'] = $data['SYS_PAGES'];

				if (isset($data['TEMPLATES']) && is_array($data['TEMPLATES']))
				{
					$return['RATIO']['TEMPLATES'] = $data['TEMPLATES'];
				}
				if (isset($data['TPL_ID']) && $data['TPL_ID'])
				{
					$return['RATIO']['TEMPLATE_LINKING'][-1 * $res->getId()] = [
						'TPL_ID' => (int) $data['TPL_ID'],
						'TEMPLATE_REF' => isset($data['TEMPLATE_REF'])
										? (array) $data['TEMPLATE_REF']
										: []
					];
				}
				return $return;
			}

			$return['ERROR_EXCEPTION'] = $res->getErrorMessages();

			return $return;
		}

		// something went wrong, site was not created
		if (!isset($return['RATIO']['SITE_ID']))
		{
			$return['ERROR_EXCEPTION'][] = Loc::getMessage('LANDING_IMPORT_ERROR_SITE_ID_NOT_FOUND');
			return $return;
		}

		// skip import site step if import page in existing site
		if (!isset($data['SITE_ID']))
		{
			return $return;
		}

		// not site imports
		if (isset($return['RATIO']['REPLACE_ID']) && $return['RATIO']['REPLACE_ID'] > 0)
		{
			return Landing::replaceLanding($event);
		}

		return Landing::importLanding($event);
	}

	/**
	 * Prepare site data, set some fields to default values
	 * @param array $data
	 * @return array
	 */
	protected static function prepareData(array $data): array
	{
		if (!isset($data['TYPE']))
		{
			$data['TYPE'] = 'PAGE';
		}

		$data['LANG'] = Manager::getZone();

		return $data;
	}

	/**
	 * Prepare hooks and settings by additional fields
	 * @param array $data - base params
	 * @param array|null $additional - additional data
	 * @return array
	 */
	protected static function prepareAdditionalFields(array $data, ?array $additional): array
	{
		if ($additional)
		{
			if (isset($additional['theme']) && $additional['theme'])
			{
				$color = $additional['theme'];
				if ($color[0] !== '#')
				{
					$color = '#' . $color;
				}
				$data['ADDITIONAL_FIELDS']['THEME_COLOR'] = $color;
				unset($data['ADDITIONAL_FIELDS']['THEME_CODE']);
				$data['ADDITIONAL_FIELDS']['THEME_USE'] = 'Y';
			}

			if (isset($additional['title']) && $additional['title'])
			{
				$data['TITLE'] = $additional['title'];
			}
		}

		//default widget value
		$buttons = B24button::getButtons();
		$buttonKeys = array_keys($buttons);
		if (!empty($buttonKeys))
		{
			$data['ADDITIONAL_FIELDS']['B24BUTTON_CODE'] = $buttonKeys[0];
		}
		else
		{
			$data['ADDITIONAL_FIELDS']['B24BUTTON_CODE'] = 'N';
		}
		//default site boost
		$data['ADDITIONAL_FIELDS']['SPEED_USE_WEBPACK'] = 'Y';
		$data['ADDITIONAL_FIELDS']['SPEED_USE_LAZY'] = 'Y';
		//default powered by b24
		$data['ADDITIONAL_FIELDS']['COPYRIGHT_SHOW'] = 'Y';
		$data['ADDITIONAL_FIELDS']['COPYRIGHT_CODE'] = Copyright::getRandomPhraseId();
		//default cookie
		if (in_array(Manager::getZone(), ['es', 'de', 'fr', 'it', 'pl', 'uk']))
		{
			$data['ADDITIONAL_FIELDS']['COOKIES_USE'] = 'Y';
		}

		return $data;
	}

	/**
	 * Sets replace array to the pending blocks.
	 * @param array $pendingIds Pending block ids.
	 * @param array $replace Array for future linking.
	 * @return void
	 */
	protected static function linkingPendingBlocks(array $pendingIds, array $replace): void
	{
		$replaceEncoded = base64_encode(serialize($replace));
		$res = BlockTable::getList([
			'select' => [
				'ID'
			],
			'filter' => [
				'ID' => $pendingIds
			]
		]);
		while ($row = $res->fetch())
		{
			$blockInstance = new Block($row['ID']);
			if ($blockInstance->exist())
			{
				$blockInstance->updateNodes([
					AppConfiguration::SYSTEM_COMPONENT_REST_PENDING => [
						'REPLACE' => $replaceEncoded
					]
				]);
				$blockInstance->save();
			}
		}
	}

	/**
	 * Updates added pages on new folder ids.
	 * @param int $siteId Site id.
	 * @param array $folderMapIds References between old and new folders.
	 * @return void
	 */
	protected static function updateFolderIds(int $siteId, array $folderMapIds): void
	{
		$res = LandingCore::getList([
			'select' => [
				'ID', 'FOLDER_ID'
			],
			'filter' => [
				'SITE_ID' => $siteId,
				'FOLDER_ID' => array_keys($folderMapIds)
			]
		]);
		while ($row = $res->fetch())
		{
			if (isset($folderMapIds[$row['FOLDER_ID']]))
			{
				LandingCore::update($row['ID'], [
					'FOLDER_ID' => $folderMapIds[$row['FOLDER_ID']]
				]);
			}
		}
	}

	/**
	 * Add folders and move pages to the folders.
	 * @param int $siteId Site id.
	 * @param array $foldersNew Folders' array to add.
	 * @param array $landingMapIds Landing's map from old to new ids.
	 * @return void
	 */
	protected static function addFolders(int $siteId, array $foldersNew, array $landingMapIds): void
	{
		if (!$foldersNew)
		{
			return;
		}

		$folderMapIds = [];
		foreach ($foldersNew as $folderId => $folder)
		{
			$indexId = null;

			if (!$folder['PARENT_ID'])
			{
				unset($folder['PARENT_ID']);
			}

			if ($folder['INDEX_ID'] ?? null)
			{
				$indexId = $landingMapIds[$folder['INDEX_ID']] ?? null;
				unset($folder['INDEX_ID']);
			}

			$res = SiteCore::addFolder($siteId, $folder);
			if ($res->isSuccess())
			{
				if ($indexId)
				{
					$resLanding = LandingCore::update($indexId, [
						'FOLDER_ID' => $res->getId()
					]);
					if ($resLanding->isSuccess())
					{
						\Bitrix\Landing\Folder::update($res->getId(), [
							'INDEX_ID' => $indexId
						]);
					}
				}
				$folderMapIds[$folderId] = $res->getId();
			}
		}

		$newFolders = SiteCore::getFolders($siteId);
		foreach ($newFolders as $folder)
		{
			if ($folderMapIds[$folder['PARENT_ID']] ?? null)
			{
				\Bitrix\Landing\Folder::update($folder['ID'], [
					'PARENT_ID' => $folderMapIds[$folder['PARENT_ID']]
				]);
			}
		}

		self::updateFolderIds($siteId, $folderMapIds);
	}

	/**
	 * Final step.
	 * @param Event $event
	 * @return array
	 */
	public static function onFinish(Event $event): array
	{
		$ratio = $event->getParameter('RATIO');
		$userId = $event->getParameter('USER_ID');

		if ($userId)
		{
			Rights::setContextUserId($userId);
		}

		if (isset($ratio['LANDING']))
		{
			Rights::setGlobalOff();
			$siteType = $ratio['LANDING']['TYPE'];
			$siteId = $ratio['LANDING']['SITE_ID'] ?? null;
			$blocks = $ratio['LANDING']['BLOCKS'] ?? null;
			$landings = $ratio['LANDING']['LANDINGS'] ?? [];
			$blocksPending = $ratio['LANDING']['BLOCKS_PENDING'] ?? null;
			$foldersRef = $ratio['LANDING']['FOLDERS_REF'] ?? null;
			$templatesOld = $ratio['LANDING']['TEMPLATES'] ?? [];
			$templateLinking = $ratio['LANDING']['TEMPLATE_LINKING'] ?? [];
			$specialPages = $ratio['LANDING']['SPECIAL_PAGES'] ?? null;
			$sysPages = $ratio['LANDING']['SYS_PAGES'] ?? null;
			$foldersNew = $ratio['LANDING']['FOLDERS_NEW'] ?? [];
			$additional = $event->getParameter('ADDITIONAL_OPTION') ?? [];

			// if import just page in existing site
			$isPageImport = false;
			$isReplaceLanding = isset($additional['replaceLid']) && (int)$additional['replaceLid'] > 0;
			if (
				(isset($additional['siteId']) && (int)$additional['siteId'] > 0)
				|| $isReplaceLanding
			)
			{
				$isPageImport = true;
			}

			// index page for multipage, or just once - for sigle page import
			$mainPageId = null;
			if (!empty($landings))
			{
				if ($isPageImport)
				{
					$mainPageId = reset($landings);
				}
				elseif (
					$siteId
					&& $specialPages
					&& $specialPages['LANDING_ID_INDEX']
					&& $landings[$specialPages['LANDING_ID_INDEX']]
				)
				{
					$mainPageId = $landings[$specialPages['LANDING_ID_INDEX']];
				}
			}

			Type::setScope($siteType);
			if ($blocksPending)
			{
				self::linkingPendingBlocks($blocksPending, [
					'block' => $blocks,
					'landing' => $landings
				]);
			}
			// replace links in blocks content
			if ($blocks)
			{
				$replace = [];
				ksort($blocks);
				ksort($landings);
				$blocks = array_reverse($blocks, true);
				$landings = array_reverse($landings, true);
				foreach ($blocks as $oldId => $newId)
				{
					$replace['/#block' . $oldId . '([^\d]{1})/'] = '#block' . $newId . '$1';
				}
				foreach ($landings as $oldId => $newId)
				{
					$replace['/#landing' . $oldId . '([^\d]{1})/'] = '#landing' . $newId . '$1';
				}

				$res = BlockTable::getList([
					'select' => [
						'ID', 'CONTENT'
					],
					'filter' => [
						'ID' => array_values($blocks),
						'!ID' => $blocksPending
					]
				]);
				while ($row = $res->fetch())
				{
					$count = 0;
					$row['CONTENT'] = preg_replace(
						array_keys($replace),
						array_values($replace),
						$row['CONTENT'],
						-1,
						$count
					);
					if ($count)
					{
						BlockTable::update($row['ID'], [
							'CONTENT' => $row['CONTENT']
						]);
					}
				}
			}

			if (!$isPageImport)
			{
				// move pages to the folders if needed (backward compatibility)
				if ($foldersRef)
				{
					$res = LandingCore::getList([
						'select' => [
							'ID', 'FOLDER_ID',
						],
						'filter' => [
							'SITE_ID' => $siteId,
							'FOLDER_ID' => array_keys($foldersRef),
						],
					]);
					while ($row = $res->fetch())
					{
						LandingCore::update($row['ID'], [
							'FOLDER_ID' => $foldersRef[$row['FOLDER_ID']],
						]);
					}
				}
				// add folders and move pages (new format)
				self::addFolders($siteId, $foldersNew, $landings);
				// gets actual layouts
				$templatesNew = [];
				$templatesRefs = [];
				$res = Template::getList([
					'select' => [
						'ID', 'XML_ID',
					],
				]);
				while ($row = $res->fetch())
				{
					$templatesNew[$row['XML_ID']] = $row['ID'];
				}
				foreach ($templatesOld as $oldId => $oldXmlId)
				{
					if (is_string($oldXmlId) && isset($templatesNew[$oldXmlId]))
					{
						$templatesRefs[$oldId] = $templatesNew[$oldXmlId];
					}
				}

				// set layouts to site and landings
				foreach ($templateLinking as $entityId => $templateItem)
				{
					$tplId = $templateItem['TPL_ID'];
					$tplRefs = [];
					if (isset($templatesRefs[$tplId]))
					{
						$tplId = $templatesRefs[$tplId];
						foreach ($templateItem['TEMPLATE_REF'] as $areaId => $landingId)
						{
							if (intval($landingId) && isset($landings[$landingId]))
							{
								$tplRefs[$areaId] = $landings[$landingId];
							}
						}
						if ($entityId < 0)
						{
							SiteCore::update(-1 * $entityId, [
								'TPL_ID' => $tplId,
							]);
							TemplateRef::setForSite(-1 * $entityId, $tplRefs);
						}
						else
						{
							LandingCore::update($entityId, [
								'TPL_ID' => $tplId,
							]);
							TemplateRef::setForLanding($entityId, $tplRefs);
						}
					}
				}

				// replace special pages in site (503, 404)
				if ($specialPages && $siteId)
				{
					foreach ($specialPages as $code => $id)
					{
						$specialPages[$code] = isset($landings[$id]) ? $landings[$id] : 0;
					}
					SiteCore::update($siteId, $specialPages);
				}

				// system pages
				if (is_array($sysPages) && $siteId)
				{
					foreach ($sysPages as $sysPage)
					{
						if (isset($landings[$sysPage['LANDING_ID']]))
						{
							Syspage::set($siteId, $sysPage['TYPE'], $landings[$sysPage['LANDING_ID']]);
						}
					}
				}
			}

			//set default additional fields for page
			if ($mainPageId && !$isReplaceLanding)
			{
				self::setAdditionalPageFields($mainPageId, $additional);
			}

			Rights::setGlobalOn();

			// link for "go to site" button
			$linkAttrs = [
				'class' => 'ui-btn ui-btn-md ui-btn-success ui-btn-round',
				'data-is-site' => 'Y',
				'data-site-id' => $siteId,
				'href' => '#' . $siteId,
				'target' => '_top'
			];
			if ($mainPageId)
			{
				$linkAttrs['data-is-landing'] = 'Y';
				$linkAttrs['data-landing-id'] = $mainPageId;
			}
			$linkText = Loc::getMessage('LANDING_IMPORT_FINISH_GOTO_SITE');
			if ($siteType === 'KNOWLEDGE')
			{
				$linkAttrs['href'] = \Bitrix\Landing\Site::getPublicUrl($siteId);
			}
			elseif ($siteType === 'PAGE' && empty($additional))
			{
				$linkText = Loc::getMessage('LANDING_IMPORT_FINISH_GOTO_PAGE');
				$url = Manager::getOption('tmp_last_show_url', '');
				if ($url === '' && ModuleManager::isModuleInstalled('bitrix24'))
				{
					$linkAttrs['href'] = '/sites/';
				}
				elseif ($url !== '')
				{
					$linkAttrs['href'] = str_replace(
						[
							'#site_show#',
							'#landing_edit#',
						],
						[
							$siteId,
							$siteId,
						],
						$url
					);
				}
			}

			if ($isReplaceLanding)
			{
				$linkAttrs['data-replace-lid'] = (int)$additional['replaceLid'];
			}

			$domList = [
				[
					'TAG' => 'a',
					'DATA' => [
						'attrs' => $linkAttrs,
						'text' => $linkText,
					]
				]
			];

			if (mb_strpos($linkAttrs['href'], '#') !== 0)
			{
				$domList[] = [
					'TAG' => 'script',
					'DATA' => [
						'html' => "top.window.location.href='" . $linkAttrs['href'] . "'",
					]
				];
			}

			if (
				!empty($additional)
				&& array_key_exists('st_category', $additional)
				&& array_key_exists('st_event', $additional)
			)
			{
				$analyticData = [
					'category' => $additional['st_category'],
					'event' => $additional['st_event'],
					'status' => 'success',
				];
				if (array_key_exists('st_section', $additional))
				{
					$analyticData['c_section'] = $additional['st_section'];
				}
				if (array_key_exists('st_element', $additional))
				{
					$analyticData['c_element'] = $additional['st_element'];
				}
				if (array_key_exists('app_code', $additional))
				{
					$analyticData['params'] = [
						'appCode' => $additional['app_code'],
					];
				}

				$script = "if (typeof BX.Landing.Metrika !== 'undefined') {";
				$script  .= "const metrika = new BX.Landing.Metrika(true);";
				$script  .= "metrika.sendData(" . \CUtil::PhpToJSObject($analyticData) . ")";
				$script  .= "}";
				$domList[] = [
					'TAG' => 'script',
					'DATA' => [
						'html' => $script,
					]
				];
			}

			return [
				'CREATE_DOM_LIST' => $domList,
				'ADDITIONAL' => [
					'id' => $siteId,
					'publicUrl' => \Bitrix\Landing\Site::getPublicUrl($siteId),
					'imageUrl' => Manager::getUrlFromFile(\Bitrix\Landing\Site::getPreview($siteId)),
				]
			];
		}

		Rights::setGlobalOn();

		return [];
	}

	protected static function setAdditionalPageFields($landingId, array $additional): void
	{
		$additionalFields = [];

		// set Title and Description to mainpage
		if (!empty($additional))
		{
			if (isset($additional['title']))
			{
				$additionalFields['METAMAIN_TITLE'] = $additional['title'];
				$additionalFields['METAOG_TITLE'] = $additional['title'];

				LandingCore::update($landingId, [
					'TITLE' => $additional['title']
				]);
			}
			if (isset($additional['description']))
			{
				$additionalFields['METAMAIN_DESCRIPTION'] = $additional['description'];
				$additionalFields['METAOG_DESCRIPTION'] = $additional['description'];
			}
		}

		LandingCore::saveAdditionalFields($landingId, $additionalFields);
	}
}