php - Yii2 DataFilter 构建错误的条件
问题描述
我必须按要求按日期过滤。我知道现有的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;
}
如您所见,有“EQUALS”操作数而不是“>”,它在 query-string 中定义?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
解决方案
ActiveDataFilter
和之间有一个粘性差异DataFilter
。它在方法中得出结论[[buildInternal()]]
。
DataFilter
方法:
protected function buildInternal()
{
return $this->normalize(false);
}
ActiveDataFilter
方法:
protected function buildInternal()
{
$filter = $this->normalize(false);
if (empty($filter)) {
return [];
}
return $this->buildCondition($filter);
}
通过调用$this->buildCondition($filter)
ActiveDataFilter
传递$filter
变量,然后应用 QueryBilders,$filter
变量变为:
$filter = ['>', 'date_success', 100];
推荐阅读
- javascript - 如何处理打字稿中的确切值类型
- apache-kafka - Kafka 中的 CommitSync
- python - 入门:Huggingface 模型卡
- excel - Excel Pivot - 计算值 > XX 的平均值
- python - Python - 使用 Plotly Express 的交互式多线图 - 需要基于列中相似值的每条线
- django - Django collectstatic 在部署到 Heroku 时重新收集模块静态文件
- sql-server - 如何将一条记录重复 n 次 - SQL Server
- ssms - SQL 服务器管理工作室关系连接
- tfs - DevOps 2019 Office 集成是否可以使用每个工作表都与不同的 wiql 查询相关的 excel 文件?
- vba - 如何在自定义约会选项卡中运行代码?