web-dev-qa-db-fra.com

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

J'aimerais pouvoir ajouter un attribut/une propriété personnalisée à un modèle Laravel/Eloquent lors de son chargement, comme cela pourrait être réalisé avec la méthode RedBean's$model->open().

Par exemple, pour le 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 rempli.

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

Remarques:

  • 'disponible' n'est pas un champ de la table sous-jacente.
  • $sessions est renvoyé en tant qu'objet JSON en tant qu'élément d'une API. Par conséquent, appeler quelque chose comme $session->available() dans un modèle n'est pas une option.
168
coatesap

Le problème est dû au fait que la méthode toArray() de la Model ignore tous les accesseurs qui ne sont pas directement liés à une colonne de la table sous-jacente.

Comme Taylor Otwell a mentionné ici , "C’est intentionnel et pour des raisons de performance." Cependant, il existe 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 répertorié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 consiste à remplacer la méthode toArray() et à 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 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);    
    }

}
273
coatesap

Le dernière chose sur la page de la documentation de 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 tel que la modification de méthodes telles que ::toArray()

Créez simplement l'accesseur getFooBarAttribute(...) et ajoutez le tableau foo_bar au tableau $appends

107
trm42

Si vous renommez votre méthode getAvailability() en getAvailableAttribute(), votre méthode devient un accessor et vous pourrez le lire à l'aide de ->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é ceci: Les accesseurs de modèles personnalisés ne sont pas traités quand -> toJson () appelé?

Afin de forcer le renvoi de votre attribut dans le tableau, ajoutez-le en tant que clé au tableau $ attributs.

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

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

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

32
Alexandre Danault

J'avais quelque chose de similaire: J'ai une image d'attribut dans mon modèle, elle contient l'emplacement du fichier dans le dossier de stockage . L'image doit être retournée codée en base64

//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);
}
12
Patrique

vous pouvez utiliser la fonction setAttribute dans Model pour ajouter un attribut personnalisé

12
jianfeng

Supposons que vous avez 2 colonnes nommées first_name et last_name dans votre table d'utilisateurs et que vous voulez récupérer le nom complet. vous pouvez réaliser avec le code suivant:

class User extends Eloquent {


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

maintenant vous pouvez obtenir le nom complet en tant que:

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

dans mon cas, créer une colonne vide et paramétrer son accesseur a bien fonctionné . mon accesseur en remplissant l'âge de l'utilisateur à partir de la colonne dob. La fonction toArray () a également fonctionné.

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

Dans mon modèle d’abonnement, j’ai besoin de savoir si l’abonnement est en pause ou non. public function getIsPausedAttribute() { $isPaused = false; if (!$this->is_active) { $isPaused = true; } }

ensuite, dans le modèle de vue, je peux utiliser $subscription->is_paused pour obtenir le résultat. 

getIsPausedAttribute est le format pour définir un attribut personnalisé,

et utilise is_paused pour obtenir ou utiliser l'attribut dans votre vue. 

0
li bing zhao