Изменение кодировки таблиц. Решение для кодеров

mbaev 08.12.2017, 13:07

После установки Drupal версии 7, на странице статуса можно встретить надпись
image

Database 4 byte UTF-8 support
Enabled, but database tables need conversion
Please convert all database tables to utf8mb4 prior to enabling it in settings.php. See the documentation on adding 4 byte UTF-8 support for more information.

Здесь, как известно, речь идёт о том, что неплохо было бы вам сменить кодировку своей базы таким образом, чтобы она могла корректно сохранять эмоджи, китайские иероглифы, математические и другие спец. символы.

Перейдя по ссылке, можно увидеть действия. необходимые для подготовки базы и сайта к изменению кодировки, а именно:

  1. Удостовериться, что в конфигах Mysql есть записи
    1. [mysqld]
    2. innodb_large_prefix=true
    3. innodb_file_format=barracuda
    4. innodb_file_per_table=true
  2. Убедиться, что ваш MySQL драйвер поддерживает кодировку utf8mb4 (libmysqlclient 5.5.3 и выше, также как mysqlnd 5.0.9 и выше)
  3. Проверить, что MySQL сервер поддерживает кодировку utf8mb4 (5.5.3 и выше) .

Если всё в порядке, тогда можно подготовить сайт. Для этого нужно в вашем settings.php, в массиве настроек коннекции к базе, добавить ключи collation  и charset. Результат должен выглядеть примерно так:

  1. $databases['default']['default'] = array(
  2.   'driver' => 'mysql',
  3.   'database' => 'databasename',
  4.   'username' => 'username',
  5.   'password' => 'password',
  6.   'host' => 'localhost',
  7.   'charset' => 'utf8mb4',
  8.   'collation' => 'utf8mb4_general_ci',
  9. );

Уже после завершения этого этапа на странице статуса сайта можно увидеть примерно следующую картину:
drupal-db-collation

На этом прелюдия заканчивается и для активной фазы изменения кодировки базы и таблиц начинаются переводы стрелок:

  1. У нас есть возможность нажать на каждую из ссылок на скриншоте выше, по которой можно будет подтвердить свои намерения о изменении кодировки, кликнув специальную кнопку... 
  2. Нам говорят, поставьте модуль, который добавит drush команду, которая позволит изменить кодировку.
  3. Нашлись добрые люди, которые написали модуль и обернули это дело в функцию. Но сам модуль тоже ничего не делает.

Мне всё это не нравится, т.к. реально вся эта тема укладывается в 4 строчки.

  1. db_query("ALTER DATABASE my_db CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci");
  2. foreach (db_query('show tables')->fetchCol() as $table) {
  3.   db_query("ALTER TABLE $table CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci");
  4. }

Но конечно же, я добавил вкусности и няшности, для удобства и безопасности выполнения процедуры. Создаём свой hook_update_N и запускаем

  1. /**
  2.  * Implements hook_update_n().
  3.  */
  4. function MYMODULE_update_N() {
  5.   $connection = Database::getConnection();
  6.   $database_info = $connection->getConnectionOptions();
  7.   $database = @$database_info['database'] ?: NULL;
  8.   $collation = @$database_info['collation'] ?: NULL;
  9.   $charset = @$database_info['charset'] ?: NULL;
  10.  
  11.   if (!$collation) {
  12.     throw new Exception('Collation is not configured');
  13.   }
  14.   if (!$charset) {
  15.     throw new Exception('Charset is not configured');
  16.   }
  17.   if ($database && $collation && $charset) {
  18.     db_query("ALTER DATABASE $database CHARACTER SET = $charset COLLATE = $collation");
  19.     foreach (db_query('show tables')->fetchCol() as $table) {
  20.       db_query("ALTER TABLE $table CONVERT TO CHARACTER SET $charset COLLATE $collation");
  21.     }
  22.  
  23.     // Эта проверка необходима, для того, чтобы убрать сообщение
  24.     // о некоректной кодировке со страницы статуса т.к. Drupal
  25.     // делает такую проверку единажды, при установке сайта.
  26.     if ($connection->utf8mb4IsConfigurable() && $connection->utf8mb4IsActive()) {
  27.       variable_set('drupal_all_databases_are_utf8mb4', TRUE);
  28.     }
  29.   }
  30. }

image

Убедитесь, что на данный момент у вас есть в переменной $databases, находящейся в settings.php записи о charset и collation, о чем написано выше.

P.S.
Если будут отзывы о необходимости создания модуля, который делает это не выходя за рамки UI, накидаю такой в следующий раз.