> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Introduction aux relations Eloquent

> Comment définir les relations entre tables (1-1, 1-N, N-N) avec Eloquent et récupérer efficacement les données associées.

## Qu'est-ce qu'une relation

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.

<Info>
  Cette page prend `User`, `Post`, `Comment`, `Tag` comme exemples concrets.
  Ces modèles et leurs tables sont supposés déjà créés.
</Info>

Principales relations Eloquent :

| Relation        | Description                                    |
| --------------- | ---------------------------------------------- |
| `hasOne`        | 1-1 (le parent a un seul enfant)               |
| `belongsTo`     | Inverse de 1-1 (l'enfant appartient au parent) |
| `hasMany`       | 1-N (le parent a plusieurs enfants)            |
| `belongsToMany` | N-N (via une table pivot)                      |

```mermaid theme={null}
erDiagram
    users ||--o| profiles : "hasOne / belongsTo (profiles.user_id)"
    posts ||--o{ comments : "hasMany / belongsTo (comments.post_id)"
    posts }o--o{ tags : "belongsToMany (table pivot post_tag)"
```

## hasOne (1-1)

`hasOne` : le modèle possède un seul autre modèle. Par exemple, `User` a un `Profile`.

### Définir la relation

Ajoutez `profile` au modèle `User`.

```php theme={null}
<?php

namespace 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`.

### Récupérer la relation

Accédez à la relation comme une propriété.

```php theme={null}
$user = User::find(1);
$profile = $user->profile;
```

<Tip>
  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 ».
</Tip>

## belongsTo (inverse de 1-1)

`belongsTo` est l'inverse : à définir sur le modèle qui contient la clé étrangère. `Profile` appartient à `User`.

### Définir la relation

```php theme={null}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Profile extends Model
{
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }
}
```

Eloquent utilise le nom de la méthode + `_id` comme clé étrangère (`user_id`).

### Récupérer la relation

```php theme={null}
$profile = Profile::find(1);
$user = $profile->user;

echo $user->name;
```

## hasMany (1-N)

`hasMany` est la relation la plus courante : un parent, plusieurs enfants. Par exemple, un `Post` a plusieurs `Comment`.

### Définir la relation

```php theme={null}
<?php

namespace 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);
    }
}
```

Eloquent attend une colonne `post_id` sur `comments`.

### Récupérer la relation

`hasMany` retourne une Collection.

```php theme={null}
$post = Post::find(1);

foreach ($post->comments as $comment) {
    echo $comment->body;
}
```

Vous pouvez ajouter des conditions.

```php theme={null}
$recentComments = Post::find(1)
    ->comments()
    ->latest()
    ->take(5)
    ->get();
```

### Relation inverse (belongsTo)

Pour remonter d'un commentaire au post, définissez `belongsTo` dans `Comment`.

```php theme={null}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Comment extends Model
{
    public function post(): BelongsTo
    {
        return $this->belongsTo(Post::class);
    }
}
```

```php theme={null}
$comment = Comment::find(1);
echo $comment->post->title;
```

## belongsToMany (N-N)

Une relation N-N s'utilise quand chaque côté peut avoir plusieurs relations. Par exemple, `Post` a plusieurs `Tag` et `Tag` appartient à plusieurs `Post`.

### Structure des tables

Une table pivot est nécessaire. Pour `Post` et `Tag`, créez `post_tag`.

```text theme={null}
posts
    id - integer
    title - string

tags
    id - integer
    name - string

post_tag
    post_id - integer
    tag_id - integer
```

<Info>
  Eloquent déduit le nom de la table pivot en combinant les deux noms de modèles par ordre alphabétique (`post` + `tag` → `post_tag`).
</Info>

### Définir la relation

```php theme={null}
<?php

namespace 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`.

```php theme={null}
<?php

namespace 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);
    }
}
```

### Récupérer la relation

```php theme={null}
$post = Post::find(1);

foreach ($post->tags as $tag) {
    echo $tag->name;
}
```

### Ajouter / retirer

`attach` ajoute des enregistrements dans la pivot ; `detach` en retire.

```php theme={null}
$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]);
```

<Tip>
  `sync` remplace toutes les associations : seules les IDs passées restent, les autres sont supprimées de la pivot.
</Tip>

## Eager loading

### Problème N+1

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.

```php theme={null}
// 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.

### Eager loading avec `with()`

`with()` charge la relation en masse : seulement 2 requêtes au total.

```php theme={null}
// Posts + utilisateurs en 2 requêtes
$posts = Post::with('user')->get();

foreach ($posts as $post) {
    // Aucune requête supplémentaire
    echo $post->user->name;
}
```

Les 2 SQL exécutés :

```sql theme={null}
select * from posts

select * from users where id in (1, 2, 3, ...)
```

### Charger plusieurs relations

Passez un tableau à `with()`.

```php theme={null}
$posts = Post::with(['user', 'comments', 'tags'])->get();
```

### Eager loading imbriqué

La notation point permet d'aller plus loin.

```php theme={null}
// Commentaires des posts + utilisateur de chaque commentaire
$posts = Post::with('comments.user')->get();
```

<Warning>
  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.
</Warning>

## Prochaines étapes

<Card title="Introduction à Eloquent" icon="database" href="/fr/eloquent">
  Revenez sur les opérations CRUD de base d'Eloquent.
</Card>


## Related topics

- [Eloquent API Resources](/fr/eloquent-resources.md)
- [Introduction aux tests](/fr/testing.md)
- [Sérialisation Eloquent](/fr/eloquent-serialization.md)
- [Introduction à l'authentification](/fr/authentication.md)
- [Factories Eloquent](/fr/eloquent-factories.md)
