web-dev-qa-db-fra.com

Inclure les relations de modèle dans la réponse json en utilisant Eloquent et Laravel 5

J'ai une configuration de modèle comme suit:

<?php namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Upload extends Model {

    /**
     * The database table used by the model.
     *
     * @var string
     */
    protected $table = 'uploads';

    /**
     * The attributes excluded from the model's JSON form.
     *
     * @var array
     */
    protected $hidden = array('id', 'user', 'created_at', 'updated_at');

    public function mime() {
        return $this->hasOne('App\Models\Mime', 'mime');
    }
}

Et lorsque JsonSerialize() est appelée, elle retourne:

{
    "serverPath": "upload/2015/06/06/21/filename.jpg",
    "filename": "filename.jpg",
    "mime": "92"
}

Ce 92 Fait référence à l'id dans une autre table (que App\Models\Mime Représente) avec une chaîne, type, qui lui est associée. Je voudrais remplacer ce 92 Par ladite chaîne.

{
    "serverPath": "upload/2015/06/06/21/filename.jpg",
    "filename": "filename.jpg",
    "mime": "image/jpeg"
}

Comment est-ce possible? J'ai essayé quelques trucs avec protected $appends Dans le modèle Upload, mais je ne suis pas sûr de bien comprendre comment utiliser/accéder aux relations à partir du modèle.

Clarification Le tableau mimes contient les colonnes id et type, tandis que le tableau uploads contient une colonne entière appelée mime qui référence un identifiant dans mimes

25
Lucas Raines

Ce n'est pas une bonne idée de nommer une relation du même nom que l'un des champs de la table. Cela provoque des problèmes (comme vous l'avez découvert) lorsque vous essayez d'accéder à la relation par rapport à l'accès au champ.

Idéalement, votre champ mime devrait être renommé en mime_id. Ceci est conforme aux conventions de Laravel et est un nom plus précis pour le champ.

Cependant, si vous n'avez pas la possibilité de modifier le nom du champ, vous devez modifier le nom de la relation.

class Upload extends Model {
    protected $hidden = array('id', 'user', 'created_at', 'updated_at');

    public function uploadMime() {
        return $this->belongsTo('App\Models\Mime', 'mime');
    }
}

Dans la classe ci-dessus, le nom de la relation est désormais uploadMime. De plus, la relation est passée de hasOne à belongsTo. Étant donné que votre table de téléchargements a la clé étrangère de la table mimes, le modèle de téléchargement appartient au modèle Mime (et le modèle Mime a des modèles de téléchargement hasOne/hasMany).

Maintenant, votre code devrait ressembler à ceci:

$data = \App\Models\Upload::with('uploadMime')->findOrFail(1);
return new JsonResponse($data);

Cela devrait vous donner quelque chose comme:

{
    "serverPath": "upload/2015/06/06/21/filename.jpg",
    "filename": "filename.jpg",
    "mime": "92",
    "uploadMime": {
        "id": 92,
        "type": "image/jpeg"
    }
}

Modification de JSON à l'aide de $appends Et des accesseurs d'attribut

Si vous souhaitez vous rapprocher de la sortie JSON que vous avez fournie dans votre question, vous pouvez créer un accesseur mimeType et l'ajouter à la propriété $appends:

class Upload extends Model {
    // hide the mime field and uploadMime data
    protected $hidden = array('id', 'user', 'created_at', 'updated_at', 'mime', 'uploadMime');

    // add the mimeType attribute to the array
    protected $appends = array('mimeType');

    // code for $this->mimeType attribute
    public function getMimeTypeAttribute($value) {
        $mimeType = null;
        if ($this->uploadMime) {
            $mimeType = $this->uploadMime->type;
        }
        return $mimeType;
    }

    public function uploadMime() {
        return $this->belongsTo('App\Models\Mime', 'mime');
    }
}

Cela devrait vous donner quelque chose comme:

{
    "serverPath": "upload/2015/06/06/21/filename.jpg",
    "filename": "filename.jpg",
    "mimeType": "image/jpeg"
}

Modification de JSON en remplaçant la fonction toArray()

Ou, si vous voulez vraiment que le JSON utilise la touche mime, vous pouvez modifier directement la méthode toArray():

class Upload extends Model {
    // hide uploadMime data, but not the mime field
    protected $hidden = array('id', 'user', 'created_at', 'updated_at', 'uploadMime');

    public function uploadMime() {
        return $this->belongsTo('App\Models\Mime', 'mime');
    }

    // override the toArray function (called by toJson)
    public function toArray() {
        // get the original array to be displayed
        $data = parent::toArray();

        // change the value of the 'mime' key
        if ($this->uploadMime) {
            $data['mime'] = $this->uploadMime->type;
        } else {
            $data['mime'] = null;
        }

        return $data;
    }
}

Cela devrait vous donner quelque chose comme:

{
    "serverPath": "upload/2015/06/06/21/filename.jpg",
    "filename": "filename.jpg",
    "mime": "image/jpeg"
}
45
patricus

D'accord, je crois que c'est ce que vous cherchez ...

Upload.php (aucune modification ici)

<?php namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Upload extends Model {

    /**
     * The database table used by the model.
     *
     * @var string
     */
    protected $table = 'uploads';

    /**
     * The attributes excluded from the model's JSON form.
     *
     * @var array
     */
    protected $hidden = array('id', 'user', 'created_at', 'updated_at');

    public function mime() {
        return $this->hasOne('App\Models\Mime', 'mime');
    }
}

Ensuite, vous avez votre modèle Mime

Mime.php

<?php namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Mime extends Model {

    /**
     * The database table used by the model.
     *
     * @var string
     */
    protected $table = 'mimes';

}

si vous faites cela pour un test, je pense que vous devriez voir le type

routes.php

Route::get('test', function() {
    $upload = \Upload::with('mime')->first();
    // return $upload //here would return it as JSON I'm pretty sure!
    return $upload->mime->type;
});

Consultez la documentation pour plus de détails sur le chargement rapide: http://laravel.com/docs/5.0/eloquent#eager-loading

1
haakym