279 votes

Ajouter un attribut personnalisé à un modèle Laravel / Eloquent lors du chargement ?

J'aimerais pouvoir ajouter un attribut/propriété personnalisé à un modèle Laravel/Eloquent lorsqu'il est chargé, de manière similaire à ce que l'on peut réaliser avec RedBean's $model->open() méthode.

Par exemple, en ce moment, dans mon contrôleur j'ai :

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

Ce serait bien de pouvoir omettre la boucle et d'avoir l'attribut "disponible" déjà défini et alimenté.

J'ai essayé d'utiliser certains des événements de modèle décrits dans la documentation pour attacher cette propriété lorsque l'objet se charge, mais sans succès jusqu'à présent.

Notes :

  • Le terme "disponible" n'est pas un champ de la table sous-jacente.
  • $sessions est renvoyé sous la forme d'un objet JSON dans le cadre d'une API et, par conséquent, l'appel de quelque chose comme $session->available() dans un modèle n'est pas une option

403voto

coatesap Points 788

Le problème est causé par le fait que le Model 's toArray() ignore tous les accesseurs qui ne se rapportent pas directement à une colonne de la table sous-jacente.

Comme l'a mentionné Taylor Otwell aquí "C'est intentionnel et pour des raisons de performance." Il existe cependant un moyen simple d'y parvenir :

class EventSession extends Eloquent {

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

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

Tous les attributs énumérés dans la propriété $appends seront automatiquement inclus dans le tableau ou la forme JSON du modèle, à condition que vous ayez ajouté l'accesseur approprié.

Ancienne réponse (pour les versions de Laravel < 4.08) :

La meilleure solution que j'ai trouvée est de remplacer la fonction toArray() et soit définir explicitement l'attribut :

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

}

ou, si vous avez beaucoup d'accesseurs personnalisés, parcourez-les tous en boucle et appliquez-les :

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

}

133voto

trm42 Points 623

Le site dernière chose sur la page de la doc Laravel Eloquent est :

protected $appends = array('is_admin');

Cela peut être utilisé automatiquement pour ajouter de nouveaux accesseurs au modèle sans aucun travail supplémentaire comme la modification de méthodes telles que ::toArray() .

Il suffit de créer getFooBarAttribute(...) et ajoutez l'accesseur foo_bar à $appends le tableau.

43voto

Alexandre Danault Points 3443

Si vous renommez votre getAvailability() pour getAvailableAttribute() votre méthode devient un accesseur et vous serez en mesure de le lire en utilisant ->available directement sur votre modèle.

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

EDIT : Comme votre attribut est "virtuel", il n'est pas inclus par défaut dans la représentation JSON de votre objet.

Mais j'ai trouvé ça : Les accesseurs de modèles personnalisés ne sont pas traités lorsque ->toJson() est appelé ?

Afin d'obliger votre attribut à être renvoyé dans le tableau, ajoutez-le comme clé au tableau $attributes.

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

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

Je ne l'ai pas testé, mais il devrait être assez simple pour vous d'essayer dans votre configuration actuelle.

30voto

Patrique Points 301

J'ai eu quelque chose de similaire : J'ai un attribut image dans mon modèle, celui-ci contient l'emplacement du fichier dans le dossier Storage. L'image doit être retournée encodée en 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);
}

29voto

Bomjon Bedu Points 109

Étape 1 : Définir les attributs dans $appends
Étape 2 : Définir l'accesseur pour ces attributs.
Exemple :

<?php
...

class Movie extends Model{

    protected $appends = ['cover'];

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X