简体   繁体   English

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

[英]Add a custom attribute to a Laravel / Eloquent model on load?

I'd like to be able to add a custom attribute/property to an Laravel/Eloquent model when it is loaded, similar to how that might be achieved with RedBean's $model->open() method.我希望能够在加载时向 Laravel/Eloquent 模型添加自定义属性/属性,类似于使用RedBean 的$model->open()方法实现的方式。

For instance, at the moment, in my controller I have:例如,目前,在我的控制器中,我有:

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

It would be nice to be able to omit the loop and have the 'available' attribute already set and populated.如果能够省略循环并且已经设置并填充了 'available' 属性,那就太好了。

I've tried using some of the model events described in the documentation to attach this property when the object loads, but without success so far.我已经尝试使用文档中描述的一些模型事件在对象加载时附加此属性,但到目前为止没有成功。

Notes:笔记:

  • 'available' is not a field in the underlying table. 'available' 不是基础表中的字段。
  • $sessions is being returned as a JSON object as part of an API, and therefore calling something like $session->available() in a template isn't an option $sessions作为 API 的一部分作为 JSON 对象返回,因此不能在模板中调用类似$session->available()的内容

The problem is caused by the fact that the Model 's toArray() method ignores any accessors which do not directly relate to a column in the underlying table.该问题是由ModeltoArray()方法忽略与基础表中的列不直接相关的任何访问器这一事实引起的。

As Taylor Otwell mentioned here , "This is intentional and for performance reasons."正如 Taylor Otwell 在这里提到的,“这是有意为之,也是出于性能原因。” However there is an easy way to achieve this:但是,有一种简单的方法可以实现这一目标:

class EventSession extends Eloquent {

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

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

Any attributes listed in the $appends property will automatically be included in the array or JSON form of the model, provided that you've added the appropriate accessor. $appends 属性中列出的任何属性都将自动包含在模型的数组或 JSON 形式中,前提是您已添加适当的访问器。

Old answer (for Laravel versions < 4.08):旧答案(对于 Laravel 版本 < 4.08):

The best solution that I've found is to override the toArray() method and either explicity set the attribute:我发现的最佳解决方案是覆盖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);    
    }

}

or, if you have lots of custom accessors, loop through them all and apply them:或者,如果您有很多自定义访问器,请遍历它们并应用它们:

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

}

The last thing on the Laravel Eloquent doc page is: Laravel Eloquent 文档页面上的最后一件事是:

protected $appends = array('is_admin');

That can be used automatically to add new accessors to the model without any additional work like modifying methods like ::toArray() .这可以自动用于向模型添加新的访问器,而无需任何额外的工作,例如修改::toArray()类的方法。

Just create getFooBarAttribute(...) accessor and add the foo_bar to $appends array.只需创建getFooBarAttribute(...)访问器并将foo_bar添加到$appends getFooBarAttribute(...)数组。

If you rename your getAvailability() method to getAvailableAttribute() your method becomes an accessor and you'll be able to read it using ->available straight on your model.如果您将getAvailability()方法重命名为getAvailableAttribute()您的方法将成为访问器,您将能够直接在模型上使用->available来读取它。

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

EDIT: Since your attribute is "virtual", it is not included by default in the JSON representation of your object.编辑:由于您的属性是“虚拟的”,因此默认情况下它不包含在您的对象的 JSON 表示中。

But I found this: Custom model accessors not processed when ->toJson() called?但我发现了这一点:调用 ->toJson() 时未处理自定义模型访问器?

In order to force your attribute to be returned in the array, add it as a key to the $attributes array.为了强制您的属性在数组中返回,请将其作为键添加到 $attributes 数组中。

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

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

I didn't test it, but should be pretty trivial for you to try in your current setup.我没有测试它,但对于您在当前设置中尝试应该非常简单。

I had something simular: I have an attribute picture in my model, this contains the location of the file in the Storage folder.我有一些类似的东西:我的模型中有一个属性图片,它包含文件在 Storage 文件夹中的位置。 The image must be returned base64 encoded图像必须返回 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);
}

Step 1: Define attributes in $appends第 1 步:在$appends定义属性
Step 2: Define accessor for that attributes.第 2 步:为该属性定义访问器。
Example:例子:

<?php
...

class Movie extends Model{

    protected $appends = ['cover'];

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

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

Let say you have 2 columns named first_name and last_name in your users table and you want to retrieve full name.假设您的用户表中有 2 列名为 first_name 和 last_name,并且您想要检索全名。 you can achieve with the following code :您可以使用以下代码实现:

class User extends Eloquent {


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

now you can get full name as:现在你可以得到全名:

$user = User::find(1);
$user->full_name;

In my subscription model, I need to know the subscription is paused or not.在我的订阅模型中,我需要知道订阅是否暂停。 here is how I did it这是我如何做到的

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

then in the view template,I can use $subscription->is_paused to get the result.然后在视图模板中,我可以使用$subscription->is_paused来获得结果。

The getIsPausedAttribute is the format to set a custom attribute, getIsPausedAttribute是设置自定义属性的格式,

and uses is_paused to get or use the attribute in your view.并使用is_paused在您的视图中获取或使用该属性。

in my case, creating an empty column and setting its accessor worked fine.就我而言,创建一个空列并设置其访问器工作正常。 my accessor filling user's age from dob column.我的访问器从 dob 列填充用户的年龄。 toArray() function worked too. toArray() 函数也有效。

public function getAgeAttribute()
{
  return Carbon::createFromFormat('Y-m-d', $this->attributes['dateofbirth'])->age;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM