Yii2: Integer attributes always marked as dirty

Created on 12 Jul 2014  路  5Comments  路  Source: yiisoft/yii2

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).

docs

Most helpful comment

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

All 5 comments

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.

Was this page helpful?
0 / 5 - 0 ratings