Помимо других полезных свойств моделей, таких как $with
или $guarded
, есть в Laravel такая приятная мелочь для связанных моделей как свойство $touches
. Как гласит документация, достаточно перечислить в этом свойстве отношения с другими моделями, и при обновлении данной модели все перечисленные связанные с ней — также обновятся (обновится значение updated_at
). То есть для данного примера (из документации):
class Comment extends Model
{
/**
* All of the relationships to be touched.
*
* @var array
*/
protected $touches = ['post'];
/**
* Get the post that the comment belongs to.
*/
public function post()
{
return $this->belongsTo('App\Post');
}
}
при обновлении или создании комментария, обновится модель Post
.
А вот что в документации не написано — так это то, что помимо обновления поля updated_at
, для связанной модели выстрелит событие saved
. Причём, выстрелит только оно, а created
и updated
— нет. И это может быть полезно, например, вот зачем.
Допустим, у нас есть несколько разных моделей, которые могут быть отмечены тегами из пакета Spatie / Laravel Tags. Тогда эти модели будут состоять с тегами в полиаморных полиморфических отношениях, описываемых в трейте HasTags
вот так:
public function tags(): MorphToMany
{
return $this
->morphToMany(self::getTagClassName(), 'taggable')
->ordered();
}
Обновлять, скажем, новость, когда ей присвоен новый тег (скажем, методом syncTags()
) — вполне нормальное желание. Можно по событию обновить зависимую сущность какую-нибудь, или просто кэш почистить.
Но напрямую мы присвоить модели Tag
свойство protected $touches = ['posts'];
не можем, потому что на этой модели не реаловано обратное полиморфическое отношение. Реализуем его отдельно для моделей постов:
public function posts()
{
return $this->morphedByMany(Post::class, 'taggable', 'taggables', 'tag_id');
}
Теперь при добавлении модели Post
нового тега, сама модель будет обновлена и произойдет событие saved
.
К сожалению, в ходе экспериментов мне не удалось описать общее полиморфическое отношение с помощью morphTo()
так, чтобы не реализовывать отношение для каждой использующей теги модели. Видимо, если нужно чтобы работало свойство $touches
— придется реализовать отношение для каждого родителя, которого нужно потрогать.