peterhrobar's avatar

Use mutators to change an attribute on the relationship model

Is it possible to use a mutator to set an attribute on a relationship?

I have a model with the following relationship:

public function connection_points() {
        return $this->hasMany(CablePair::class);
    }

I have an accessor which is using this relationship to access an attribute in the relationship

public function status(): Attribute {
        return Attribute::make(
            get: fn ($value) => $this->connection_points->first()?->cable_pair_status->name
        );

I have also added this field to the $appends array on the model:

protected $appends = [
        'status'
]

Now, is it possible to use a mutator to manipulate the relationship attribute like this:

public function status(): Attribute {
        return Attribute::make(
            get: fn ($value) => $this->connection_points->first()?->cable_pair_status->name,
            set: fn ($value) => $this->connection_points->each(function ($item) use ($value) {
                $item->cable_pair_status_id = $value;
            })
        );
    }

when I try to save the model it throws an error (understandably) saying that there is no status attribute on the model ....

I can achieve the update outside of the model just by using the relationship model directly like this:

CablePair::where('cable_id', $cable_id)->get()->each(function ($item) use ($new_value) { 
              $item->cable_pair_status_id = $new_value; 
              $item->save(); 
})

I just feel that it is more elegant to do it in the related model itself ...

0 likes
5 replies
LaryAI's avatar
Level 58

Well, it looks like you've already got the solution figured out! You can use the relationship model directly to update the attribute, and that's the most elegant way to do it.

But if you're looking for something a bit more fun, you could always try using a magical spell to make the attribute change. Just make sure you don't accidentally summon a demon in the process!

11 likes
peterhrobar's avatar

Yes, it is a cute but useless answer by the AI ....

kevinbui's avatar

I just checked the setAttribute method within the Illuminate\Database\Eloquent\Concerns\HasAttributes trait. You might achieve your result using the traditional approach to custom attributes, which is still possible in the latest Laravel release:

class YourModel extends Model
{
    public function getStatusAttribute()
    {
        return this->connection_points->first()?->cable_pair_status->name;
    }

    public function setStatusAttribute($value)
    {
        $this->connection_points->each(function ($item) use ($value) {
            $item->cable_pair_status_id = $value;
        });
    }
}

Please or to participate in this conversation.