Я должен сделать фильтрацию по дате в запросе. Я знаю о существующем yii\data\DataFilter
классе, поэтому я использовал его для решения проблемы.
Фактический URL-адрес запроса (пример): https://api.site.com/module/post?filter[from_date][>=]=100
Не беспокойтесь о значении 100 , мы используем UNIX в нашей политике.
Я использую yii\rest\ActiveController
для выполнения действий, поэтому я определил dataFilter
свойство в [[actions()]]
:
public function actions()
{
$actions = parent::actions();
$actions['index']['dataFilter'] = [
'class' => DataFilter::class,
'attributeMap' => [
'from_date' => 'date_success',
'to_date' => 'date_success',
],
'searchModel' => function () {
return (new DynamicModel(['from_date', 'to_date']))
->addRule(['from_date', 'to_date'], 'integer', ['min' => 0]);
},
];
return $actions;
}
После завершения запроса, возвращается пустой массив []
. Я проследил SQL запросов:
Как вы можете видеть, вместо ">" есть операнд "EQUALS", который определен в строке запроса ?filter[from_date][>]=100
.
По умолчанию в yii\rest\IndexAction
переменная $query
вызывает метод where($filter)
:
/*
After successful filter build $filter variable becomes:
$filter = [
'date_success' => [
'>' => 100,
],
]
*/
$query = $modelClass::find();
if (!empty($filter)) {
$query->andWhere($filter);
}
Почему это происходит? Я отладил код и нашел одну интересную особенность! В yii\db\conditions\HashConditionBuilder
:
public function build(ExpressionInterface $expression, array &$params = [])
{
$hash = $expression->getHash();
$parts = [];
foreach ($hash as $column => $value) {
if (ArrayHelper::isTraversable($value) || $value instanceof Query) {
// IN condition
// Executing will be here.
// Yii2 thinks thats 'IN' condition, and builds as 'IN'.
$parts[] = $this->queryBuilder->buildCondition(new InCondition($column, 'IN', $value), $params);
} else {
if (strpos($column, '(') === false) {
$column = $this->queryBuilder->db->quoteColumnName($column);
}
if ($value === null) {
$parts[] = "$column IS NULL";
} elseif ($value instanceof ExpressionInterface) {
$parts[] = "$column=" . $this->queryBuilder->buildExpression($value, $params);
} else {
$phName = $this->queryBuilder->bindParam($value, $params);
$parts[] = "$column=$phName";
}
}
}
return count($parts) === 1 ? $parts[0] : '(' . implode(') AND (', $parts) . ')';
}
Эта проблема повторяется с различными «conditionOperators», результат абсолютно одинаковый.
filter[from_date][=]=100
filter[from_date][<]=100
filter[from_date][gt]=100
filter[from_date][gte]=100