Your IP : 3.145.79.214


Current Path : /var/www/www-root/data/www.catalog.monolith-realty.ru/bitrix/modules/landing/lib/block/
Upload File :
Current File : /var/www/www-root/data/www.catalog.monolith-realty.ru/bitrix/modules/landing/lib/block/designer.php

<?php
namespace Bitrix\Landing\Block;

use \Bitrix\Landing\Block;
use \Bitrix\Landing\Hook;
use \Bitrix\Landing\Restriction;
use \Bitrix\Main\EventManager;
use \Bitrix\Main\Localization\Loc;

Loc::loadMessages(__FILE__);

class Designer
{
	/**
	 * Current block for design.
	 * @var Block|null
	 */
	protected $block = null;

	/**
	 * Designer constructor.
	 * @param int $blockId block id.
	 */
	public function __construct(int $blockId)
	{
		$block = new Block($blockId, [], [
			'designer_mode' => true
		]);
		if ($block->exist())
		{
			$this->block = $block;
		}
	}

	/**
	 * Returns true if current designer filled up with block.
	 * @return bool
	 */
	public function isReady(): bool
	{
		return $this->block !== null;
	}

	/**
	 * Returns current block.
	 * @return Block|null
	 */
	public function getBlock(): ?Block
	{
		return $this->block;
	}

	/**
	 * Registers onLandingView callback for set design block flag.
	 * @param bool $flag Design block flag.
	 * @return void
	 */
	public static function setLandingDesignBlockMode(bool $flag): void
	{
		$eventManager = EventManager::getInstance();
		$eventManager->addEventHandler('landing', 'onLandingView',
			function(\Bitrix\Main\Event $event) use($flag)
			{
				$result = new \Bitrix\Main\Entity\EventResult;
				$options = $event->getParameter('options');
				$options['design_block'] = $flag;
				$options['design_block_allowed'] = Restriction\Manager::isAllowed('limit_crm_superblock');
				$result->modifyFields([
					'options' => $options
				]);
				return $result;
			}
		);
	}

	/**
	 * Exec block's landing and site hooks.
	 * @see \Bitrix\Landing\Landing::execHooks
	 * @return void
	 */
	public function execHooks(): void
	{
		$hooksExec = [];

		foreach (Hook::getForSite($this->block->getSiteId()) as $hook)
		{
			if ($hook->enabled())
			{
				$hooksExec[$hook->getCode()] = $hook;
			}
		}

		foreach (Hook::getForLanding($this->block->getLandingId()) as $hook)
		{
			if ($hook->enabled())
			{
				$hooksExec[$hook->getCode()] = $hook;
			}
		}

		foreach ($hooksExec as $hook)
		{
			if ($hook->enabledInEditMode())
			{
				$hook->exec();
			}
		}
	}

	/**
	 * Static getter for repository.
	 * @return array
	 */
	protected static function getRepo(): array
	{
		static $repo = [];

		if ($repo)
		{
			return $repo;
		}

		$res = DesignerRepo::getList([
			'order' => [
				'SORT' => 'asc'
			]
		]);
		while ($row = $res->fetch())
		{
			$repo[] = $row;
		}

		return $repo;
	}

	/**
	 * Adjusts styles for manifest (for specific selectors adds new features).
	 * @param string $selector Selector code.
	 * @param array $item Manifest item's style section.
	 * @return void
	 */
	private static function adjustStylesType(string $selector, array &$item): void
	{
		if ($selector === 'landing-block-node-title')
		{
			$item['type'] = (array)$item['type'];
			$item['type'][] = 'heading';
		}
	}

	/**
	 * Returns map of references between classes and type.
	 * @return array
	 */
	protected static function getTypeClassReferences(): array
	{
		$references = [];
		$selectorName = [];

		foreach (self::getRepo() as $repoItem)
		{
			if (
				!isset($repoItem['MANIFEST']) ||
				!is_array($repoItem['MANIFEST'])
			)
			{
				continue;
			}
			ksort($repoItem['MANIFEST']);
			foreach (['nodes', 'style'] as $category)
			{
				if (isset($repoItem['MANIFEST'][$category]))
				{
					foreach ($repoItem['MANIFEST'][$category] as $selector => $item)
					{
						if (!is_array($item))
						{
							continue;
						}
						$selector = trim($selector, '.');
						if (!isset($references[$selector]))
						{
							$references[$selector] = [];
						}
						if (!isset($references[$selector][$category]))
						{
							$references[$selector][$category] = [];
						}
						if (!isset($selectorName[$selector]))
						{
							$selectorName[$selector] = Loc::getMessage('LANDING_DESIGN_NODE_' . mb_strtoupper($selector));
						}
						if ($category === 'style')
						{
							self::adjustStylesType($selector, $item);
						}
						$item['name'] = $selectorName[$selector];
						$references[$selector][$category] = $item;
						if (
							isset($repoItem['MANIFEST']['assets']) &&
							is_array($repoItem['MANIFEST']['assets'])
						)
						{
							$references[$selector]['assets'] = $repoItem['MANIFEST']['assets'];
						}
					}
				}
			}
		}

		return $references;
	}

	/**
	 * Returns additional manifest nodes from content.
	 * @param string $content Block content.
	 * @return array
	 */
	public static function parseManifest(string $content): array
	{
		static $references = [];
		$manifest = [
			'nodes' => [],
			'style' => [],
		];

		if (!$references)
		{
			$references = self::getTypeClassReferences();
		}

		if (preg_match_all('/[\s"]+((' . implode('|', array_keys($references)) . ')[-\d]*)[\s"]+/is', $content, $matches))
		{
			foreach ($matches[2] as $i => $selector)
			{
				if (isset($references[$selector]))
				{
					foreach ($manifest as $code => &$items)
					{
						if (isset($references[$selector][$code]))
						{
							$items['.'.$matches[1][$i]] = $references[$selector][$code];
						}
					}
					unset($items);
					if (isset($references[$selector]['assets']))
					{
						$manifest['assets'] = $references[$selector]['assets'];
					}
				}
			}
		}

		return $manifest;
	}

	/**
	 * Returns repository's elements.
	 * @param bool $installRepo Install repo if empty result.
	 * @return array
	 */
	public static function getRepository(bool $installRepo = true): array
	{
		$repo = [];

		foreach (self::getRepo() as $row)
		{
			$repo[] = [
				'name' => $row['TITLE'] ?: Loc::getMessage('LANDING_DESIGNER_REPO_ELEM_' . mb_strtoupper($row['XML_ID'])),
				'code' => $row['XML_ID'],
				'html' => $row['HTML'],
				'manifest' => $row['MANIFEST']
			];
		}

		if (!$repo && $installRepo)
		{
			DesignerRepo::installRepo();
			return self::getRepository(false);
		}

		return $repo;
	}

	/**
	 * Registers new repo element.
	 * @param array $fields Data array ([XML_ID, ?TITLE, HTML, MANIFEST]).
	 * @return void
	 */
	public static function registerRepoElement(array $fields): void
	{
		if (isset($fields['XML_ID']) && is_string($fields['XML_ID']))
		{
			$res = DesignerRepo::getList([
				'select' => [
					'ID'
				],
				'filter' => [
					'=XML_ID' => $fields['XML_ID']
				]
			]);
			if ($row = $res->fetch())
			{
				DesignerRepo::update($row['ID'], $fields);
			}
			else
			{
				DesignerRepo::add($fields)->isSuccess();
			}
		}
	}

	/**
	 * Removes repo element by code.
	 * @param string $code External code.
	 * @return void
	 */
	public static function unregisterRepoElement(string $code): void
	{
		$res = DesignerRepo::getList([
			'select' => [
				'ID'
			],
			'filter' => [
				'=XML_ID' => $code
			]
		]);
		if ($row = $res->fetch())
		{
			DesignerRepo::delete($row['ID']);
		}
	}
}