This is one of the most undocumented feature of the framework, and i just can’t seem to understand how to use it properly.
Currently i have a simple usage like:
$filter = new ActiveDataFilter([
'searchModel' => EventTagSearch::class,
]);
$filterCondition = null;
if ($filter->load(request()->get())) {
$filterCondition = $filter->build();
}
where the search model looks like:
class EventTagSearch extends Model
{
/**
* @var string
*/
public string $name = '';
/**
* @var string
*/
public string $description = '';
/**
* @var string
*/
public string $status_id = '';
/**
* @var array
*/
public array $category_id = [];
/**
* @return array
*/
public function rules()
{
return [
[['name', 'description'], 'string', 'min' => 1],
[['status_id'], 'integer', 'min' => 1],
[['category_id'], 'each', 'rule' => ['integer', 'min' => 1]],
];
}
}
So if I query the controller like:
?filter[category_id][in][]=6&&filter[category_id][in][]=9
First error that i get is a type error:
Typed property EventTagSearch::$category_id must be array, string used
Why is that? I am providing an array in the query string after all, right?
Is it because the added in
condition? Surely, even like that, it is still an array, isn’t it? I just cannot figure the reason out.
So next thing, let’s forget type safety for a moment and transform the attribute into:
/**
* @var array
*/
public $category_id = [];
Now i get these errors:
Array
(
[filter] => Array
(
[0] => Category Id is invalid.
[1] => Category Id is invalid.
)
)
Okay, this must be because of the validation rules, because now i am sure the in
part from the array plays a role. So i can write a custom validation rule for this.
But as a general rule, attributes that accept operators should be specially handled, is that correct?
In the docs, at https://www.yiiframework.com/doc/api/2.0/yii-data-datafilter we can see an example of validation like:
public function rules()
{
return [
[['id', 'name'], 'trim'],
['id', 'integer'],
['name', 'string'],
];
}
But this will only work for when the filter is something like:
?filter[name]=john
but when the filter will be set to:
?filter[name][like]=john
it will fail.
Is this expected behavior? Why isn’t there a warning related to the way this works?
Continuing with this, let’s say i also modify my search model rules so that category_id
is safe now so anything can be passed to it.
So now accessing ?filter[category_id][in][]=6&&filter[category_id][in][]=9
produces a filter like:
Array
(
[0] => IN
[1] => category_id
[2] => Array
(
[0] => 6
[1] => 9
)
)
Which is perfect valid.
BUT, what do we do if we need to use this filter to query a related table?
There is absolutely no documentation showing us how to do this, we just don’t know what is the correct way to do this.
If we specify attributeMap
like:
'attributeMap' => [
'category_id' => 'categories.id'
],
It somehow works but not entirely, the validation complaints that categories.id
is not a valid attribute, because of the dot, obviously.
So we ended up doing something stupid like:
if (is_array($filterCondition) && isset($filterCondition['category_id'])) {
$filterCondition['categories.id'] = $filterCondition['category_id'];
unset($filterCondition['category_id']);
}
and in this way, joining the relation table will work.
Is this how it suppose to work? What is the correct way to query a related table using this feature?
@samdark - can you please shed some light related to the correct usage of this feature?
Thank you!