- Модуль: main
- Путь к файлу: ~/bitrix/modules/main/lib/orm/query/query.php
- Класс: Bitrix\Main\ORM\Query\Query
- Вызов: Query::getFilterCswFields
protected function getFilterCswFields(&$filter)
{
$fields = array();
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, $operation) = array_values($csw_result);
$chain = $this->filter_chains[$definition];
$last = $chain->getLastElement();
// need to create an alternative of CSQLWhere in D7.Entity
$field_type = $last->getValue()->getDataType();
$callback = null;
// rewrite type & value for CSQLWhere
if (in_array($operation, array('SE', 'SN'), true)
&& in_array($filter_match, array(null, true, false), true)
)
{
$field_type = 'callback';
if ($filter_match === null)
{
$callback = array($this, 'nullEqualityCallback');
}
else
{
// just boolean expression, without operator
// e.g. WHERE EXISTS(...)
$callback = array($this, 'booleanStrongEqualityCallback');
}
}
elseif ($field_type == 'integer')
{
$field_type = 'int';
}
elseif ($field_type == 'boolean')
{
$field_type = 'string';
/** @var BooleanField $field */
$field = $last->getValue();
$values = $field->getValues();
if (is_numeric($values[0]) && is_numeric($values[1]))
{
$field_type = 'int';
}
if (is_scalar($filter_match))
{
$filter_match = $field->normalizeValue($filter_match);
}
}
elseif ($field_type == 'float')
{
$field_type = 'double';
}
elseif ($field_type == 'enum' || $field_type == 'text')
{
$field_type = 'string';
}
$sqlDefinition = $chain->getSqlDefinition();
// data-doubling-off mode
/** @see disableDataDoubling */
if ($chain->forcesDataDoublingOff() || ($this->data_doubling_off && $chain->hasBackReference()))
{
$primaryName = $this->entity->getPrimary();
$uniquePostfix = '_TMP'.rand();
// build subquery
$subQuery = new Query($this->entity);
$subQuery->addSelect($primaryName);
$subQuery->addFilter($filter_def, $filter_match);
$subQuery->setTableAliasPostfix(strtolower($uniquePostfix));
$subQuerySql = $subQuery->getQuery();
// proxying subquery as value to callback
$filter_match = $subQuerySql;
$callback = array($this, 'dataDoublingCallback');
$field_type = 'callback';
// change sql definition
$idChain = $this->getRegisteredChain($primaryName);
$sqlDefinition = $idChain->getSqlDefinition();
}
// set entity connection to the sql expressions
if ($filter_match instanceof Main\DB\SqlExpression)
{
$filter_match->setConnection($this->entity->getConnection());
}
//$is_having = $last->getValue() instanceof ExpressionField && $last->getValue()->isAggregated();
// if back-reference found (Entity:REF)
// if NO_DOUBLING mode enabled, then change getSQLDefinition to subquery exists(...)
// and those chains should not be in joins if it is possible
/*if (!$this->data_doubling && $chain->hasBackReference())
{
$field_type = 'callback';
$init_query = $this;
$callback = function ($field, $operation, $value) use ($init_query, $chain)
{
$init_entity = $init_query->getEntity();
$init_table_alias = CBaseEntity::camel2snake($init_entity->getName()).$init_query->getTableAliasPostfix();
$filter = array();
// add primary linking with main query
foreach ($init_entity->getPrimaryArray() as $primary)
{
$filter['='.$primary] = new CSQLWhereExpression('?#', $init_table_alias.'.'.$primary);
}
// add value filter
$filter[CSQLWhere::getOperationByCode($operation).$chain->getDefinition()] = $value;
// build subquery
$query_class = __CLASS__;
$sub_query = new $query_class($init_entity);
$sub_query->setFilter($filter);
$sub_query->setTableAliasPostfix('_sub');
return 'EXISTS(' . $sub_query->getQuery() . ')';
};
}*/
$fields[$definition] = array(
'TABLE_ALIAS' => 'table',
'FIELD_NAME' => $sqlDefinition,
'FIELD_TYPE' => $field_type,
'MULTIPLE' => '',
'JOIN' => '',
'CALLBACK' => $callback
);
}
elseif (is_array($filter_match))
{
$fields = array_merge($fields, $this->getFilterCswFields($filter_match));
}
}
return $fields;
}