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