- Модуль: 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;
}