• Модуль: main
  • Путь к файлу: ~/bitrix/modules/main/lib/orm/query/chain.php
  • Класс: BitrixMainORMQueryChain
  • Вызов: Chain::getChainByDefinition
static function getChainByDefinition(Entity $init_entity, $definition)
{
	if (!is_string($definition))
	{
		throw new MainArgumentException('String expected, but `'.gettype($definition).'` is given.');
	}

	$chain = new Chain;
	$chain->addElement(new ChainElement($init_entity));

	$def_elements = explode('.', $definition);
	$def_elements_size = count($def_elements);

	$prev_entity  = $init_entity;

	$i = 0;

	foreach ($def_elements as &$def_element)
	{
		$is_last_elem  = (++$i == $def_elements_size);

		$not_found = false;

		// all elements should be a Reference field or Entity
		// normal (scalar) field can only be the last element

		if ($prev_entity->hasField($def_element))
		{
			// field has been found at current entity
			$field = $prev_entity->getField($def_element);

			if ($field instanceof Reference)
			{
				$prev_entity = $field->getRefEntity();
			}
			elseif ($field instanceof ExpressionField)
			{
				// expr can be in the middle too
			}
			elseif ($field instanceof OneToMany)
			{
				$prev_entity = $field->getRefEntity();
			}
			elseif ($field instanceof ManyToMany)
			{
				$prev_entity = $field->getRefEntity();
			}
			elseif (!$is_last_elem)
			{
				throw new SystemException(sprintf(
					'Normal fields can be only the last in chain, `%s` %s is not the last.',
					$field->getName(), get_class($field)
				));
			}

			if ($is_last_elem && $field instanceof ExpressionField)
			{
				// we should have own copy of build_from_chains to set join aliases there
				$field = clone $field;
			}

			$chain->addElement(new ChainElement($field));
		}
		elseif (Entity::isExists($def_element)
			&& Entity::getInstance($def_element)->getReferencesCountTo($prev_entity->getName()) == 1
		)
		{
			// def_element is another entity with only 1 reference to current entity
			// need to identify Reference field
			$ref_entity = Entity::getInstance($def_element);
			$field = end($ref_entity->getReferencesTo($prev_entity->getName()));

			$prev_entity = $ref_entity;

			$chain->addElement(new ChainElement(
				array($ref_entity, $field)
			));
		}
		elseif ( ($pos_wh = strpos($def_element, ':')) > 0 )
		{
			$ref_entity_name = substr($def_element, 0, $pos_wh);

			if (strpos($ref_entity_name, '\') === false)
			{
				// if reference has no namespace, then it'is in the namespace of previous entity
				$ref_entity_name = $prev_entity->getNamespace().$ref_entity_name;
			}

			if (
				Entity::isExists($ref_entity_name)
				&& Entity::getInstance($ref_entity_name)->hasField($ref_field_name = substr($def_element, $pos_wh + 1))
				&& Entity::getInstance($ref_entity_name)->getField($ref_field_name) instanceof Reference
			)
			{
				/** @var Reference $reference */
				$reference = Entity::getInstance($ref_entity_name)->getField($ref_field_name);

				if (
					$reference->getRefEntity()->getFullName() == $prev_entity->getFullName() ||
					is_subclass_of(
						$prev_entity->getDataClass(),
						$reference->getRefEntity()->getDataClass()
					)
				)
				{
					// chain element is another entity with >1 references to current entity
					// def like NewsArticle:AUTHOR, NewsArticle:LAST_COMMENTER
					// NewsArticle - entity, AUTHOR and LAST_COMMENTER - Reference fields
					$chain->addElement(new ChainElement(array(
						Entity::getInstance($ref_entity_name),
						Entity::getInstance($ref_entity_name)->getField($ref_field_name)
					)));

					$prev_entity = Entity::getInstance($ref_entity_name);
				}
				else
				{
					$not_found = true;
				}
			}
			else
			{
				$not_found = true;
			}

		}
		elseif ($def_element == '*' && $is_last_elem)
		{
			continue;
		}
		else
		{
			// unknown chain
			$not_found = true;
		}

		if ($not_found)
		{
			throw new SystemException(sprintf(
				'Unknown field definition `%s` (%s) for %s Entity.',
				$def_element, $definition, $prev_entity->getFullName()
			), 100);
		}
	}

	return $chain;
}