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

# Introduzione alle relazioni Eloquent

> Come definire relazioni tra tabelle (1-a-1, 1-a-molti, molti-a-molti) con Eloquent e recuperare efficacemente i dati correlati.

## Cosa sono le relazioni

Le tabelle di un database sono spesso correlate tra loro. Ad esempio, un post di blog ha molti commenti, oppure un ordine è collegato all'utente che l'ha effettuato.

Eloquent offre un modo semplice per definire e manipolare queste relazioni tra tabelle. Le relazioni si definiscono come metodi sui modelli Eloquent.

<Info>
  In questa pagina usiamo come esempio modelli concreti come `User`, `Post`, `Comment` e `Tag`.
  Diamo per scontato che modelli e tabelle siano già stati creati.
</Info>

Le principali relazioni supportate da Eloquent sono le seguenti.

| Relazione       | Descrizione                                         |
| --------------- | --------------------------------------------------- |
| `hasOne`        | 1-a-1 (il genitore ha un figlio)                    |
| `belongsTo`     | Inverso di 1-a-1 (il figlio appartiene al genitore) |
| `hasMany`       | 1-a-molti (il genitore ha più figli)                |
| `belongsToMany` | Molti-a-molti (usa una tabella 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 (tabella pivot post_tag)"
```

## hasOne (1-a-1)

`hasOne` rappresenta una relazione in cui un modello possiede esattamente un altro modello. Ad esempio, un `User` ha un `Profile`.

### Definizione della relazione

Nel modello `User` definisci il metodo `profile`.

```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 deduce automaticamente la chiave esterna dal nome del modello padre. Assume che la tabella `profiles` abbia una colonna `user_id`.

### Recupero dei dati correlati

La relazione definita è accessibile come una proprietà.

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

<Tip>
  Chiamando il metodo di relazione come una proprietà, Eloquent emette automaticamente la query e restituisce i dati correlati. Questa è la "dynamic relationship property".
</Tip>

## belongsTo (inverso di 1-a-1)

`belongsTo` è l'inverso di `hasOne` e va definito sul modello che possiede la chiave esterna. Rappresenta la relazione "un `Profile` appartiene a un `User`".

### Definizione della relazione

```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 usa come chiave esterna la colonna con nome-del-metodo + `_id` (in questo caso `user_id`).

### Recupero dei dati correlati

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

echo $user->name;
```

## hasMany (1-a-molti)

`hasMany` è la relazione più usata: un modello padre possiede più figli. Ad esempio, un `Post` ha più `Comment`.

### Definizione della relazione

```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 assume che la tabella `comments` abbia una colonna `post_id`.

### Recupero dei dati correlati

Una relazione `hasMany` restituisce una collection.

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

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

Puoi anche aggiungere condizioni alla query.

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

### Relazione inversa (belongsTo)

Per riferirsi al post da un commento, definisci `belongsTo` sul modello `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 (molti-a-molti)

La relazione molti-a-molti si usa quando entrambi i modelli hanno molteplici associazioni tra loro. Ad esempio, un `Post` ha più `Tag` e un `Tag` appartiene a più `Post`.

### Struttura delle tabelle

Il molti-a-molti richiede una tabella pivot. Per `Post` e `Tag` prepara la tabella pivot `post_tag`.

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

tags
    id - integer
    name - string

post_tag
    post_id - integer
    tag_id - integer
```

<Info>
  Il nome della tabella pivot viene dedotto automaticamente concatenando in ordine alfabetico i nomi dei due modelli correlati (`post` + `tag` → `post_tag`).
</Info>

### Definizione della relazione

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

Definendola in modo analogo anche sul lato `Tag` puoi navigare la relazione anche nel verso opposto.

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

### Recupero dei dati correlati

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

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

### Aggiungere e rimuovere associazioni

Con `attach` aggiungi un record nella tabella pivot, con `detach` lo rimuovi.

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

// Aggiungi un tag
$post->tags()->attach($tagId);

// Rimuovi un tag
$post->tags()->detach($tagId);

// Sostituisce completamente le associazioni correnti
$post->tags()->sync([$tagId1, $tagId2]);
```

<Tip>
  Con `sync` i record della tabella pivot che non corrispondono agli ID passati vengono eliminati automaticamente, lasciando solo quelli indicati.
</Tip>

## Eager loading

### Cos'è il problema N+1

Accedendo a una relazione come proprietà, Eloquent emette una query ogni volta. Questo è il "lazy loading". Se accedi alla relazione in un ciclo, incorri nel problema N+1.

```php theme={null}
// Una query per recuperare tutti i post
$posts = Post::all();

foreach ($posts as $post) {
    // Per ogni post viene emessa una query per ottenere l'utente (N volte)
    echo $post->user->name;
}
```

Con 100 post fai 101 query in totale. Ha un forte impatto sulle prestazioni.

### Eager loading con with()

Con il metodo `with()` recuperi in blocco i dati correlati. Le query si riducono a due.

```php theme={null}
// Recupera post e utenti in due query
$posts = Post::with('user')->get();

foreach ($posts as $post) {
    // Non vengono emesse query aggiuntive
    echo $post->user->name;
}
```

L'SQL eseguito è solo questo:

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

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

### Eager load di più relazioni contemporaneamente

Puoi indicare più relazioni con un array.

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

### Eager load annidato

Con la notazione dot puoi fare eager load anche di relazioni annidate.

```php theme={null}
// Eager load dei commenti dei post e degli utenti di ciascun commento
$posts = Post::with('comments.user')->get();
```

<Warning>
  L'eager loading è fondamentale per prevenire il problema N+1. Prendi l'abitudine di usare `with()` ogni volta che accedi a relazioni all'interno di un ciclo.
</Warning>

## Prossimi passi

<Card title="Introduzione a Eloquent" icon="database" href="/it/eloquent">
  Ripassa le operazioni CRUD di base di Eloquent.
</Card>


## Related topics

- [Eloquent API Resource](/it/eloquent-resources.md)
- [Serializzazione Eloquent](/it/eloquent-serialization.md)
- [Introduzione a Eloquent](/it/eloquent.md)
- [Introduzione all'autenticazione](/it/authentication.md)
- [Introduzione al testing](/it/testing.md)
