我正在尝试对Laravel模型的虚拟属性使用动态访问器。实际上,我想处理以下情况:如果属性不直接存在/数据库中不存在,请从配置文件中加载它的值。
我设法通过为每个属性编写一个访问器来处理它,但是我发现它是多余且丑陋的。我相信它可以更有效地完成。
class MyModel extends Model
{
public function getTitleAttribute()
{
return $this->loadAttributeFromConfig('title');
}
public function getSubtitleAttribute()
{
return $this->loadAttributeFromConfig('subtitle');
}
public function getTagAttribute()
{
return $this->loadAttributeFromConfig('tag');
}
public function getIconCssClassAttribute()
{
return $this->loadAttributeFromConfig('iconCssClass');
}
public function getBoxCssClassAttribute()
{
return $this->loadAttributeFromConfig('boxCssClass');
}
public function getBulletsAttribute()
{
return $this->loadAttributeFromConfig('bullets');
}
protected function loadAttributeFromConfig($attribute)
{
return config('myConfigAttributes.' . $this->name . '.' . $attribute);
}
}
$myModel->append(['title', 'subtitle', 'tag', 'iconCssClass', 'boxCssClass', 'bullets']);
我的解决方案有效,但我认为它很丑。
答案 0 :(得分:1)
使用__get
魔术方法实际上可以很容易地实现。您可以在继承的基本模型类上重写它,或创建如下特征:
trait ConfigAttributes
{
/**
* @param string $key
*
* @return mixed
* @throws \Exception
*/
public function __get($key)
{
// Make sure the required configuration property is defined on the parent class
if (!property_exists($this, 'configAttributes')) {
throw new Exception('The $configAttributes property should be defined on your model class');
}
if (in_array($key, $this->configAttributes)) {
return $key;
}
return parent::__get($key);
}
/**
* @return array
*/
public function toArray()
{
// We need to override this method because we need to manually append the
// attributes when serializing, since we're not using Eloquent's accessors
$data = collect($this->configAttributes)->flip()->map(function ($v, $key) {
return $this->loadAttributeFromConfig($key);
});
return array_merge(parent::toArray(), $data->toArray());
}
/**
* @param string $attribute
*
* @return mixed
*/
protected function loadAttributeFromConfig($attribute)
{
return config('myConfigAttributes.' . $this->name . '.' . $attribute);
}
}
然后在模型类中,只需导入特征并指定自定义字段:
class MyModel extends Model
{
use ConfigAttributes;
protected $configAttributes = [
'title',
'subtitle',
'tag',
'iconCssClass',
'boxCssClass',
'bullets'
];
}
警告语::在Laravel定义的类上覆盖魔术方法时要小心,因为Laravel大量使用了它们,如果不小心,可能会破坏其他功能。