[13.x] Fix extra attributes skipping casts when incrementing or decrementing a model

Merged
SU
21d ago
+28-0

The extra attributes passed to increment(), decrement(), incrementEach() and decrementEach() on a model are written to the database as they were passed in, without going through casts or mutators:

class User extends Model
{
    protected $casts = ['api_token' => 'encrypted'];
}

$user->increment('logins', 1, ['api_token' => $token]);

$user->fresh()->api_token; // DecryptException: The payload is invalid.

The token is stored as plain text, so it ends up unencrypted in the database and can't be read back. The same goes for other casts and set mutators, like a mutator that lowercases an email: the model holds the mutated value but the column gets the raw one.

The methods already forceFill() the extra attributes onto the model, so this sends those stored values in the update instead of the raw input, matching what save() would write. Keys that aren't attributes, like JSON paths (options->enabled), are still passed through as before.