• Модуль: main
  • Путь к файлу: ~/bitrix/modules/main/lib/orm/query/query.php
  • Класс: Bitrix\Main\ORM\Query\Query
  • Вызов: Query::setFilterChains
public function setFilterChains(&$filter, $section = 'filter')
{
	foreach ($filter as $filter_def => &$filter_match)
	{
		if ($filter_def === 'LOGIC')
		{
			continue;
		}

		if (!is_numeric($filter_def))
		{
			$sqlWhere = new \CSQLWhere();
			$csw_result = $sqlWhere->makeOperation($filter_def);
			list($definition, ) = array_values($csw_result);

			// do not register it in global chain registry - get it in a smuggled way
			// - we will do the registration later after UF rewriting and data doubling checking
			$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
							unset($filter[$filter_def]);
							$filter[$filter_def.'_SINGLE'] = $filter_match;
							$definition .= '_SINGLE';
						}
					}
				}
			}

			// 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);
			}
		}
		elseif (is_array($filter_match))
		{
			$this->setFilterChains($filter_match, $section);
		}
	}
}