option('dry-run'); $chunkSize = max(1, (int) $this->option('chunk')); $onlyMismatched = (bool) $this->option('only-mismatched'); if (! $dryRun) { $this->ensureSlugIsNotUnique(); } $processed = 0; $updated = 0; DB::table('artworks') ->select(['id', 'title', 'slug']) ->orderBy('id') ->chunkById($chunkSize, function ($artworks) use ($dryRun, $onlyMismatched, &$processed, &$updated): void { foreach ($artworks as $artwork) { $processed++; $normalizedSlug = Str::limit(Str::slug((string) ($artwork->title ?? '')) ?: 'artwork', 160, ''); $currentSlug = (string) ($artwork->slug ?? ''); if ($onlyMismatched && $currentSlug === $normalizedSlug) { continue; } if ($currentSlug === $normalizedSlug) { continue; } if ($dryRun) { $this->line(sprintf('#%d %s => %s', $artwork->id, $currentSlug !== '' ? $currentSlug : '[empty]', $normalizedSlug)); $updated++; continue; } DB::table('artworks') ->where('id', $artwork->id) ->update(['slug' => $normalizedSlug]); $updated++; } }); if ($dryRun) { $this->info(sprintf('Dry run complete. Checked %d artworks, %d would be updated.', $processed, $updated)); return self::SUCCESS; } $this->info(sprintf('Normalization complete. Checked %d artworks, updated %d.', $processed, $updated)); return self::SUCCESS; } private function ensureSlugIsNotUnique(): void { $driver = DB::getDriverName(); if ($driver === 'mysql') { $indexes = collect(DB::select("SHOW INDEX FROM artworks WHERE Column_name = 'slug'")); $indexes ->filter(fn ($index) => (int) ($index->Non_unique ?? 1) === 0) ->pluck('Key_name') ->filter() ->unique() ->each(function ($indexName): void { $this->warn(sprintf('Dropping unique slug index %s before normalization.', $indexName)); DB::statement(sprintf('ALTER TABLE artworks DROP INDEX `%s`', str_replace('`', '``', (string) $indexName))); }); $hasNonUniqueSlugIndex = $indexes->contains(fn ($index) => (string) ($index->Key_name ?? '') === 'artworks_slug_index' || (int) ($index->Non_unique ?? 0) === 1); if (! $hasNonUniqueSlugIndex) { DB::statement('CREATE INDEX artworks_slug_index ON artworks (slug)'); } return; } if ($driver === 'sqlite') { $indexes = collect(DB::select("PRAGMA index_list('artworks')")); $indexes ->filter(function ($index): bool { if ((int) ($index->unique ?? 0) !== 1) { return false; } $columns = collect(DB::select(sprintf("PRAGMA index_info('%s')", str_replace("'", "''", (string) $index->name)))) ->pluck('name') ->map(fn ($name) => (string) $name); return $columns->contains('slug'); }) ->pluck('name') ->each(fn ($indexName) => DB::statement(sprintf('DROP INDEX IF EXISTS "%s"', str_replace('"', '""', (string) $indexName)))); DB::statement('CREATE INDEX IF NOT EXISTS artworks_slug_index ON artworks (slug)'); } } }