• Модуль: iblock
  • Путь к файлу: ~/bitrix/modules/iblock/lib/Controller/DefaultElement.php
  • Класс: BitrixIblockControllerDefaultElement
  • Вызов: DefaultElement::checkFields
static function checkFields($fields, Entity $entity)
{
	$propertyEntityAllowedList = static::getPropertyEntityAllowedList();
	$elementEntityAllowedList = static::getElementEntityAllowedList();
	$allowedList = array_merge($elementEntityAllowedList, static::getAllowedList());

	// replace REF.* for allowed fields REF.ALLOWED1, REF.ALLOWED2, etc.
	$chainReplacement = [];

	// analyze
	foreach ($fields as $definition)
	{
		// check allowed list
		if (in_array($definition, $allowedList, true))
		{
			continue;
		}

		// smart check for relations and property fields
		$chain = Chain::getChainByDefinition($entity, $definition);
		$currentDefinition = '';

		$elements = $chain->getAllElements();
		$lastElement = $chain->getLastElement();

		foreach ($elements as $element)
		{
			$isLastElement = ($element === $lastElement);

			// skip init entity
			if ($element->getValue() instanceof ElementEntity && !$isLastElement)
			{
				continue;
			}

			// append definition
			$currentDefinition = Chain::appendDefinition($currentDefinition, $element->getDefinitionFragment());

			// handle wildcard
			if ($currentDefinition === '*' && $isLastElement)
			{
				$chainReplacement[$definition] = [];

				foreach ($elementEntityAllowedList as $allowedFieldName)
				{
					if ($entity->hasField($allowedFieldName))
					{
						$chainReplacement[$definition][] = $allowedFieldName;
					}
				}

				continue;
			}

			// check access
			if (!($element->getValue() instanceof Field))
			{
				throw new ArgumentException(
					sprintf('Restricted field `%s`', $currentDefinition)
				);
			}

			$currentField = $element->getValue();
			$currentEntity = $currentField->getEntity();

			// case 1. iblock
			if ($currentEntity instanceof ElementEntity)
			{
				// case 1.1. iblock scalar
				if (in_array($currentField->getName(), $elementEntityAllowedList, true))
				{
					continue;
				}

				// case 1.2. iblock property
				if (!empty(class_uses($currentField)[PropertyRelation::class]))
				{
					if ($isLastElement)
					{
						// replace * with allowed fields
						$propEntity = $currentField->getRefEntity();
						$chainReplacement[$definition] = [];

						foreach ($propertyEntityAllowedList as $allowedFieldName)
						{
							if ($propEntity->hasField($allowedFieldName))
							{
								$chainReplacement[$definition][] = Chain::appendDefinition($currentDefinition, $allowedFieldName);
							}
						}
					}

					continue;
				}
			}

			// case 2. property entity
			if ($currentEntity instanceof ValueStorageEntity)
			{
				// case 2.1. property scalar
				if (in_array($currentField->getName(), $propertyEntityAllowedList, true))
				{
					continue;
				}

				// case 2.1. ref to another iblock
				if ($currentField instanceof Reference)
				{
					$refEntity = $currentField->getRefEntity();

					// check if remote iblock is readable
					if ($refEntity instanceof ElementEntity && $refEntity->getIblock()->fillRestOn())
					{
						if ($isLastElement)
						{
							// replace * with allowed fields
							$chainReplacement[$definition] = [];

							foreach ($elementEntityAllowedList as $allowedFieldName)
							{
								if ($refEntity->hasField($allowedFieldName))
								{
									$chainReplacement[$definition][] = Chain::appendDefinition($currentDefinition, $allowedFieldName);
								}
							}
						}

						continue;
					}
				}
			}

			// restricted by default
			throw new ArgumentException(
				sprintf('Restricted field `%s`', $currentDefinition)
			);
		}
	}

	// time to replace *
	foreach ($chainReplacement as $definition => $replacement)
	{
		// unset original
		$key = array_search($definition, $fields);
		unset($fields[$key]);

		// add replacement
		$fields = array_merge($fields, $replacement);
	}

	return $fields;
}