Vazby v Eloquentu: Polymorfismus many to many
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.
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 posts
, videos
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
);
use Illuminate\Database\Eloquent\Model;
class Post extends Model { /** * Pro ziskani vsech stitku prispevku */ public function tags() { return $this->morphToMany(Tag::class, 'taggable'); } }
```php
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');
}
}
$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]);
$tags = $post->tags;
```php
$tag = Tag::find(1);
$videos = $tag->videos;
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.