From e53e82faf3cb7c53da8618f3c6c672a7e7b3584a Mon Sep 17 00:00:00 2001 From: Shlee Date: Sat, 29 Aug 2026 22:52:55 +0930 Subject: [PATCH] Update 2025_07_31_164635_change_hashtags_collation.php --- ...07_31_164635_change_hashtags_collation.php | 68 +++++++++++++++---- 1 file changed, 54 insertions(+), 14 deletions(-) diff --git a/database/migrations/2025_07_31_164635_change_hashtags_collation.php b/database/migrations/2025_07_31_164635_change_hashtags_collation.php index bd621ccfa..6a1f965e1 100644 --- a/database/migrations/2025_07_31_164635_change_hashtags_collation.php +++ b/database/migrations/2025_07_31_164635_change_hashtags_collation.php @@ -1,23 +1,36 @@ = 0x10000). The historic default + * of utf8mb4_unicode_ci treats all such characters as equal, which causes + * distinct hashtags (e.g. Shavian vs cuneiform of the same length) to + * collide on the unique name/slug indexes. + */ + private const TARGET_COLLATION = 'utf8mb4_unicode_520_ci'; + + /** + * The collation to restore on rollback (the previous project default). + */ + private const PREVIOUS_COLLATION = 'utf8mb4_unicode_ci'; + + /** + * Column definitions to keep intact while altering the collation. Both are + * VARCHAR(255) NOT NULL with unique indexes; MODIFY preserves the index. + */ + private const COLUMNS = ['name', 'slug']; + /** * Run the migrations. */ public function up(): void { - if (config('database.default') === 'pgsql') - return; - - Schema::table('hashtags', function (Blueprint $table) { - $table->string('name')->collation('utf8mb4_unicode_520_ci')->change(); - $table->string('slug')->collation('utf8mb4_unicode_520_ci')->change(); - }); + $this->setCollation(self::TARGET_COLLATION); } /** @@ -25,12 +38,39 @@ return new class extends Migration */ public function down(): void { - if (config('database.default') === 'pgsql') + $this->setCollation(self::PREVIOUS_COLLATION); + } + + /** + * Apply the given collation to the hashtags name and slug columns. + * + * Laravel's fluent ->change() does not reliably emit a collation-only + * change on MySQL/MariaDB, so issue an explicit MODIFY per column. + */ + private function setCollation(string $collation): void + { + if (! $this->isMysql()) { return; + } - Schema::table('hashtags', function (Blueprint $table) { - $table->string('name')->change(); - $table->string('slug')->change(); - }); + foreach (self::COLUMNS as $column) { + DB::statement( + 'ALTER TABLE `hashtags` MODIFY `'.$column.'` '. + 'VARCHAR(255) CHARACTER SET utf8mb4 COLLATE '.$collation.' NOT NULL' + ); + } + } + + /** + * This migration only applies to MySQL/MariaDB. Postgres compares + * hashtags with ILIKE (no collation quirk) and other drivers (e.g. the + * sqlite test database) do not support these collations. + * + * Note: Laravel 11+ reports MariaDB as the distinct "mariadb" driver, so + * both must be matched here. + */ + private function isMysql(): bool + { + return in_array(DB::connection()->getDriverName(), ['mysql', 'mariadb'], true); } };