Update 2025_07_31_164635_change_hashtags_collation.php

pull/6098/head
Shlee 4 weeks ago committed by GitHub
parent 53e5692cfb
commit e53e82faf3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -1,23 +1,36 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
/**
* The collation that correctly differentiates characters outside the
* Basic Multilingual Plane (codepoints >= 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);
}
};

Loading…
Cancel
Save