创建动态的Laravel访问器

5
我有一个产品模型和一个属性模型,它们之间的关系是多对多。在我的产品模型中,我想创建一个动态访问器。我熟悉 Laravel 的访问器和修改器功能,如此处所述。但问题是,我不想每次创建产品属性时都创建一个访问器。
例如,一个产品可能有一个颜色属性,可以这样设置:
/**
 * 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;
}

产品的颜色可以这样访问:$product->color。如果我要添加一个size属性到产品中,我需要在Product模型上设置另一个访问器,这样我就可以像这样访问它:$product->size是否有一种方法可以设置单个“动态”访问器来处理所有属性的访问? 我需要覆盖Laravel的访问器功能吗?

也许在多对多关系中的定义自定义中间表模型部分,是你需要采取的方法,而不是绕弯路去做。 - apokryfos
我知道这是一个比较旧的问题,但是我很好奇,你是否使用public $with = ['attributes']来预加载属性到Product模型中? - WhyAyala
3个回答

5

是的,您可以在Eloquent Model类的getAttribute()函数中添加自己的逻辑(在模型中覆盖它),但我认为这不是一个好的做法。

也许您可以有一个函数:

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

    return null;
}

并且像这样调用它:

$model->getProductAttr('color');

是的,我也是这么想的。但我们不能使用getAttribute(),因为那会覆盖HasAttributes trait中的方法。感谢您的回答。 - Denis Priebe
你说得对,这个名称是被保留的。已经修正了答案。 - Laraleg
你可能会对 https://github.com/topclaudy/eloquent-mutators 感兴趣。 - topclaudy

5

覆盖魔术方法 - __get() 方法。

试试这个。

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

    return parent::__get($key);
}

我似乎无法让它正常工作。我认为当__get方法触发时,Laravel没有加载所有模型的关系。不过我会继续尝试。 - Denis Priebe
它似乎可以使用基本的一对多关系。然而,在定义产品和属性之间的关系时,我正在使用withPivot方法。在那一点上它会抛出一个错误。让我进一步研究一下,看看是否能够解决它。谢谢。 - Denis Priebe
不客气。很高兴能帮忙。显然,你可以为任何关系定制此方法。 - Abid Raza
我理论上喜欢这个想法,但这样做会不会影响所有访问器的性能呢? - WhyAyala

0

我认为Олег Шовкун的答案可能是正确的,但如果您确实想使用模型属性符号表示法,您可以通过类变量将所需参数传递到模型中。

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;
  }
}

然后执行

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

但它有点冗长和无意义


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接