chadhutchins's avatar

Adding Same Accessor Method to Multiple Model Classes

Hi all, I'm looking to add the same accessor to multiple models. I looked at Traits, but I don't think it quite solves the problem. Here's an example:

class User extends Model
{
    protected $details = [
        'a' => 1,
        'b' => 2,
        'c' => 3,
    ];

    public function getDetailsAttribute() {
        return $this->details;
    }
}

I want to add this same details accessor to multiple models WITHOUT having to copy/paste the getDetailsAttribute in each model class.

Is there a way to do this?

Thanks!

0 likes
8 replies
Snapey's avatar

i can't think of a reason why a trait would not work in this case

Alternatively, create your own Model class which extends Illuminate model, then switch your models to extend this new class.

chadhutchins's avatar

@snapey thanks for the feedback, felt like overkill extending a model for this. Traits felt just right, but I couldn't get it right.

Here's what I tried:


namespace App\Traits;

trait Detailable
{
    public function getAttribute($key)
    {
        if ($key == 'details') return $this->details;
    }

    public function setAttribute($key, $value)
    {
        // don't really care about the setAttribute... 
        return parent::setAttribute($key, $value);
    }
}

Basically if the key is 'details', return the protected member variable. It would always return null for me. Any ideas?

Snapey's avatar

use accessor?

public function getDetailsAttribute()
{
    return $this->details;
}
chadhutchins's avatar

@snapey Thanks, I think that's the best answer right now, I was just hoping to avoid copy/paste the same accessor in multiple models. Would be nice if this could be done through a trait somehow.

Thanks again for the help!

Snapey's avatar
Snapey
Best Answer
Level 122

Just put those lines in a trait !

(but then import the trait, and use the trait in every model)

Or create your own model that extends the base model (as mentioned)

chadhutchins's avatar

@snapey thanks again for the help! I thought I tried adding that to a trait before and had issues, but I guess not. I did what you suggested and that worked perfectly. Thanks!

dlogon's avatar

You can create a base model and add the appends to this model.

You should add a booted closure for retrieved and add the appends here, with this, you don't overwrite the child appends.

abstract class BaseModel extends Model
{
		protected $details = [
        'a' => 1,
        'b' => 2,
        'c' => 3,
    ];
    protected $appends = ['details'];

    public function getDetailsAttribute() {
        return $this->details;
    }

    protected static function booted()
    {
        static::retrieved(function (Model $model) {
            $model->appends = array_merge($model->appends, ['details']);
        });
    }
}
Snapey's avatar

@dlogon its a 4 year old question, that was already answered to their satisfaction

Please or to participate in this conversation.