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