I found that this is not a bug and is by design.
There’s a note on this pitfall in the API document.
Note: As this is a short-hand method only, using more complex conditions, like [’!=’, ‘id’, 1] will not work. If you need to specify more complex conditions, use find() in combination with where() instead.
protected static function findByCondition($condition)
{
$query = static::find();
if (!ArrayHelper::isAssociative($condition) && !$condition instanceof ExpressionInterface) {
// query by primary key
$primaryKey = static::primaryKey();
if (isset($primaryKey[0])) {
// if condition is scalar, search for a single primary key, if it is array, search for multiple primary key values
$condition = [$primaryKey[0] => is_array($condition) ? array_values($condition) : $condition];
} else {
throw new InvalidConfigException('"' . get_called_class() . '" must have a primary key.');
}
}
return $query->andWhere($condition);
}
As far as I can see, that is done to replace search by hash-format condition with a search by primary keys. These two syntaxes conflict. That is what’s meant by “shortcut”.
Also, I don’t see it should be fixed since it is not safe to pass user-supplied condition to a method supporting hash-format without pre-filtering while it’s OK to do it for shortcut-method.
So, the following table shows the comparison of the condition parameter of the relevant methods.
Method
Scalar Value
Non-Associative Array
Associative Array
Expression
findOne()
PK Search
PK search
Column Search
Generic Search
findAll()
PK Search
PK search
Column Search
Generic Search
where()
(not supported)
Operator Format Search
Column Search
Generic Search
I hope it is correct.
A non-associative array will be treated as the search key for the multi-column primary key in findOne() and findAll(), while it is treated as an operator-format conditions in where().
findOne() and findAll() follow the same logic, by sharing findByCondition() internally.
But I don’t think the PK search for findAll() has much meaning, since it will not return more than 1 record in an ordinary scenario. I’d rather want it to behave like where()->all() does.