Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Eloquent, relazioni uno a molti, molti a molti e polimorfiche

Come rappresentare le relazioni uno a molti indirette, molti a molti e relazioni polimorfiche tra tabelle
Come rappresentare le relazioni uno a molti indirette, molti a molti e relazioni polimorfiche tra tabelle
Link copiato negli appunti

Relazioni molti a molti

Le precedenti relazioni erano abbastanza semplici, rappresentavano in fondo la stessa tipologia di relazione e non introducevano strutture dati relazionali particolari, se non la necessità di avere una colonna in più nel database. Le relazioni molti a molti sono più complesse e necessitano la presenza di tre tabelle: due per rappresentare le entità e una, chiamata tabella pivot, per gestire le relazioni. Il nome di questa terza tabella è derivato dai nomi della altre due unendo i nomi singolari di esse, in ordine alfabetico, separati da un underscore.

Un'implementazione di una classica wishlist presenterà quindi la tabella users, la tabella products e la tabella product_user. Quest'ultima dovrà contenere la colonna user_id e la colonna product_id.

Per definire la relazione basta utilizzare il metodo belongsToMany. La relazione non ha modelli "deboli" e "forti", quindi il metodo potrà essere utilizzato da entrambe le entità.

class User extends Model {
    public function products() {
        return $this->belongsToMany('App\Product');
    }
}
[...]
class Product extends Model {
    public function users() {
        return $this->belongsToMany('App\User');
    }
}

Eventuali parametri addizionali del metodo belongsToMany, utili solo nel caso non si rispettino le convenzioni, sono: nome della tabella pivot, nome della colonna che contiene l'id della prima tabella e nome della colonna della seconda tabella.

Alcuni tipi di relazioni molti a molti necessitano la presenza di eventuali altre colonne all'interno della tabella pivot. Nel nostro piccolo esempio della wishlist potrebbe essere la data di inserimento del prodotto. Laravel permette di accedere ai dati addizionali della tabella pivot tramite una particolare property pivot a patto che questi dati siano evidenziati nella configurazione della relazione.

class User extends Model {
    public function products() {
        return $this->belongsToMany('App\Product')->withPivot('extraField');
    }
}
[...]
$products = User::find(1)->products();
$products[0]->pivot->extraField;

Relazioni uno a molti indiretta

Questo tipo di relazione rappresenta una scorciatoia nel caso di struttura complessa di entità relazionate tra loro secondo un modello uno a molti. Supponendo una struttura dati che modella le entità Artist, Album e Song, dove Artist e Album sono relazionati uno a molti così come Album e Song, tramite una relazione uno a molti indiretta è possibile risalire alle canzoni di un artista, passando, in maniera totalmente trasparente, dalla tabella degli album.

Per definire questo tipo di relazione usiamo il metodo hasManyThrough.

class Artist extends Model {
    public function songs() {
        return $this->hasManyThrough('App\Song', 'App\Album');
    }
}

Le convenzioni utilizzate da Laravel sono quelle già viste in precedenza. Nel caso fosse necessario personalizzare qualcosa, è possibile utilizzare i parametri addizionali del metodo hasManyThrough.

Relazioni polimorfiche

Le relazioni polimorfiche sono una delle funzionalità di Eloquent più particolari e spesso non si trovano in altri ORM. Immaginiamo un modello dati che permetta di avere relazioni uno a molti ma con oggetti di natura diversa e un'unica entità correlata. Pensiamo per esempio alle entità Album, Artist e Photo e in particolare alla possibilità di avere foto sia legate all'album (per esempio la copertina) che all'artista.

Ovviamente questo modello è implementabile con una doppia relazione uno a molti, ma questo sarebbe limitante nel caso si voglia considerare integra l'entità Photo. Le relazioni polimorfiche permettono appunto di avere un unica tabella Photo che è in grado di gestire relazioni con Album e Artist.

Le tabelle Artists e Albums non presentano nulla di particolare, tutto è implementato nella tabella Photos. Oltre alle colonne di business, sarà necessario avere due colonne dedicate alla relazione, una contenente l'id dell'entità relazionata e uno contenente il tipo (che in questo modello potrà essere album o artist). Queste due colonne devono condividere un prefisso che rappresenta il nome astratto delle entità relazionate, per esempio coverable.

Riassumendo quindi una struttura database per questo tipo di relazione potrebbe essere:

// tabella artists
id, name
// tabella albums
id, name, year, artist_id
// tabella photos
id, url, coverable_id, coverable_type

La definizione della relazione invece:

class Photo extends Model {
    public function coverable() {
        return $this->morphTo();
    }
}
class Artist extends Model {
    public function photos() {
        return $this->morphMany('App\Photo', 'coverable');
    }
}
class Album extends Model {
    public function photos() {
        return $this->morphMany('App\Photo', 'coverable');
    }
}

Grazie a questi metodi abbiamo creato una relazione bidirezionale. Sarà quindi possibile recuperare le foto di un album (o artista) in questo modo:

Album::find(1)->photos

e l'entità relazionata a partire dalla photo:

Photo::find(1)->coverable

Relazioni polimorfiche molti a molti

L'ultima tipologia di relazione configurabile in Laravel è una versione modificata delle relazioni polimorfiche che però include la possibilità di avere una relazione molti a molti tra l'entità morph e le altre. Riprendendo il nostro contesto musicale, possiamo creare una relazione di questo tipo partendo da Artists, Album, Songs e Genre e supponendo che un artista possa avere un genere principale, ma possa aver inciso album o canzoni di un diverso genere. In questo caso il genere è l'oggetto morph che si relaziona a ben 3 diverse entità .

La struttura dati sarà simile a quella precedente se non per il fatto che viene creata una tabella pivot per gestire la relazione molti a molti:

// tabella artists
id, name
// tabella albums
id, name, year, artist_id
// tabella songs
id, name, album_id
// tabella genre
id, genre
// tabella genreable
id, genreable_id, genreable_type

Per definire la relazione all'interno delle nostre classi PHP utilizziamo i metodi morphToMany e morphByMany

class Artist {
    public function genres() {
        return $this->morphToMany('App\Genre', 'genreable');
    }
}
class Album {
    public function genres() {
        return $this->morphToMany('App\Genre', 'genreable');
    }
}
class Song {
    public function genres() {
        return $this->morphToMany('App\Genre', 'genreable');
    }
}
class Genre {
    public function artists() {
        return $this->morphedByMany('App\Artist', 'genreable');
    }
    public function albums() {
        return $this->morphedByMany('App\Album', 'genreable');
    }
    public function songs() {
        return $this->morphedByMany('App\Song', 'genreable');
    }
}

Ti consigliamo anche