$model */ public function __construct( protected string $model, protected ?int $ignoreId = null, protected string $column = 'slug', ) {} public function validate(string $attribute, mixed $value, Closure $fail): void { $translations = is_string($value) ? [app()->getLocale() => $value] : (array) $value; foreach ($translations as $locale => $slug) { if (blank($slug)) { continue; } $query = $this->model::query() ->where("{$this->column}->{$locale}", $slug); if ($this->ignoreId !== null) { $query->whereKeyNot($this->ignoreId); } // Soft-deleted rows still hold their slug, so include them — // otherwise restoring one would resurrect a duplicate. if (method_exists($this->model, 'bootSoftDeletes')) { $query->withTrashed(); } if ($query->exists()) { $fail(__('rules.slug.unique', [ 'slug' => $slug, 'locale' => (string) $locale, ])); return; } } } }