V minulém díle jsme si vysvětlili jak polymorfimus vlastně vypadá a jak ho lze využít. V tomto posledním díle seriálu o relacích budeme opět pokračovat polymorfismem, avšak tentokrát ve vazbě n:m, čili many to many. Opět si vše ukážeme na příkladě.

Podobně jako ve vazbě 1:n je i tato relace o něco složitější pro vysvětlení. Mějme například příspěvky, videa a štítky, které potřebujeme mezi sebou propojit, jelikož každý příspěvek může mít několik štítků a naopak, stejně tak je to u videa. Pokud bychom toto potřebovali vyřešit bez polymorfismu, pak bychom museli pro každou vazbu m:n vytvořit i třetí tabulku, která by vlastně sloužila jako průchozí, pivot, tabulka. Najednou tak máte dohromady pět tabulek, z toho dvě pivotní slouží pouze jako prostředník a jsou prakticky totožné, jen odkazují na jiné klíče. Díky polymorfismu můžeme počet zredukovat na čtyři, kdy namísto pivotních tabulek použijeme pouze jednu.

Migrace

```php Schema::create('posts', function (Blueprint $table) { $table->increments('id'); $table->string("name"); $table->timestamps(); }); ```
Schema::create('videos', function (Blueprint $table) {
    $table->increments('id'); 
    $table->string("name"); 
    $table->timestamps();
});
Schema::create('tags', function (Blueprint $table) {
    $table->increments('id');
    $table->string("name");
    $table->timestamps();
});

Tyto tři migrace nám vytvoří jednoduché tabulky postsvideos a tags. Jako další si vytvoříme polymorfickou tabulku, která bude sloužit pro všechny jako pivotní. Název se většinou odvozuje od schopnosti, tedy anglicky "able". V našem případě se jedná o štítky, takže tabulku pojmenujeme jako taggables:

Schema::create('taggables', function (Blueprint $table) {
    $table->integer("tag_id");
    $table->morphs('taggable'); // prida sloupce unsigned integer taggable_id a string taggable_type
);

Eloquent modely

Definování relací v modelech bude vypadat velmi podobně jako v předešlém díle. Tentokrát však využijeme metody `morphToMany()`a `morphedByMany()`: ```php namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model { /**

  • Pro ziskani vsech stitku prispevku */ public function tags() { return $this->morphToMany(Tag::class, 'taggable'); } }
namespace App;

use Illuminate\Database\Eloquent\Model;

class Video extends Model
{
    /**
     * Pro ziskani vsech stitku pro video
     */
    public function tags()
    {
        return $this->morphToMany(Tag::class, 'taggable');
    }
}
namespace App;

use Illuminate\Database\Eloquent\Model;

class Tag extends Model
{
    /**
     * Pro ziskani vsech prispevku ktere jsou prirazeny k danemu stitku
     */
    public function posts()
    {
        return $this->morphedByMany(Post::class, 'taggable');
    }

    /**
     * Pro ziskani vsech videi ktere jsou prirazeny k danemu stitku
     */
    public function videos()
    {
        return $this->morphedByMany(Video::class, 'taggable');
    }
}

Uložení záznamu

Pro vytvoření můžeme použít více způsobů: ```php // pro ulozeni stitku pro dany zaznam $post = Post::find(1);

$tag = new Tag; $tag->name = "someTag";

$post->tags()->save($tag);


```php
// pro ulozeni stitku pro dane video
$video = Video::find(1);    

$tag = new Tag;
$tag->name = "someTag";

$video->tags()->save($tag);

Více štítků můžeme uložit i naráz:

$post = Post::find(1);  

$tag1 = new Tag;
$tag1->name = "someTag";

$tag2 = new Tag;
$tag2->name = "anotherTag";

$post->tags()->saveMany([$tag1, $tag2]);

Stejně tak je můžeme i přidat pomocí metody attach(), kdy nekontrolujeme, jestli daná vazba již existuje:

$video = Video::find(1);    

$tag1 = Tag::find(3);
$tag2 = Tag::find(4);

$video->tags()->attach([$tag1->id, $tag2->id]);

Nebo můžeme využít metody sync() pro smazání všech vazeb modelu a sesynchronizovat ho znovu s novými záznamy:

$post = Post::find(1);  

$tag1 = Tag::find(3);
$tag2 = Tag::find(4);

$post->tags()->sync([$tag1->id, $tag2->id]);

Získávání záznamu

Získat záznamy je velmi jednoduché: ```php $post = Post::find(1);

$tags = $post->tags;


```php
$tag = Tag::find(1);    

$videos = $tag->videos;

Závěr

Tento díl jsem vzal trochu rychleji a stručněji, protože to nejdůležitější bylo již popsáno v předešlém díle. Polymorfismus pro n:m má velmi podobnou definici zápisu jako při vazbě 1:n. Je potřeba jen mít správně definované vazby v modelech. V případech, kdy potřebujete pivotní tabulku použít pro více vazeb a zároveň se struktura pivot tabulky nemění a mění se pouze cizí klíče, se může polymorfismus velmi hodit, především pak pokud nastane situace, kdy potřebujete přidat další tabulku s pivotem. V tomto případě pokud bychom chtěli přidat ještě kategorie, které by také měli vlastní štítky, tak stačí v definici modelu přidat další vazbu a nepotřebujeme vytvářet novou pivot tabulku, ale využijeme již stávající `taggables`.

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.