- Модуль: main
- Путь к файлу: ~/bitrix/modules/main/lib/orm/query/query.php
- Класс: Bitrix\Main\ORM\Query\Query
- Вызов: Query::addToSelectChain
protected function addToSelectChain($definition, $alias = null)
{
if ($definition instanceof ExpressionField)
{
if (empty($alias))
{
$alias = $definition->getName();
}
$this->registerRuntimeField($alias, $definition);
$chain = $this->getRegisteredChain($alias);
// add
$this->registerChain('select', $chain);
// recursively collect all "build_from" fields
if ($chain->getLastElement()->getValue() instanceof ExpressionField)
{
$this->collectExprChains($chain, array('hidden', 'select_expr'));
}
}
elseif (is_array($definition))
{
// it is runtime field
// now they are @deprecated in here
throw new Main\ArgumentException(
'Expression as an array in `select` section is no more supported due to security reason.'
.' Please use `runtime` parameter, or Query->registerRuntimeField method, or pass ExpressionField object instead of array.'
);
}
else
{
// localize definition (get last field segment e.g. NAME from REF1.REF2.NAME)
$localDefinitionPos = strrpos($definition, '.');
if ($localDefinitionPos !== false)
{
$localDefinition = substr($definition, $localDefinitionPos + 1);
$localEntityDef = substr($definition, 0, $localDefinitionPos);
$localChain = Chain::getChainByDefinition($this->entity, $localEntityDef.'.*');
$lastElemValue = $localChain->getLastElement()->getValue();
if ($lastElemValue instanceof Reference)
{
$localEntity = $lastElemValue->getRefEntity();
}
elseif (is_array($lastElemValue))
{
list($localEntity, ) = $lastElemValue;
}
else
{
$localEntity = $lastElemValue;
}
}
else
{
$localDefinition = $definition;
$localEntityDef = "";
$dataClass = $this->entity->getDataClass();
$localEntity = $dataClass::getEntity();
}
// if there is a shell pattern in final segment, run recursively
if ((strlen($localDefinition) > 1 && strpos($localDefinition, '*') !== false)
|| strpos($localDefinition, '?') !== false
)
{
// get fields by pattern
foreach ($localEntity->getFields() as $field)
{
if (
($field instanceof ScalarField || $field instanceof ExpressionField)
&& fnmatch($localDefinition, $field->getName())
)
{
// skip private fields
if ($field instanceof ScalarField && $field->isPrivate())
{
continue;
}
// skip uf utm single
if (
substr($field->getName(), 0, 3) == 'UF_' && substr($field->getName(), -7) == '_SINGLE'
&& $localEntity->hasField(substr($field->getName(), 0, -7))
)
{
continue;
}
// build alias
$customAlias = null;
if ($alias !== null)
{
// put alias as a prefix
$customAlias = $alias.$field->getName();
}
// build definition
$fieldDefinition = $field->getName();
if (!empty($localEntityDef))
{
$fieldDefinition = $localEntityDef.'.'.$fieldDefinition;
}
$this->addToSelectChain($fieldDefinition, $customAlias);
}
}
return $this;
}
// there is normal scalar field, or Reference, or Entity (all fields of)
$chain = $this->getRegisteredChain($definition, true);
if ($alias !== null)
{
// custom alias
$chain = clone $chain;
$chain->setCustomAlias($alias);
}
$last_elem = $chain->getLastElement();
// fill if element is not scalar
/** @var null|Entity $expand_entity */
$expand_entity = null;
if ($last_elem->getValue() instanceof Reference)
{
$expand_entity = $last_elem->getValue()->getRefEntity();
}
elseif (is_array($last_elem->getValue()))
{
list($expand_entity, ) = $last_elem->getValue();
}
elseif ($last_elem->getValue() instanceof Entity)
{
$expand_entity = $last_elem->getValue();
}
elseif ($last_elem->getValue() instanceof OneToMany)
{
$expand_entity = $last_elem->getValue()->getRefEntity();
}
elseif ($last_elem->getValue() instanceof ManyToMany)
{
$expand_entity = $last_elem->getValue()->getRefEntity();
}
if (!$expand_entity && $alias !== null)
{
// we have a single field, let's check its custom alias
if (
$this->entity->hasField($alias)
&& (
// if it's not the same field
$this->entity->getFullName() !== $last_elem->getValue()->getEntity()->getFullName()
||
$last_elem->getValue()->getName() !== $alias
)
)
{
// deny aliases eq. existing fields
throw new Main\ArgumentException(sprintf(
'Alias "%s" matches already existing field "%s" of initial entity "%s". '.
'Please choose another name for alias.',
$alias, $alias, $this->entity->getFullName()
));
}
}
if ($expand_entity)
{
// add all fields of entity
foreach ($expand_entity->getFields() as $exp_field)
{
// except for references and expressions
if ($exp_field instanceof ScalarField)
{
// skip private fields
if ($exp_field->isPrivate())
{
continue;
}
$exp_chain = clone $chain;
$exp_chain->addElement(new ChainElement(
$exp_field
));
// custom alias
if ($alias !== null)
{
$fieldAlias = $alias . $exp_field->getName();
// deny aliases eq. existing fields
if ($this->entity->hasField($fieldAlias))
{
throw new Main\ArgumentException(sprintf(
'Alias "%s" + field "%s" match already existing field "%s" of initial entity "%s". '.
'Please choose another name for alias.',
$alias, $exp_field->getName(), $fieldAlias, $this->entity->getFullName()
));
}
$exp_chain->setCustomAlias($fieldAlias);
}
// add
$this->registerChain('select', $exp_chain);
}
}
}
else
{
// scalar field that defined in entity
$this->registerChain('select', $chain);
// it would be nice here to register field as a runtime when it has custom alias
// it will make possible to use aliased fields as a native init entity fields
// e.g. in expressions or in data_doubling=off filter
// collect buildFrom fields (recursively)
if ($chain->getLastElement()->getValue() instanceof ExpressionField)
{
$this->collectExprChains($chain, array('hidden', 'select_expr'));
}
}
}
return $this;
}