ロード時にLaravel / Eloquentモデルにカスタム属性を追加しますか?


219

RedBeanの $model->open()メソッドで実現できる方法と同様に、ロード時にLaravel / Eloquentモデルにカスタム属性/プロパティを追加できるようにしたいと思います。

たとえば、現時点では、私のコントローラーには次のものが含まれています。

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

ループを省略して、 'available'属性を既に設定および設定できると便利です。

ドキュメントで説明されているいくつかのモデルイベントを使用して、オブジェクトの読み込み時にこのプロパティをアタッチしようとしましたが、これまでのところ成功していません。

ノート:

  • 「利用可能」は、基になるテーブルのフィールドではありません。
  • $sessionsAPIの一部としてJSONオブジェクトとして返されているため$session->available()、テンプレートのようなものを呼び出すことはオプションではありません

回答:


316

この問題は、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);    
    }

}

今日の最高の質問と回答。私はこれを達成する方法についてさまざまな実装に取り​​組んでおり、laravel.ioに質問を投稿する直前に私はこれを見つけました!わーい !!!
Gayan Hewa 2014

そして、いくつかのケースでそれらをjsonに追加しない方法はありますか?
JordiPuigdellívol、2015年

3
これらの税関属性は、関係を介してモデルを呼び出すときに表示されないようです。(例:Models \ Company :: with( 'people'))。何か案が?
Andrew

@JordiPuigdellívolLaravel 5では、を使用しprotected $hidden = []て、列/アクセサを追加して除外することができます。
junkystu 2015年

124

Laravel Eloquentのドキュメントページ最後は次のとおりです。

protected $appends = array('is_admin');

これを自動的に使用して、のようなメソッドを変更するなどの追加作業なしで、モデルに新しいアクセサーを追加できます::toArray()

getFooBarAttribute(...)アクセサを作成しfoo_bar$appends配列に追加する だけです。


4
面白いですね。この機能は、私の質問が投稿されてから、Laravelに追加されました(github.com/laravel/framework/commit/…)。これは、v4.08以降を使用するすべての人にとって正しい答えです。
コートサップ2013年

3
関係を使用してアクセサーのコンテンツを生成している場合、これは利用できません。この場合、toArrayメソッドをオーバーライドする必要があるかもしれません。
gpmcadam 2015

2
参照していたドキュメントがhttps://laravel.com/docs/5.5/eloquent-serializationに移動したようです。
mibbler

40

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 ....
    }
}

私はそれをテストしませんでした、しかしあなたがあなたの現在のセットアップで試すのはかなり簡単なはずです。


これ->availableは、$sessionオブジェクトで利用できる範囲で機能しますが$sessions、JSON文字列(APIの一部)に直接変換されるため、これを使用する機会はありません。
コートサップ2013年

私はあなたのものがどのように機能するか理解しているのかわかりません。EventSession::all()APIからJSONオブジェクトを返す場合、実際にはLaravelモデルを使用していませんよね?申し訳ありませんが、モデルの実装方法がわかりません。
Alexandre Danault 2013年

EventSessionは標準のEloquentオブジェクト(class EventSession extends Eloquent)です。::all()単なる例です。EventSession::find(170071)別のものになります。これらはSessionController extends \BaseController、「/ sessions / 170071」などのURLを介して呼び出されるSessionController()全体のさまざまな時点で呼び出されます。
コートサップ2013年

重要なのは、Eloquentの組み込みオブジェクトからJSONへの変換が行われることにあると思います。public $availableモデルなどにカスタム属性を追加しても、オブジェクトの変換時には表示されません。
コートサップ2013年

3
これは2013年10月8日のLaravel 4.0.8のリリース以降に利用可能です。公式ドキュメントを参照してください:laravel.com/docs/eloquent#converting-to-arrays-or-json(を探すprotected $appends = array('is_admin');
Ronald Hulshof

23

私は何か似ています:モデルに属性画像があり、これには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);
}

1
$ attributes&$ appendsのpictureDataではなく、picture_dataである必要があります。また、$ attributes変数をスキップすることもできます。
Madushan Perera

16

setAttributeモデルの関数を使用してカスタム属性を追加できます


9

usersテーブルにfirst_nameとlast_nameという2つの列があり、フルネームを取得したいとします。あなたは次のコードで達成することができます:

class User extends Eloquent {


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

今、あなたはフルネームを次のように得ることができます:

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

7

ステップ1:$appends
ステップ2:属性のアクセサーを定義するで属性を定義します。
例:

<?php
...

class Movie extends Model{

    protected $appends = ['cover'];

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

3

私のサブスクリプションモデルでは、サブスクリプションが一時停止されているかどうかを知る必要があります。これが私がやった方法です

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

次に、ビューテンプレートで$subscription->is_paused、結果を取得するために使用できます 。

getIsPausedAttributeカスタム属性を設定するためのフォーマットであり、

そして使用していますis_pausedあなたのビューで属性を取得または使用します。


2

私の場合、空の列を作成し、そのアクセサーを設定するとうまくいきました。私のアクセサーは、ドブ列からユーザーの年齢を入力します。toArray()関数も機能しました。

public function getAgeAttribute()
{
  return Carbon::createFromFormat('Y-m-d', $this->attributes['dateofbirth'])->age;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.