Come tutti gli ORM che si rispettino, anche Eloquent è in grado di gestire le relazioni tra le entità in maniera facile e trasparente per l'utilizzatore. Laravel permette di implementare facilmente 6 tipologie di relazioni:
- Uno a uno.
- Uno a molti.
- Molti a molti.
- Molti a molti indiretta.
- Polimorfiche.
- Polimorfiche molti a molti.
Il modello presente in Eloquent per definire relazioni si basa sulla presenza di particolari metodi all'interno delle nostre classi. Questi metodi offrono una duplice funzionalità: invocando il metodo otterremo un oggetto programmabile (basato sui query builders di Laravel) per effettuare particolari operazioni, come ad esempio i filtri, mentre sfruttando le magic properties
di PHP possiamo recuperare il valore della relazione come se fossero property.
$song->artist->name // restituisce 'R.E.M.'
$sont->artist() // restituisce l'oggetto che rappresenta la relazione
Come abbiamo visto nell'articolo precedente, Eloquent offre un sistema di convention over configuration eccellente che, se rispettato, permette di creare strutture di dati complesse praticamente senza scrivere alcuna riga di configurazione. Ovviamente il consiglio è quello di sfruttare al massimo le convenzioni e di sovrascriverle solamente se sono presenti impedimenti esterni non aggirabili.
Relazioni uno a uno
La relazione uno a uno è la tipologia di relazione più semplice e permette di avere un particolare modello collegato univocamente ad un altro modello. Un esempio di questa relazione potrebbe essere quella tra utente e indirizzo.
Per definire tale relazione è sufficiente creare il metodo address
nella classe User
e invocare il metodo, ereditato da Model, hasOne
.
class User extends Model {
public function address() {
return $this->hasOne('App\Address');
}
}
Il metodo hasOne
accetta tre parametri di cui solo il primo obbligatorio. Esso rappresenta il nome completo del modello relazionato. Il secondo parametro, opzionale, permette di definire il nome della colonna che rappresenta la foreign key verso l'entità principale. La convenzione definisce di avere una colonna denominata user_id
all'interno della tabella addresses
che conterrà l'id dell'utente correlato. Il terzo parametro serve nel caso si volesse utilizzare una colonna diversa dall'id per creare la relazione.
Nel caso fosse necessario creare anche la relazione inversa, ovvero la possibilità di recuperare l'utente a partire dall'indirizzo, sarà necessario utilizzare il metodo privato belongsTo
riportando sempre il nome del modello associato. Gli eventuali secondo e terzo parametro rispecchiano lo stesso valore semantico del metodo hasOne
.
class Address extends Model {
public function user() {
return $this->belongsTo('App\User');
}
}
E' importante ricordarsi queste due semplici regole:
- il modello "forte" che non presenta, tra le sue colonne, riferimenti al modello "debole" necessita del metodo
hasOne
- il modello "debole" che presenta, tra le sue colonne, il riferimento al modello "forte" necessita del metodo
belongsTo
Relazioni uno a molti
Una relazione uno a molti è similare alla precedente ma permette di associare un particolare modello con una lista di altri modelli che possono avere solamente un padre. L'esempio di prima potrebbe ritornare valido, se supponiamo che un utente può avere diversi indirizzi (per esempio di spedizione, di fatturazione, di residenza...).
Per definire questa relazione creiamo il metodo addresses
invocando il metodo hasMany
.
class User extends Model {
public function addresses() {
return $this->hasMany('App\Address');
}
}
Come per il metodo hasOne
, il secondo e il terzo parametro rappresentano rispettivamente il nome della colonna dell'entità debole e la chiave primaria dell'entità forte. Impostando la relazione in questo modo possiamo quindi ottenere la lista degli indirizzi associati ad un particolare utente:
User::find(123)->addresses
Sfruttando invece l'oggetto che rappresenta la relazione è possibile effettuare filtri:
User::find(123)->addresses()->where('city', 'Milano')->get()
Per definire la relazione inversa possiamo utilizzare il metodo belongsTo
nello stesso modo analizzato per le relazioni uno a uno.
Nel prossimo capitolo verranno analizzate le restanti tipologie di relazione, più articolate rispetto a quelle già esposte.