• Модуль: main
  • Путь к файлу: ~/bitrix/modules/main/classes/general/entity_query_chain.php
  • Класс: CEntityQueryChain
  • Вызов: CEntityQueryChain::getChainByDefinition
static function getChainByDefinition(CBaseEntity $init_entity, $definition)
{
	$chain = new CEntityQueryChain;
	$chain->addElement(new CEntityQueryChainElement($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_first_elem = ($i == 0);
		$is_last_elem  = (++$i == $def_elements_size);

		// 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 CReferenceEntityField)
			{
				$prev_entity = $field->getRefEntity();
			}
			elseif ($field instanceof CExpressionEntityField)
			{
				// expr can be in the middle too
			}
			elseif (!$is_last_elem)
			{
				throw new Exception(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 CExpressionEntityField)
			{
				// we should have own copy of build_from_chains to set join aliases there
				$field = clone $field;
			}

			$chain->addElement(new CEntityQueryChainElement($field));
		}
		elseif ($prev_entity->hasUField($def_element))
		{
			// extend chain with utm/uts entity
			$ufield = $prev_entity->getUField($def_element);

			$u_entity = null;

			if ($ufield->isMultiple())
			{
				// add utm entity  user.utm:source_object (1:N)
				$utm_entity = CBaseEntity::getInstance('Utm'.$prev_entity->getName());
				$u_entity = $utm_entity;

				$chain->addElement(new CEntityQueryChainElement(
					array($utm_entity, $utm_entity->getField('SOURCE_OBJECT')),
					array('ufield' => $ufield)
				));

				if ($ufield->getTypeId() == 'iblock_section'
					&& substr($ufield->getName(), -3) == '_BY'
					&& $prev_entity->hasUField(substr($ufield->getName(), 0, -3))
				)
				{
					// connect next entity
					$utm_fname = $ufield->getName();
					$prev_entity = CBaseEntity::getInstance('IblockSection');
				}
				else
				{
					$utm_fname = $ufield->getValueFieldName();
				}

				$chain->addElement(new CEntityQueryChainElement(
					$utm_entity->getField($utm_fname),
					array('ufield' => $ufield)
				));
			}
			else
			{
				// uts table - single value
				// add uts entity user.uts (1:1)
				$uts_entity = CBaseEntity::getInstance('Uts'.$prev_entity->getName());
				$u_entity = $uts_entity;

				$chain->addElement(new CEntityQueryChainElement(
					$prev_entity->getField('UTS_OBJECT')
				));

				// add `value` field
				$chain->addElement(new CEntityQueryChainElement(
					$uts_entity->getField($def_element)
				));
			}
		}
		elseif (CBaseEntity::isExists($def_element)
			&& CBaseEntity::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 = CBaseEntity::getInstance($def_element);
			$field = end($ref_entity->getReferencesTo($prev_entity->getName()));

			$prev_entity = $ref_entity;

			$chain->addElement(new CEntityQueryChainElement(
				array($ref_entity, $field)
			));
		}
		elseif ( ($pos_wh = strpos($def_element, ':')) > 0
				&& CBaseEntity::isExists(($ref_entity_name = substr($def_element, 0, $pos_wh)))
				&& CBaseEntity::getInstance($ref_entity_name)->hasField($ref_field_name = substr($def_element, $pos_wh+1))
				&& CBaseEntity::getInstance($ref_entity_name)->getField($ref_field_name)->getRefEntity()->getName() == $prev_entity->getName()
		)
		{
			// 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 CEntityQueryChainElement(array(
				CBaseEntity::getInstance($ref_entity_name),
				CBaseEntity::getInstance($ref_entity_name)->getField($ref_field_name)
			)));

			$prev_entity = CBaseEntity::getInstance($ref_entity_name);
		}
		elseif ($def_element == '*' && $is_last_elem)
		{
			continue;
		}
		else
		{
			// unknown chain
			throw new Exception(sprintf(
				'Unknown field definition `%s` (%s) for %s Entity.',
				$def_element, $definition, $prev_entity->getName()
			), 100);
		}
	}

	return $chain;
}