Formation PUB030 : Laravel, 2019 Les outils de Laravel

2.7 Eloquent ORM


Eloquent est le système de classes liées aux tables d'une base de données. Il s'agit d'une couche située entre votre application et votre base de données.

Les classes seront générées à l'aide de la commande php artisan make:model. Chaque classe ainsi générée est une représentation objet d'une table. Et, fait inusité, elle est déjà fonctionnelle même si elle est vide.

Il est possible de compléter les classes afin de répondre à certains besoins. Eloquent propose donc des propriétés et des méthodes pour y parvenir.

Voici quelques propriétés et méthodes Eloquent utiles :

Constante, propriété ou méthode Utilité Exemple
CREATED_AT

Nom du champ qui stocke automatiquement la date de création.

Si omis, s'appellera created_at.

Si on n'a pas de champ pour stocker automatiquement la date de création, on peut initialiser cette constante à null.

/**
 * Constante pour le nom du champ qui stocke automatiquement la date de création.
 *
 * @var string
 */
const CREATED_AT = 'datecreation';

UPDATED_AT

Nom du champ qui stocke automatiquement la date de modification.

Si omis, s'appellera updated_at.

Si on n'a pas de champ pour stocker automatiquement la date de modification, on peut initialiser cette constante à null.

/**
 * Constante pour le nom du champ qui stocke automatiquement la date de modification.
 *
 * @var string
 */
const UPDATED_AT = 'datemodification';

DELETED_AT

Nom du champ qui fait les Soft Deletes.

Si omis, s'appellera deleted_at.

/**
 * Constante pour le nom du champ qui fait les Soft Deletes. Seulement si use SoftDeletes.
 *
 * @var string
 */
const DELETED_AT = 'datesuppression';

$table

Nom de la table associée au modèle.

Si omis, le nom de la table sera obtenu en ajoutant un s au nom de la classe converti en lettre minuscules.

/**
* Table associée au modèle.
*
* @var string
*/
protected $table = 'travaux';

$primaryKey

Nom de la clé primaire de la table.

Si omis, la clé primaire s'appellera 'id'.

/**
 * Nom de la clé primaire.
 *
 * @var string
 */
protected $primaryKey = 'usager_id'; // Dans une table complément (relation de 1 à 1), la clé primaire est aussi la clé étrangère vers l'autre table.

 

$incrementing

Indique si la clé primaire doit être auto-incrémentée.

Si omis, true.

/**
 * Indique si la clé primaire doit être auto-incrémentée.
 *
 * @var boolean
 */
public $incrementing = false; // Nécessaire dans la table complément (relation de 1 à 1) puisque la clé primaire est aussi la clé étrangère vers l'autre table.

$timestamps

Indique si la table contient les champs created_at et updated_at qui seront mis à jour automatiquement.

Si omis, true.

/**
 * Indique si la table contient les champs created_at et updated_at qui seront mis à jour automatiquement.
 *
 * @var boolean
 */
public $timestamps = false;

$dateFormat

Format de stockage des champs de type date du modèle.

Détermine comment les attributs seront stockés dans la base de données de même que leur format lorsque le modèle est sérialisé dans un tableau ou au format JSON.

/**
 * Format de stockage des champs de type date du modèle.
 *
 * @var string
 */
protected $dateFormat = 'Y-m-d H:i:s';

$fillable

Liste de champs pouvant être assignés en lot (mass assignment).

Pourront être assignés à l'aide d'une instruction du genre $produit = new Produit($request->all()); ou Produit::create($array);

Tous les champs qui ne font pas partie de $fillable seront ignorés lors d'une telle opération.

Un modèle peut avoir un champ $fillable ou un champ $guarded mais pas les deux.

/**
 * Liste de champs pouvant être assignés en lot (mass assignment).
 *
 * @var array
 */
protected $fillable = [
    'nomfamille',
    'prenom',
    'telephone',
    'courriel',
    'bureau',
    'usager_id',
];

$guarded

Liste de champs ne pouvant pas être assignés en lot (mass assignment).

Devront être assignés explicitement à l'aide d'une instruction du genre :

    $objet->champ = $valeur;

    $objet->save();

Un modèle peut avoir un champ $fillable ou un champ $guarded mais pas les deux.

/**
 * Liste de champs ne pouvant pas être assignés en lot (mass assignment).
 *
 * @var array
 */
protected $guarded = [
    'administrateur',
];

$hidden Attributs à exclure lors de la sérialisation en tableau ou en JSON pour ce modèle.

/**
 * Attributs à exclure lors de la sérialisation en tableau ou en JSON pour ce modèle.
 *
 * @var array
 */
protected $hidden = [
    'champ1',
    'champ2',
    'champ3',
];

$dates

Champs devant être traités comme des instances Carbon.

Pourront être traités comme des objets à l'aide d'instructions du genre $uneInstance->champ1->toDateString();

/**
 * Champs devant être traités comme des instances Carbon.
 *
 * @var array
 */
protected $dates = [
    'champ1',
    'champ2',
    'champ3',
    'deleted_at', // seulement si use SoftDeletes
];

$casts Attributs nécessitant une conversion de type automatique.

/**
 * Attributs nécessitant une conversion de type automatique.
 *
 * @var array
 */
protected $casts = [
    'champ1' => 'boolean',
    'champ2' => 'array',
];

$with Relations à chargement hâtif automatique (eager load).

/**
 * Relations à chargement hâtif automatique (eager load).
 *
 * @var array
 */
protected $with = ['nomRelation'];

$appends Accesseur à ajouter automatiquement à la liste des champs du modèle et à sa représentation JSON (model's array form).

/**
 * Accesseur à ajouter automatiquement à la liste des champs du modèle et à sa représentation JSON (model's array form).
 *
 * @var array
 */
protected $appends = ['is_admin'];

$perPage Nombre d'enregistrements à utiliser par défaut lors de la pagination avec ce modèle (si omis : 15)

/**
 * Nombre d'enregistrements à utiliser par défaut lors de la pagination avec ce modèle.
 *
 * @var integer
 */
protected $perPage = 25;

boot() La méthode de démarrage du modèle.

/**
 * La méthode de démarrage du modèle.
 *
 * @return void
 */
protected static function boot()
{
    parent::boot();
    static::addGlobalScope(new ActifScope);
}

 

ou 

 

protected static function boot(
{
    parent::boot();
    static::addGlobalScope('actif', function (Builder $builder) {
        $builder->where('actif', true);
    });
}

$snakeAttributes Indicates whether attributes are snake cased on arrays.

/**
* Indicates whether attributes are snake cased on arrays.
*
* @var boolean
*/
public static $snakeAttributes = true;

Relations

Méthode Type de relation Exemple
hasMany() un à plusieurs (côté table principale)

/**
 * Un modeleA peut avoir plusieurs modeleB (ou "peut être associé à").
 *
 * @return \Illuminate\Database\Eloquent\Relations\HasMany
 */
public function modelesB() : HasMany
{
    return $this->hasMany('App\ModeleB', 'nom_cle_etrangere', 'nom_cle_primaire');
}

belongsTo()

un à plusieurs (côté table secondaire)

ou

un à un (côté table secondaire)

/**
 * Un modeleA appartient à un modeleB (ou "est associé à" ou "a").
 *
 * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
 */
public function modeleB() : BelongsTo
{
    return $this->belongsTo('App\ModeleB', 'nom_cle_etrangere', 'nom_cle_primaire');
}

belongsToMany() plusieurs à plusieurs

/**
 * Un modeleA peut être associé à plusieurs modeleB.
 *
 * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
 */
public function modelesB() : BelongsToMany
{
    return $this->belongsToMany('App\ModeleB', 'nom_table_pivot', 'nom_cle_etrangere_vers_table_actuelle', 'nom_cle_etrangere_vers_autre_table', 'nom_cle_primaire_dans_table_actuelle', 'nom_cle_primaire_dans_autre_table');
}

hasOne() un à un (côté table principale)

/**
 * Un modeleA peut avoir un modeleB (relation de un à un).
 *
 * @return \Illuminate\Database\Eloquent\Relations\HasOne
 */
public function modeleB() : HasOne
{
    return $this->hasOne('App\ModeleB', 'nom_cle_etrangere', 'nom_cle_primaire');
}

hasManyThrough() deux relations un à plusieurs enchaînées

/**
 * Un modeleA peut avoir plusieurs modeleB.
 *
 * @return \Illuminate\Database\Eloquent\Relations\HasManyThrough
 */
public function modelesB() : HasManyThrough
{
    return $this->hasManyThrough('App\ModeleB', 'App\ModeleTableIntermediaire', 'nom_cle_etrangere_dans_table_intermediaire_vers_table_actuelle', 'nom_cle_etrangere_dans_table_eloignee_vers_table_intermediaire', 'nom_cle_primaire_dans_table_actuelle', 'nom_cle_primaire_dans_table_intermediaire');
}

Modification de la portée des requêtes (query scopes)

Par exemple, pour un modificateur de portée permettant de n'avoir que les enregistrements actifs, on pourra retrouver tous les enregistrements actifs à l'aide de : Modele::actif();

La fonction doit s'appeler scope suivi du nom qui sera utilisé dans la requête.

On pourrait utiliser des paramètres en ajoutant un second paramètre dans la déclaration de la fonction (ex : scopeActif($query, $valeur)) et en le passant entre parenthèses lors de l'appel (ex : Modele::actif($valeur);).

Exemple

/**
 * Modificateur de portée permettant de n'avoir que les enregistrements qui sont actifs.
 *
 * @param $query
 */
public function scopeActif($query)
{
    return $query->where('actif', '=', true);
}

Accesseurs et mutateurs

La fonction doit s'appeler get ou set suivi du nom à donner à la propriété puis du mot Attribute.

Sera toujours utilisée comme s'il s'agissait d'une propriété dynamique.

Ex : pour getPrenomNomFamilleAttribute : $usager->prenomNomFamille

Exemple

/**
 * Retrouve le prénom et le nom de famille de l'usager sous la forme Prenom Nomfamille.
 *
 * @return string
 */
public function getPrenomNomFamilleAttribute()
{
    return $this->prenom . ' ' . $this->nomfamille;
}

/**
 * Retrouve le code et la description du produit sous la forme code : description.
 * Attention : avec {{ $produit->codeDescription }}, l'espace insécable sera encodé en double alors le navigateur affichera  .
 * Pour éviter ceci, ajouter l'instruction Blade::withoutDoubleEncoding(); dans la fonction boot() de la classe AppServiceProvider
 * puis supprimer le cache des vues à l'aide de php artisan view:clear.
 *
 * @return string
 */
public function getCodeDescriptionAttribute()
{
    return $this->code . ' :  ' . $this->description;
}

/**
 * Retourne une collection des compétences auxquelles ce plan-cadre est associé.
 * Simule une propriété dynamique.
 *
 * @return \Illuminate\Database\Eloquent\Collection
 */
public function getCompetencesAttribute() : \Illuminate\Database\Eloquent\Collection
{
    return $this->competences()->get();
}

/**
 * Retourne la chaîne oui ou non selon que l'usager est actif ou non.
 *
 * @return string
 */
public function getActifOuiNonAttribute()
{
    return $this->actif ? trans('general.oui') : trans('general.non');
}

/**
 * Retrouve la valeur du champ ... avec la première lettre en majuscule.
 *
 * @return string
 */
public function get...Attribute()
{
    return ucfirst(...);
}

/**
 * Assigne une date au champ datecreation.
 *
 * @param $value
 */
public function setDateCreationAttribute($value)
{
    $this->attributes['datecreation'] = Carbon::parse($value);
}

/**
 * Assigne un mot de passe crypté au champ motdepasse.
 * Le mot de passe sera donc crypté même si on fait $usager->motdepasse = 'motenclair';
 *
 * @param $motdepasse
 */
public function setMotDePasseAttribute($motdepasse)
{
    //$this->attributes['motdepasse'] = mcrypt($motdepasse);
    $this->attributes['motdepasse'] = Hash::make($motdepasse); // ou bcrypt($motdepasse); voir https://laravel.com/docs/master/hashing
}

Autres fonctions

Exemple

/**
 * Indique si le programme contient au moins un profil auquel au moins une compétence est associée
 * ou s'il est le programme par défaut d'au moins une compétence.
 *
 * @return Boolean
 */
public function hasCompetences()
{
    $retour = false;
 
    //Log::debug('*** Programme: ' . $this->titre)
    foreach($this->profils as $profil) {
        //Log::debug('Profil: ' . $profil->code . ' Nb. compétences: ' . $profil->competences()->count());
        if ($profil->competences()->count() > 0) {
            $retour = true;
            break;
        }
    }
 
    if (!$retour && $this->competencesFacultatives()->count() > 0) {
        //Log::debug('Facultative associée');
        $retour = true;
    }
 
    return $retour;
}

/**
 * Retourne un Builder des compétences auxquelles ce plan-cadre est associé.
 * Ne peut pas être fait directement par les relations puisque trop de tables séparent les plans-cadres des compétences.
 *
 * @return \Illuminate\Database\Eloquent\Builder
 */
public function competences() : \Illuminate\Database\Eloquent\Builder
{
    return PccCompetence::join('pcc_elements', 'pcc_elements.competence_id', '=', 'pcc_competences.id')
        ->join('pcc_cours_elements', 'pcc_cours_elements.element_id', '=', 'pcc_elements.id')
        ->where('pcc_cours_elements.cours_id', $this->cours_id)
        ->orderBy('pcc_competences.code', 'asc')
        ->select('pcc_competences.*')
        ->distinct();
}

/**
 * Définit le champ à utiliser dans les URL des routes.
 *
 * @return string
 */
public function getRouteKeyName()
{
    // source : https://mattstauffer.co/blog/implicit-model-binding-in-laravel-5-2
    return 'slug';
}

Pour plus d'information

« Model ». Laravel API. https://laravel.com/api/master/Illuminate/Database/Eloquent/Model.html

«  framework/src/Illuminate/Database/Eloquent/Model.php  ». GitHub. https://github.com/laravel/framework/blob/master/src/Illuminate/Database/Eloquent/Model.php

▼Publicité

Veuillez noter que le contenu de cette fiche vous est partagé à titre gracieux, au meilleur de mes connaissances et sans aucune garantie.
Merci de partager !
Soumettre