📚
【Laravel 11】多対多のポリモーフィックでのattach, syncメソッドでイベントを発火させる
Laravelで多対多にすることってよくあると思います。
ドキュメントとほぼ同じですが以下のような構造。
今回はポリモーフィックでの多対多です。(普通の多対多でも手順はほぼ同じです)
posts
id - integer
name - string
videos
id - integer
name - string
tags
id - integer
name - string
taggables
tag_id - integer
taggable_id - integer
taggable_type - string
order - int #creating時にこれを更新したい
この posts
や videos
が作成された時点で、 taggable#order
を更新したいとします。
その際に検討するのがEventsです。
class Taggable extends Model
{
protected static function booted(): void
{
static::creating(function (User $user) {
// orderを更新する処理
});
}
}
しかし、残念ながらこれは発火しません。
$post = Post::factory()->create();
$video = Video::factory()->create();
$post->attach($video) // Eventは発火しない
中間テーブルのEventを発火させるにはDefining Custom Intermediate Table Modelsを定義する必要があります。
Custom many-to-many pivot models should extend the Illuminate\Database\Eloquent\Relations\Pivot class while custom polymorphic many-to-many pivot models should extend the Illuminate\Database\Eloquent\Relations\MorphPivot class.
ドキュメントでは以下のように使い分けて中間テーブルのクラスに継承させろと書いてあります。
普通の多対多の時 | Illuminate\Database\Eloquent\Relations\Pivot |
ポリモーフィックでの多対多の時 | Illuminate\Database\Eloquent\Relations\MorphPivot |
use Illuminate\Database\Eloquent\Relations\MorphPivot;
// MorphPivotを継承させる
class Taggable extends MorphPivot
{
// 「pivotは本来単数系で、ポリモーフィックは複数形」がLaravelのデフォルト定義なのだが
// 競合してエラーになるのでテーブル名を明示している。
protected $table = 'taggables';
protected static function booted()
{
static::creating(function ($taggable) {
// orderを更新する処理
});
}
}
class Tag extends Model
{
public function videos():
{
// using(Taggable::class)->withPivot('order')を追加
return $this->morphedByMany(Video::class, 'taggable')->using(Taggable::class)->withPivot('order');
}
}
以上です。
Discussion