Студия разработки сайтов и приложений

Netspark.ru

Как потрогать родительскую модель в Laravel

Помимо других полезных свойств моделей, таких как $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 — придется реализовать отношение для каждого родителя, которого нужно потрогать.

Комментарии