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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17232714/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 12:33:09  来源:igfitidea点击:

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

phpormlaraveleloquent

提问by coatesap

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.
  • $sessionsis 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
  • 'available' 不是基础表中的字段。
  • $sessions作为 API 的一部分作为 JSON 对象返回,因此$session->available()不能在模板中调用类似的东西

回答by coatesap

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.

问题是由于Model'stoArray()方法忽略了与基础表中的列不直接相关的任何访问器。

As Taylor Otwell mentioned here, "This is intentional and for performance reasons." However there is an easy way to achieve this:

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

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

}

回答by trm42

The last thing on the Laravel Eloquent doc pageis:

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

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_barto $appendsarray.

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

回答by Alexandre Danault

If you rename your getAvailability()method to getAvailableAttribute()your method becomes an accessorand you'll be able to read it using ->availablestraight 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.

我没有测试它,但对于您在当前设置中尝试应该非常简单。

回答by Patrique

I had something simular: I have an attribute picture in my model, this contains the location of the file in the Storage folder. The image must be returned base64 encoded

我有一些类似的东西:我的模型中有一个属性图片,它包含文件在 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);
}

回答by jianfeng

you can use setAttributefunction in Model to add a custom attribute

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

回答by ShuBham GuPta

Let say you have 2 columns named first_name and last_name in your users table and you want to retrieve full name. you can achieve with the following code :

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

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;

回答by Bedram Tamang

Step 1: Define attributes in $appends
Step 2: Define accessor for that attributes.
Example:

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

<?php
...

class Movie extends Model{

    protected $appends = ['cover'];

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

回答by li bing zhao

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_pausedto get the result.

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

The getIsPausedAttributeis the format to set a custom attribute,

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

and uses is_pausedto get or use the attribute in your view.

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

回答by Hanif Rifa'i

in my case, creating an empty column and setting its accessor worked fine. my accessor filling user's age from dob column. toArray() function worked too.

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

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