在加载时将自定义属性添加到Laravel/Eloquent模型?

coa*_*sap 195 php orm laravel eloquent

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

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

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

能够省略循环并且已经设置和填充'available'属性会很好.

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

笔记:

  • 'available'不是基础表中的字段.
  • $sessions作为API的一部分作为JSON对象返回,因此调用类似于$session->available()模板的东西不是一种选择

coa*_*sap 298

问题是由于Models toArray()方法忽略了与基础表中的列没有直接关系的任何访问器.

正如泰勒奥特威尔此提到的那样,"这是故意的,也是出于性能原因." 但是,有一种简单的方法可以实现这一目标:

class EventSession extends Eloquent {

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

    public function getAvailabilityAttribute()
    {
        return $this->calculateAvailability();  
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您添加了适当的访问者,则$ 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);    
    }

}
Run Code Online (Sandbox Code Playgroud)

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

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

}
Run Code Online (Sandbox Code Playgroud)

  • 通过关系调用模型时,似乎不会出现这些习惯属性.(例如:Models\Company :: with('people')).任何的想法? (3认同)

trm*_*m42 119

该Laravel雄辩文档页面上最后一件事是:

protected $appends = array('is_admin');
Run Code Online (Sandbox Code Playgroud)

这可以自动用于向模型添加新的访问器,而无需像修改方法那样进行任何额外的工作::toArray().

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

  • 好有意思啊 自我的问题发布以来,此功能已添加到Laravel(https://github.com/laravel/framework/commit/615f16fb0407f7668536bdc0b578fea60dda5d18).对于使用v4.08或更高版本的任何人来说,这是正确的答案. (4认同)
  • 如果您使用关系为您的访问者生成内容,则无法使用此功能.在这种情况下,您可能不得不求助于覆盖`toArray`方法. (3认同)
  • 好像您提到的文档已移至此处:[https://laravel.com/docs/5.5/eloquent-serialization](https://laravel.com/docs/5.5/eloquent-serialization) . (2认同)

Ale*_*ult 38

如果您将getAvailability()方法重命名为getAvailableAttribute()您的方法成为访问者,您将能够->available直接在模型上阅读它.

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

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

但我发现这个:当 - > toJson()调用时,自定义模型访问器不被处理?

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

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

    public function getZipCodeAttribute()
    {
        return ....
    }
}
Run Code Online (Sandbox Code Playgroud)

我没有对它进行测试,但对于您尝试当前的设置应该是非常简单的.

  • 这是自2013年10月8日Laravel 4.0.8发布以来的.请参阅官方文档:http://laravel.com/docs/eloquent#converting-to-arrays-or-json(查找`protected $ appends = array('is_admin');`) (3认同)

Bed*_*ang 20

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

<?php
...

class Movie extends Model{

    protected $appends = ['cover'];

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

Run Code Online (Sandbox Code Playgroud)


小智 18

我有一些类似的东西:我的模型中有一个属性图片,它包含Storage文件夹中文件的位置.必须返回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);
}
Run Code Online (Sandbox Code Playgroud)


jia*_*eng 14

您可以使用setAttributeModel中的函数来添加自定义属性


小智 6

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

class User extends Eloquent {


    public function getFullNameAttribute()
    {
        return $this->first_name.' '.$this->last_name;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在您可以得到全名:

$user = User::find(1);
$user->full_name;
Run Code Online (Sandbox Code Playgroud)