Denis Priebe
Denis Priebe

Reputation: 2855

Create dynamic Laravel accessor

I have a Product model and also an Attribute model. The relationship between Product and Attribute is many to many. On my Product model I am trying to create a dynamic accessor. I am familiar with Laravel's accessors and mutators feature as documented here. The problem I am having is that I do not want to create an accessor every time I create a product attribute.

For example, A product may have a color attribute which could be setup like so:

/**
 * Get the product's color.
 *
 * @param  string  $value
 * @return string
 */
public function getColorAttribute($value)
{
    foreach ($this->productAttributes as $attribute) {
        if ($attribute->code === 'color') {
            return $attribute->pivot->value;
        }
    }

    return null;
}

The product's color could then be accessed like so $product->color. If I where to add a size attribute to the product I would need to setup another accessor on the Product model so I could access that like so $product->size.

Is there a way I can setup a single "dynamic" accessor to handle all of my attributes when accessed as a property?

Do I need to override Laravel's accessor functionality with my own?

Upvotes: 5

Views: 5995

Answers (3)

Mike Miller
Mike Miller

Reputation: 3129

I think probably Олег Шовкун answer is the right one but if you did want to use the model attribute notation you could get the required argument into the model via a class variable.

class YourModel extends Model{

  public $code;

  public function getProductAttribute()
  {
    //a more eloquent way to get the required attribute
    if($attribute = $this->productAttributes->filter(function($attribute){
       return $attribute->code = $this->code;
    })->first()){
        return $attribute->pivot->value;
    }

    return null;
  }
}

Then do

$model->code = 'color';
echo $model->product;

But its a bit long and pointless

Upvotes: 0

Laraleg
Laraleg

Reputation: 527

Yes, you can add your own piece of logic into the getAttribute() function of the Eloquent Model class (override it in your model), but in my opinion, it's not a good practice.

Maybe you can have a function:

public function getProductAttr($name)
{
    foreach ($this->productAttributes as $attribute) {
        if ($attribute->code === $name) {
            return $attribute->pivot->value;
        }
    }

    return null;
}

And call it like this:

$model->getProductAttr('color');

Upvotes: 5

Abid Raza
Abid Raza

Reputation: 755

Override Magic method - __get() method.

Try this.

public function __get($key)
{
    foreach ($this->productAttributes as $attribute) {
        if ($attribute->code === $key) {
            return $attribute->pivot->value;
        }
    }

    return parent::__get($key);
}

Upvotes: 5

Related Questions