Consider a model "Person" with two attributes: "name" (varchar) and "age" (int).
Open up the update view for an existing model with name="John" and age=10. Don't change either of the fields and submit the form.
Yii will now consider the "age" attribute as dirty, and thus a sql UPDATE command will be ran, and afterSave() will receive this attribute in $changedAttributes. As this only happens for integer columns, I suspect it has something to do with the typecasting between form input (string) and database (integer).
Indeed. In BaseActiveRecord.getDirtyAttributes, _oldAttributes is already typecasted, while _attributes isn't. Because of the strict comparison $value !== $this->_oldAttributes[$name] the attribute is considered dirty.
*yii\db\BaseActiveRecord*_attributes array[3]
[id] integer 1
[name] string "Lauren Graham"
[age] string "1"
*yii\db\BaseActiveRecord*_oldAttributes array[3]
[id] integer 1
[name] string "Lauren Graham"
[age] integer 1
if you receive user input via POST you have to typecast it yourself. You can use a filter validator for this:
['age', 'filter', 'filter' => 'intval'],
related to #2790
It depends, whether default is NULL or 0. More accurate would be the next: remove extra spaces, verify the +-\d regular expression, set null or 0 for empty strings and finally convert the result to the appropriate mapping type, i. e. INT:
['age', 'trim'],
['age', 'integer', 'integerOnly' => true, 'min' => 0],
['age','default', 'value' => null], //or 0
['age', 'filter', 'filter' => function($value) {
return is_null($value) ? null : intval($value);
}],
['age', 'filter', 'filter' => 'intval'],
intval('') and intval(null) is 0, new attribute value after filter becomes 0, old attribute value by default is NULL as it's usually set in a database schema, yii will mark this attribute as dirty (INT 0 === NULL null) and save it.
Best wishes,
auxww
@auxww you can set skipOnEmpty to true on the filter so it would not convert a null value.
added an example to the guide.
Most helpful comment
if you receive user input via POST you have to typecast it yourself. You can use a filter validator for this:
related to #2790