Vazby v Eloquentu: Polymorfismus

V dnešním díle se podíváme na často nepochopené vazby, a to polymorfické (anglicky polymorphic, ale když už to máme i počeštěné, tak proč u toho nezůstat). I když se to může zdát jako něco složitého, tak si ukážeme, že ve výsledku se jedná o celkem jednoduchou záležitost. Samozřejmě si vše ukážeme na konkrétním příkladu.

Polymorfické vazby nám umožňují mít jeden model patřící k více modelům pomocí jediné vazby. Abychom si to více ujasnili, představme si situaci, kde máme model Album a  Song. Uživatelé mohou hlasovat jak pro písničku tak i pro album. Pokud použijeme polymorfické vazby, pak můžeme použít jedinou tabulku upvotes pro obě situace. To se může hodit především v případě, kdybychom ideálně potřebovali vytvořit tabulku album_upvotes a tabulku song_upvotes, abychom rozlišili hlasy. S polymorfickými vazbami nicméně nepotřebujeme vytvářet dvě tabulky. Pojďme se podívat na další příklad, kde si vše vysvětlíme detailněji.

Flag -m znamená, že se má zároveň s modelem vytvořit i migrace. Nyní si upravíme všechny tři migrace.

Migraci pro film a videohry si myslím není potřeba nějak více popisovat. To hlavní se totiž odehrává v migraci pro komentáře. Všimněte si definice sloupce commentable, kde se používá metoda morphs(). Když bychom se podívali na tuto metodu, zjistili bychom, že obsahuje toto:

Ve výsledku tedy metoda morphs() zanořuje vytvoření dalších dvou sloupců, tedy konkrétně v našem případě commentable_type a commentable_id. Jako bonus k tomu vytvoří i index. Jako název sloupců jsem zvolil commentable, protože je potřeba myslet na to, že do těchto sloupců může přijít cokoliv, kde je možné vkládat komentáře (film a videohry), tedy sloupce nejsou specifické pouze pro jeden typ, jsou různorodé (polymorfní). Spustíme si tedy migrace:

Pokud bychom si představili, že nevyužíváme polymorfickou vazbu, ale vazbu 1:n například k modelu Film, pak by klasická návratová definice vazby byla return $this->belongsTo(Film::class);. Avšak v tomto případě používáme polymorfismus, takže není možné přesně specifikovat vazbu, ke kterému modelu komentář patří. Proto namísto belongsTo použijeme morphTo a také nespecifikujeme žádný konkrétní model, protože tam může přijít cokoliv, co je "commentable".

Dále si upravíme modely Film a VideoGame, které budou mít shodné vazby:

Podobně jako v případě 1:n namísto metody hasMany, použijeme metodu morphMany. Jako první parametr uvedeme na jaký model se chceme připojovat a jako druhý parametr je potřeba přesně specifikovat název polymorfismu, jaký jsme si definovali v migraci pro tabulku comments.

Když bychom se podívali do databáze, tak kromě nového filmu a videohry bychom našli tři komentáře:

test

Jde to i obráceně, pokud bychom chtěli získat vlastníka polymorfické vazby z polymorfického modelu na základě názvu metody, která vykonává vazbu morpTo. Tedy v našem případě pokud bychom chtěli získat film, ke kterému komentář patří:

Stejný postup pak můžeme použít i u videoher.

Abychom se těmto problémům vyhnuli, můžeme využít metodu morphMap. Tato metoda dá vědět Eloquentu, aby namísto názvu třídy použil náš vlastní název. Metodu morphMap je možné zaregistrovat ve funkci boot() v AppServiceProvider nebo si můžeme vytvořit vlastní service provider:

Po změně nezapomeňte zavolat příkaz composer dumpautoload, aby se zaregistrovaly změny. Poté můžete znovu zkusit uložit nový záznam, kde již nebude celý název třídy, ale pouze alias, který jsme si definovali.

V dalším, posledním, díle si vysvětlíme opět polymorfické vazby, tentokrát však v relaci n:n, neboli many to many.

Není vám něco jasné, mám někde chybu nebo chcete přidat svůj názor na článek? Napište do komentářů pod článkem.