*/ abstract public function imageAttributes(): array; public static function bootHasImages(): void { static::saved(function (Model $model): void { foreach ($model->imageAttributes() as $attribute) { // Only on the way in or on a change: an unrelated save must // not queue work for an image nobody touched. if ($model->wasChanged($attribute) || $model->wasRecentlyCreated) { Media::for($model->getAttribute($attribute)); } } }); } /** * Relation definition shared by every image attribute. * * The join is on the stored path rather than on an id, because the file is * the identity: two records pointing at one upload share its dimensions * and its derived versions instead of each deriving them again. */ protected function imageRelation(string $attribute): BelongsTo { return $this->belongsTo(Media::class, $attribute, 'path') ->where('media.disk', (string) config('media.disk', 'public')); } }