263

我希望能够在加载 Laravel/Eloquent 模型时为其添加自定义属性/属性,类似于使用RedBean 的 $model->open()方法可以实现的方式。

例如,目前,在我的控制器中,我有:

public function index()
{
    $sessions = EventSession::all();
    foreach ($sessions as $i => $session) {
        $sessions[$i]->available = $session->getAvailability();
    }
    return $sessions;
}

如果能够省略循环并且已经设置并填充了“可用”属性,那就太好了。

我尝试使用文档中描述的一些模型事件在对象加载时附加此属性,但到目前为止没有成功。

笔记:

  • “可用”不是基础表中的字段。
  • $sessions作为 API 的一部分作为 JSON 对象返回,因此$session->available()不能在模板中调用类似的东西
4

9 回答 9

380

该问题是由于Model'toArray()方法忽略了与基础表中的列不直接相关的任何访问器这一事实引起的。

正如 Taylor Otwell 在这里提到的,“这是故意的,也是出于性能原因。” 但是,有一种简单的方法可以实现这一点:

class EventSession extends Eloquent {

    protected $table = 'sessions';
    protected $appends = array('availability');

    public function getAvailabilityAttribute()
    {
        return $this->calculateAvailability();  
    }
}

只要您添加了适当的访问器,$appends 属性中列出的任何属性都将自动包含在模型的数组或 JSON 形式中。

旧答案(对于 Laravel 版本 < 4.08):

我发现的最佳解决方案是覆盖该toArray()方法并明确设置属性:

class Book extends Eloquent {

    protected $table = 'books';

    public function toArray()
    {
        $array = parent::toArray();
        $array['upper'] = $this->upper;
        return $array;
    }

    public function getUpperAttribute()
    {
        return strtoupper($this->title);    
    }

}

或者,如果您有很多自定义访问器,请遍历它们并应用它们:

class Book extends Eloquent {

    protected $table = 'books';

    public function toArray()
    {
        $array = parent::toArray();
        foreach ($this->getMutatedAttributes() as $key)
        {
            if ( ! array_key_exists($key, $array)) {
                $array[$key] = $this->{$key};   
            }
        }
        return $array;
    }

    public function getUpperAttribute()
    {
        return strtoupper($this->title);    
    }

}
于 2013-06-22T11:51:10.047 回答
130

Laravel Eloquent 文档页面上的最后一件事是:

protected $appends = array('is_admin');

这可以自动用于向模型添加新的访问器,而无需像修改::toArray().

只需创建getFooBarAttribute(...)访问器并添加foo_bar$appends数组。

于 2013-09-30T07:22:39.117 回答
41

如果您将您的getAvailability()方法重命名为getAvailableAttribute()您的方法成为访问器,您将能够->available直接在您的模型上使用它来读取它。

文档:https ://laravel.com/docs/5.4/eloquent-mutators#accessors-and-mutators

编辑:由于您的属性是“虚拟的”,因此默认情况下它不包含在对象的 JSON 表示中。

但我发现了这一点:Custom model accessors not processed when ->toJson() called?

为了强制在数组中返回您的属性,请将其作为键添加到 $attributes 数组中。

class User extends Eloquent {
    protected $attributes = array(
        'ZipCode' => '',
    );

    public function getZipCodeAttribute()
    {
        return ....
    }
}

我没有对其进行测试,但在您当前的设置中尝试应该很简单。

于 2013-06-21T13:06:40.347 回答
30

我有一些类似的东西:我的模型中有一张属性图片,它包含存储文件夹中文件的位置。图像必须以 base64 编码返回

//Add extra attribute
protected $attributes = ['picture_data'];

//Make it available in the json response
protected $appends = ['picture_data'];

//implement the attribute
public function getPictureDataAttribute()
{
    $file = Storage::get($this->picture);
    $type = Storage::mimeType($this->picture);
    return "data:" . $type . ";base64," . base64_encode($file);
}
于 2015-12-29T22:26:45.783 回答
23

第 1 步:在$appends
第 2 步中定义属性:定义该属性的访问器。
例子:

<?php
...

class Movie extends Model{

    protected $appends = ['cover'];

    //define accessor
    public function getCoverAttribute()
    {
        return json_decode($this->InJson)->cover;
    }

于 2020-03-27T03:35:16.353 回答
19

您可以setAttribute在模型中使用函数来添加自定义属性

于 2014-10-28T07:59:08.910 回答
10

假设您的用户表中有 2 列名为 first_name 和 last_name,并且您想要检索全名。您可以使用以下代码实现:

class User extends Eloquent {


    public function getFullNameAttribute()
    {
        return $this->first_name.' '.$this->last_name;
    }
}

现在你可以得到全名:

$user = User::find(1);
$user->full_name;
于 2019-01-23T12:26:25.017 回答
3

在我的订阅模型中,我需要知道订阅是否已暂停。我是这样做的

public function getIsPausedAttribute() {
    $isPaused = false;
    if (!$this->is_active) {
        $isPaused = true;
    }
}

然后在视图模板中,我可以 $subscription->is_paused用来获取结果。

getIsPausedAttribute是设置自定义属性的格式,

并用于is_paused获取或使用视图中的属性。

于 2017-06-19T14:51:41.723 回答
2

就我而言,创建一个空列并设置其访问器工作正常。我的访问者从 dob 列填充用户的年龄。toArray() 函数也有效。

public function getAgeAttribute()
{
  return Carbon::createFromFormat('Y-m-d', $this->attributes['dateofbirth'])->age;
}
于 2016-03-31T19:19:06.060 回答