- Модуль: main
- Путь к файлу: ~/bitrix/modules/main/lib/orm/query/query.php
- Класс: Bitrix\Main\ORM\Query\Query
- Вызов: Query::prepareJoinFilterReference
protected function prepareJoinFilterReference(Filter $reference, $alias_this, $alias_ref, $baseDefinition, $refDefinition, $isBackReference, $firstCall = true)
{
// do not make an impact on original reference object
if ($firstCall)
{
$reference = clone $reference;
}
foreach ($reference->getConditions() as $condition)
{
if ($condition instanceof Filter)
{
// subfilter, recursive call
$this->prepareJoinFilterReference(
$condition,
$alias_this,
$alias_ref,
$baseDefinition,
$refDefinition,
$isBackReference,
false
);
}
else
{
// regular condition
$field = $condition->getDefinition();
if (strpos($field, 'this.') === 0)
{
// parse the chain
$definition = str_replace('this.', '', $field);
$absDefinition = $baseDefinition <> ''? $baseDefinition.'.'.$definition : $definition;
$chain = $this->getRegisteredChain($absDefinition, true);
if (!$isBackReference)
{
// make sure these fields will be joined before the main join
$this->buildJoinMap(array($chain));
}
else
{
$chain->getLastElement()->setParameter('talias', $alias_this);
}
// recursively collect all "build_from" fields
if ($chain->getLastElement()->getValue() instanceof ExpressionField)
{
$this->collectExprChains($chain);
$buildFrom = $chain->getLastElement()->getValue()->getBuildFromChains();
foreach ($buildFrom as $bf)
{
// set base chain
$baseChain = clone $chain;
// remove the last one - expression itself
$baseChain->removeLastElement();
// remove parent entity for this child
$bf->removeFirstElement();
// set new parents
$bf->prepend($baseChain);
}
$this->buildJoinMap($buildFrom);
}
$condition->setColumn($absDefinition);
}
elseif (strpos($field, 'ref.') === 0)
{
$definition = str_replace('ref.', '', $field);
if (strpos($definition, '.') !== false)
{
throw new Main\ArgumentException(sprintf(
'Reference chain `%s` is not allowed here. First-level definitions only.', $field
));
}
$absDefinition = $refDefinition <> ''? $refDefinition.'.'.$definition : $definition;
$chain = $this->getRegisteredChain($absDefinition, true);
if ($isBackReference)
{
// make sure these fields will be joined before the main join
$this->buildJoinMap(array($chain));
}
else
{
$chain->getLastElement()->setParameter('talias', $alias_ref);
}
// recursively collect all "build_from" fields
if ($chain->getLastElement()->getValue() instanceof ExpressionField)
{
$this->collectExprChains($chain);
$this->buildJoinMap($chain->getLastElement()->getValue()->getBuildFromChains());
}
$condition->setColumn($absDefinition);
}
else
{
throw new Main\SystemException(sprintf('Unknown reference key `%s`, it should start with "this." or "ref."', $field));
}
// value
$v = $condition->getValue();
if ($v instanceof Main\DB\SqlExpression)
{
// set entity connection
$v->setConnection($this->entity->getConnection());
}
elseif ($v instanceof ColumnExpression)
{
if (strpos($v->getDefinition(), 'this.') === 0)
{
$definition = str_replace('this.', '', $v->getDefinition());
$absDefinition = $baseDefinition <> ''? $baseDefinition.'.'.$definition : $definition;
$chain = $this->getRegisteredChain($absDefinition, true);
if (!$isBackReference)
{
// make sure these fields will be joined before the main join
$this->buildJoinMap(array($chain));
}
else
{
$chain->getLastElement()->setParameter('talias', $alias_this);
}
// recursively collect all "build_from" fields
if ($chain->getLastElement()->getValue() instanceof ExpressionField)
{
$this->collectExprChains($chain);
$buildFrom = $chain->getLastElement()->getValue()->getBuildFromChains();
foreach ($buildFrom as $bf)
{
// set base chain
$baseChain = clone $chain;
// remove the last one - expression itself
$baseChain->removeLastElement();
// remove parent entity for this child
$bf->removeFirstElement();
// set new parents
$bf->prepend($baseChain);
}
$this->buildJoinMap($buildFrom);
}
$v->setDefinition($absDefinition);
}
elseif (strpos($v->getDefinition(), 'ref.') === 0)
{
$definition = str_replace('ref.', '', $v->getDefinition());
if (strpos($definition, '.') !== false)
{
throw new Main\ArgumentException(sprintf(
'Reference chain `%s` is not allowed here. First-level definitions only.', $v->getDefinition()
));
}
$absDefinition = $refDefinition <> ''? $refDefinition.'.'.$definition : $definition;
$chain = $this->getRegisteredChain($absDefinition, true);
if ($isBackReference)
{
// make sure these fields will be joined before the main join
$this->buildJoinMap(array($chain));
}
else
{
$chain->getLastElement()->setParameter('talias', $alias_ref);
}
$this->buildJoinMap(array($chain));
// recursively collect all "build_from" fields
if ($chain->getLastElement()->getValue() instanceof ExpressionField)
{
// here could be one more check "First-level definitions only" for buildFrom elements
$buildFromChains = $this->collectExprChains($chain);
// set same talias to buildFrom elements
foreach ($buildFromChains as $buildFromChain)
{
if (!$isBackReference && $buildFromChain->getSize() > $chain->getSize())
{
throw new Main\ArgumentException(sprintf(
'Reference chain `%s` is not allowed here. First-level definitions only.',
$buildFromChain->getDefinition()
));
}
if ($buildFromChain->getSize() === $chain->getSize())
{
// same entity, same table
$buildFromChain->getLastElement()->setParameter('talias', $alias_ref);
}
}
$this->buildJoinMap($buildFromChains);
}
$v->setDefinition($absDefinition);
}
}
}
}
return $reference;
}