Hinzufügen eines benutzerdefinierten Attributs zu einem Laravel / Eloquent Modell beim Laden?

Ich würde gerne in der Lage sein, einem Laravel / Eloquent-Modell ein benutzerdefiniertes Attribut / Eigenschaft hinzuzufügen, wenn es geladen wird, ähnlich wie dies mit RedBeans $model->open() -Methode erreicht werden könnte.

Zum Beispiel, in meinem Controller habe ich:

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

Es wäre schön, in der Lage zu sein, die Schleife wegzulassen und das Attribut ‘available’ bereits gesetzt und aufgefüllt zu haben.

Ich habe versucht, einige der in der Dokumentation beschriebenen Modellereignisse zu verwenden, um diese Eigenschaft beim Laden des Objekts anzuhängen, aber bisher ohne Erfolg.

Anmerkungen:

  • ‘verfügbar’ ist kein Feld in der zugrunde liegenden Tabelle.
  • $sessions werden als JSON-Objekt als Teil einer API zurückgegeben, und daher ist das Aufrufen von etwas wie $session->available() in einer Vorlage keine Option

Das Problem wird durch die Tatsache verursacht, dass die toArray() -Methode des Model toArray() ignoriert, die sich nicht direkt auf eine Spalte in der zugrunde liegenden Tabelle beziehen.

Wie Taylor Otwell hier erwähnte: “Dies ist beabsichtigt und aus performancesgründen.” Es gibt jedoch einen einfachen Weg, dies zu erreichen:

 class EventSession extends Eloquent { protected $table = 'sessions'; protected $appends = array('availability'); public function getAvailabilityAttribute() { return $this->calculateAvailability(); } } 

Alle in der $ anhängigen Eigenschaft aufgelisteten Attribute werden automatisch in das Array oder die JSON-Form des Modells eingefügt, sofern Sie den entsprechenden Zugriffsmechanismus hinzugefügt haben.

Alte Antwort (für Laravel-Versionen <4.08):

Die beste Lösung, die ich gefunden habe, ist, die toArray() Methode zu überschreiben und das Attribut entweder explizit zu setzen:

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

oder, wenn Sie viele benutzerdefinierte Accessoren haben, durchlaufen Sie sie alle und wenden Sie sie an:

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

Die letzte Sache auf der Laravel Eloquent Doc-Seite ist:

 protected $appends = array('is_admin'); 

Dies kann automatisch verwendet werden, um dem Modell neue ::toArray() hinzuzufügen, ohne dass zusätzliche Arbeiten wie das Ändern von Methoden wie ::toArray() .

Erstellen getFooBarAttribute(...) einfach den getFooBarAttribute(...) Accessor und fügen Sie die foo_bar zu $appends array hinzu.

Wenn Sie Ihre getAvailability() -Methode in getAvailableAttribute() umbenennen, wird Ihre Methode zum Accessor, und Sie können sie mit ->available direkt in Ihrem Modell ->available lesen.

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

EDIT: Da Ihr Attribut “virtual” ist, ist es nicht standardmäßig in der JSON-Darstellung Ihres Objekts enthalten.

Aber ich habe folgendes gefunden: Custom Model Accessoren werden nicht verarbeitet, wenn -> toJson () aufgerufen wird?

Um zu erzwingen, dass Ihr Attribut im Array zurückgegeben wird, fügen Sie es als Schlüssel zum Array $ attributes hinzu.

 class User extends Eloquent { protected $attributes = array( 'ZipCode' => '', ); public function getZipCodeAttribute() { return .... } } 

Ich habe es nicht getestet, aber es sollte ziemlich trivial sein, dass du es in deinem aktuellen Setup probierst.

Sie können die function setAttribute in Model verwenden, um ein benutzerdefiniertes Attribut hinzuzufügen

Ich hatte etwas Ähnliches: Ich habe ein Attributbild in meinem Modell, das den Speicherort der Datei im Speicherordner enthält. Das Bild muss base64-codiert zurückgegeben werden

 //Add extra attribute protected $attributes = ['pictureData']; //Make it available in the json response protected $appends = ['pictureData']; //implement the attribute public function getPictureDataAttribute() { $file = Storage::get($this->picture); $type = Storage::mimeType($this->picture); return "data:" . $type . ";base64," . base64_encode($file); } 

In meinem Fall hat das Erstellen einer leeren Spalte und das Einstellen des Accessors gut funktioniert. Mein Accessor füllt das Alter des Benutzers aus der dob-Spalte. toArray () function hat auch funktioniert.

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

In meinem Abonnementmodell muss ich wissen, dass das Abonnement pausiert ist oder nicht. Hier ist, wie ich es getan habe public function getIsPausedAttribute() { $isPaused = false; if (!$this->is_active) { $isPaused = true; } } public function getIsPausedAttribute() { $isPaused = false; if (!$this->is_active) { $isPaused = true; } }

Dann kann ich in der Ansichtsvorlage $subscription->is_paused , um das Ergebnis zu erhalten.

Das getIsPausedAttribute ist das Format zum getIsPausedAttribute eines benutzerdefinierten Attributs.

und verwendet is_paused , um das Attribut in Ihrer Ansicht is_paused oder zu verwenden.