Search code examples
laravellaravel-9

Laravel 9's setter mutator throws an error but Laravel 8 style mutator does not


Laravel 9+ has this new mutator format according to the docs:

public function fullName(): Attribute
{
    return Attribute::make(
        get: fn() => trim($this->first_name.' '.$this->last_name),
        set: function (?string $value) {
            $names = explode(' ', $value);

            $this->attributes['first_name'] = array_shift($names);
            $this->attributes['last_name'] = implode(' ', $names);
        }
    );
}

In my model I have this:

protected $appends = ['full_name'];

However, if I try to save the value like this:

$model->full_name = 'John Doe';
$model->save();

Then I get the error:

Column not found: 1054 Unknown column 'full_name' in 'field list

However, if I use the old way to format mutator setter methods like this then there is no error:

public function setFullNameAttribute(?string $value): void
{
    $names = explode(' ', $value);

    $this->attributes['first_name'] = array_shift($names);
    $this->attributes['last_name'] = implode(' ', $names);
}

Why doesn't the new mutator format work when setting values?


Solution

  • Setting the attributes property was the problem. The values should be returned as an array in the setter for Laravel to handle itself.

    protected function fullName(): Attribute
    {
        return Attribute::make(
            get: fn(mixed $value, array $attr) => trim($attr['first_name'].' '.$attr['last_name']),
            set: function (?string $value) {
                $names = explode(' ', $value);
    
                return [
                    'first_name' => array_shift($names),
                    'last_name'  => implode(' ', $names),
                ];
            }
        );
    }