- Модуль: main
- Путь к файлу: ~/bitrix/modules/main/lib/orm/query/query.php
- Класс: Bitrix\Main\ORM\Query\Query
- Вызов: Query::setFilterHandlerChains
public function setFilterHandlerChains(Filter $where, $section = 'filter')
{
foreach ($where->getConditions() as $condition)
{
if ($condition instanceof Filter)
{
// subfilter
$this->setFilterHandlerChains($condition, $section);
}
else
{
$definition = $condition->getDefinition();
// check for runtime fields
if ($definition instanceof Field)
{
// register runtime field
$this->registerRuntimeField($definition);
// rewrite definition in filter - replace field with its name
$definition = $definition->getName();
$condition->setDefinition($definition);
}
// check if it's a regular condition, not kind of boolean/exists expression
if ($definition !== null)
{
// regular condition
$chain = $this->getRegisteredChain($definition);
if (!$chain)
{
// try to find it in filter chains if it is 2nd call of method (when dividing filter for where/having)
// and chain is still not registered in global (e.g. when forcesDataDoublingOff)
$chain = $this->filter_chains[$definition] ?? Chain::getChainByDefinition($this->entity, $definition);
}
// dirty hack for UF multiple fields: replace text UF_SMTH by UF_SMTH_SINGLE
$dstField = $chain->getLastElement()->getValue();
$dstEntity = $dstField->getEntity();
if ($dstField instanceof ExpressionField && count($dstField->getBuildFromChains()) == 1)
{
// hold entity, but get real closing field
$dstBuildFromChains = $dstField->getBuildFromChains();
/** @var Chain $firstChain */
$firstChain = $dstBuildFromChains[0];
$dstField = $firstChain->getLastElement()->getValue();
}
// check for base linking
if (($dstField instanceof TextField || $dstField instanceof ArrayField)
&& $dstEntity->hasField($dstField->getName().'_SINGLE'))
{
$utmLinkField = $dstEntity->getField($dstField->getName().'_SINGLE');
if ($utmLinkField instanceof ExpressionField)
{
$buildFromChains = $utmLinkField->getBuildFromChains();
// check for back-reference
if (count($buildFromChains) == 1 && $buildFromChains[0]->hasBackReference())
{
$endField = $buildFromChains[0]->getLastElement()->getValue();
// and final check for entity name
if(strpos($endField->getEntity()->getName(), 'Utm'))
{
$expressionChain = clone $chain;
$expressionChain->removeLastElement();
$expressionChain->addElement(new ChainElement(clone $utmLinkField));
$expressionChain->forceDataDoublingOff();
$chain = $expressionChain;
// rewrite filter definition
$definition .= '_SINGLE';
$condition->setDefinition($definition);
}
}
}
}
// continue
$registerChain = true;
// if data doubling disabled and it is back-reference - do not register, it will be overwritten
if ($chain->forcesDataDoublingOff() || ($this->data_doubling_off && $chain->hasBackReference()))
{
$registerChain = false;
}
if ($registerChain)
{
$this->registerChain($section, $chain, $definition);
// fill hidden select
if ($chain->getLastElement()->getValue() instanceof ExpressionField)
{
$this->collectExprChains($chain);
}
}
else
{
// hide from global registry to avoid "join table"
// but we still need it in filter chains
$this->filter_chains[$chain->getAlias()] = $chain;
$this->filter_chains[$definition] = $chain;
// and we will need primary chain in filter later when overwriting data-doubling
$this->getRegisteredChain($this->entity->getPrimary(), true);
}
}
// when compare with column, put it in the chains too
foreach ($condition->getAtomicValues() as $value)
{
if ($value instanceof ColumnExpression)
{
$valueDefinition = $value->getDefinition();
$chain = $this->filter_chains[$valueDefinition] ?? Chain::getChainByDefinition($this->entity, $valueDefinition);
$this->registerChain($section, $chain, $valueDefinition);
}
// set connection to correct escaping in expressions
if ($value instanceof Main\DB\SqlExpression)
{
$value->setConnection($this->entity->getConnection());
}
}
}
}
}