Formation PUB030 : Laravel, 2019 Les relations avec Eloquent ORM

22.2 hasMany() : pour les relations 1 vers 0..* (de un à plusieurs)


Une relation de un à plusieurs indique que chaque enregistrement de la table principale (celle contenant la clé primaire) peut avoir 0, 1 ou plusieurs enregistrement dans la table secondaire (celle contenant la clé étrangère). Inversement, chaque enregistrement de la table secondaire est relié à un et exactement un enregistrement dans la table principale.

La méthode hasMany() définit une relation de un à plusieurs dans le modèle de la table principale de la relation.

Par exemple, une catégorie peut avoir plusieurs produits. Dans cet exemple, la table categories contient la clé primaire de la relation (id) et la table produits contient la clé étrangère de la relation (categorie_id). La relation hasMany() sera donc définie dans le modèle de la table categories.

Schéma hasMany vs belongsTo

La relation sera définie comme suit :

Syntaxe d'une relation dans un modèle Laravel (PHP)

/**

 * 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');

}

Dans la plupart des cas, seul le premier paramètre sera obligatoire.

Puisque hasMany() peut retrouver plus d'un enregistrement, il est d'usage de mettre le ou les mots définissant la relation au pluriel.

Ex :

Modèle Laravel (PHP)

class Categorie extends Model

{

    ...

 

    /**

     * Une catégorie peut avoir plusieurs produits.

     *

     * @return \Illuminate\Database\Eloquent\Relations\HasMany

     */

    public function produits() : HasMany

    {

        return $this->hasMany('App\Produit');

    }

    ...

}

Par défaut, la relation sera établie entre une clé primaire nommée id (dans la table actuelle) et une clé étrangère (dans l'autre table) dont le nom est au format modeleprincipal_id, c'est-à-dire que son nom est formé par le nom du modèle de la table principale suivi de _id (ex : categorie_id).

Ceci est confirmé dans la documentation officielle de Laravel :

By convention, Eloquent will take the "snake case" name of the owning model and suffix it with _id.

Si, dans l'autre table, la clé étrangère n'est pas bâtie au format modeleprincipal_id, il est possible de préciser son nom comme 2e paramètre (optionnel dans cet exemple).

Modèle Laravel (PHP)

return $this->hasMany('App\Produit', 'categorie_id');

Et si, dans la table actuelle, la clé primaire ne s'appelle pas id, il est possible de préciser son nom comme 3e paramètre (optionnel dans cet exemple).

Modèle Laravel (PHP)

return $this->hasMany('App\Produit', 'categorie_id', 'id');

Utiliser la relation

Une fois les relations bien définies, vous pouvez les utiliser pour monter vos requêtes. Laravel montera lui-même la requête SQL pour retrouver les informations.

Il y a deux façon d'utiliser une relation : en appelant la méthode qui définit la relation ou encore à l'aide d'une propriété dynamique.

Appel de la méthode

Pour retrouver les enregistrements de la table secondaire liés à un enregistrement de la table principale, il suffit d'appeler la méthode qui définit la relation.

Par exemple, puisqu'une catégorie a une relation nommée produits(), on pourra retrouver les produits de la catégorie 1 comme suit :

Contrôleur Laravel (PHP)

$categorie = Categorie::find(1);

$produits = $categorie->produits()->get();

Puisque la méthode qui définit la relation retourne un objet de type HasMany et que cette classe contient une propriété de type Illuminate\Database\Eloquent\Builder, il sera possible de continuer à monter la requête.

Par exemple, on pourra ajouter une clause ORDER BY, comme suit :

Contrôleur Laravel (PHP)

$produits = $categorie->produits()->orderBy('prix')->get();

Propriété dynamique

Laravel permet également d'accéder aux données d'une relation à l'aide d'une propriété dynamique. Il s'agit d'une propriété qui porte exactement le même nom que la méthode qui définit la relation, mais sans les parenthèses.

L'utilisation d'une propriété dynamique correspondant à une relation hasMany() donnera une collection. Chaque élément de la collection sera une instance du modèle de la table associée (ex : une collection d'objets de type Produit).

Ex :

Contrôleur Laravel (PHP)

$produits = $categorie->produits;

Si on fait un dump and die de $produits, on obtiendra bel et bien une collection des produits associés à la catégorie 1 :

Résultat à l'écran

Collection {#179 ▼

  #items: array:2 [▼

    0 => Produit {#180 ▼

      ...

      #attributes: array:11 [▼

        "id" => 1

        "categorie_id" => 1

        ...

      ]

      ...

    }

    1 => Produit {#181 ▼

      ...

      #attributes: array:11 [▼

        "id" => 8

        "categorie_id" -> 1

        ...

      ]

      ...

    }

  ]

}

Requête générée

Si vous êtes intéressés à voir la requête générée par une relation hasMany(), vous pouvez utiliser toSql().

Ex :

Contrôleur Laravel (PHP)

$produits = Categorie::find(1)->produits()->toSql();

Si on fait un dump and die de $produits, voici ce qu'on obtient :

Résultat à l'écran

"select * from `produits` where `produits`.`categorie_id` = ? and `produits`.`categorie_id` is not null"

Opération inverse

Soit une relation entre la table A et la table B. Si on définit la relation dans la table A, il est d'usage de définir la relation inverse dans la table B.

Dans le cas d'une relation hasMany(), la relation inverse est belongsTo().

Pour plus d'information

« HasMany ». Laravel API. https://laravel.com/api/5.3/Illuminate/Database/Eloquent/Relations/HasMany.html

« Eloquent: Relationships - One To Many ». Laravel. https://laravel.com/docs/master/eloquent-relationships#one-to-many

« Laravel– Model Relationship To Itself ». Sheikh Heera. http://heera.it/laravel-model-relationship#.Vu1LcvnhChd

▼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