Les tables d’une base de données sont souvent liées entre elles. Un article de blog a plusieurs commentaires ; une commande est reliée à l’utilisateur qui l’a passée.Eloquent facilite la définition et la manipulation de ces relations. Elles se déclarent comme des méthodes sur les modèles Eloquent.
Cette page prend User, Post, Comment, Tag comme exemples concrets.
Ces modèles et leurs tables sont supposés déjà créés.
<?phpnamespace App\Models;use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\HasOne;class User extends Model{ public function profile(): HasOne { return $this->hasOne(Profile::class); }}
Eloquent déduit la clé étrangère du nom du modèle parent : ici, il attend une colonne user_id dans la table profiles.
Accéder à la méthode comme à une propriété déclenche automatiquement une requête et retourne les données. On parle de « propriété dynamique de relation ».
<?phpnamespace App\Models;use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\HasMany;class Post extends Model{ public function comments(): HasMany { return $this->hasMany(Comment::class); }}
<?phpnamespace App\Models;use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\BelongsToMany;class Post extends Model{ public function tags(): BelongsToMany { return $this->belongsToMany(Tag::class); }}
Définissez la relation inverse dans Tag.
<?phpnamespace App\Models;use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\BelongsToMany;class Tag extends Model{ public function posts(): BelongsToMany { return $this->belongsToMany(Post::class); }}
attach ajoute des enregistrements dans la pivot ; detach en retire.
$post = Post::find(1);// Ajouter un tag$post->tags()->attach($tagId);// Retirer un tag$post->tags()->detach($tagId);// Remplacer toutes les associations actuelles$post->tags()->sync([$tagId1, $tagId2]);
sync remplace toutes les associations : seules les IDs passées restent, les autres sont supprimées de la pivot.
Accéder à une relation comme propriété déclenche une requête à chaque fois : c’est du « lazy loading ». Dans une boucle, cela provoque le problème N+1.
// 1 requête pour tous les posts$posts = Post::all();foreach ($posts as $post) { // 1 requête par post pour récupérer l'utilisateur (N requêtes) echo $post->user->name;}
Avec 100 posts, cela fait 101 requêtes. Grosse perte de performance.
// Commentaires des posts + utilisateur de chaque commentaire$posts = Post::with('comments.user')->get();
Le eager loading est essentiel pour éviter le problème N+1. Prenez l’habitude d’utiliser with() chaque fois que vous accédez à une relation dans une boucle.