Поиск по этому блогу

вторник, 27 сентября 2011 г.

Багфикс кодировки utf8 для генерации таблиц в Doctrine 2

Привет, %username%.
Иногда пользуюсь Docrine 2.1/Symfony 2.0. + doctrine migrations. В один прекрасный момент возникла проблема с кодировкой БД mysql при автоматическом создании таблиц. Покопавшить немного в Docrine DBAL выяснилось, что при создании схемы, параметры кодировки не учитываются.



Схема БД генерится в примерно так:
/* было */
CREATE TABLE TABLENAME (
/* ... */
) ENGINE = InnoDB

А нам нужно:
/* нужно */
CREATE TABLE TABLENAME (
/* ... */
)DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE = InnoDB
Причем ни на какие настройки Docrine DBAL не реагировал.

Решение проблемы:

Открываем код. Находим файл doctrine-dbal/lib/Doctrine/DBAL/Schema/Schema.php ищем строку "new Table". Она там одна, код выглядит как-то так:
<?php
/**
     * Create a new table
     * 
     * @param  string $tableName
     * @return Table
     */
    public function createTable($tableName)
    {
        $table = new Table($tableName);
        $this->_addTable($table);
        return $table;
    }
?>
Добавляем в конструктор объекта Table параметры:

array(),array(),array(),0,array('charset'=>'utf8','collate'=>'utf8_general_ci')
Получится что-то типа такого:
<?php
/**
     * Create a new table
     * 
     * @param  string $tableName
     * @return Table
     */
    public function createTable($tableName)
    {
        $table = new Table($tableName,array(),array(),array(),0,array('charset'=>'utf8','collate'=>'utf8_general_ci'));
        $this->_addTable($table);
        return $table;
    }
?>

После этого можете запускать doctrine:migrations:diff и получать правильный SQL код.
Написал мини патч, чтобы при каждом обновлении не править, написал патч:
#!/usr/bin/php
<?php
/**
 * Doctrine DBAL Patch
 * fix table creation query encode
 * (c) _Nicolay
 */


system ('cp ./vendor/doctrine-dbal/lib/Doctrine/DBAL/Schema/Schema.php ./vendor/doctrine-dbal/lib/Doctrine/DBAL/Schema/Schema.php.Orig');

$data = file_get_contents('./vendor/doctrine-dbal/lib/Doctrine/DBAL/Schema/Schema.php');
$data = str_replace("new Table(\$tableName);",
                    "new Table(\$tableName,array(),array(),array(),0,array('charset'=>'utf8','collate'=>'utf8_general_ci'));",
                    $data);
file_put_contents('./vendor/doctrine-dbal/lib/Doctrine/DBAL/Schema/Schema.php', $data);
Про проблему создал задачу на баг фикс. На этом всё, надеюсь кому-нибудь помог.

UPD:

Ура, мой баг закрыли. Просто обновите Doctrine2 и посмотрите настройки внимательно.

2 комментария:

  1. Стоит упомянуть о более простом варианте - просто выставить сравнение по-умолчанию в utf_general_ci в настройках базы. Конечно, такой вариант не подойдет, если используются различные кодировки.

    ОтветитьУдалить
  2. Согласен, Такой вариант предлагается в официальной документации доктрины. Где-то они так и советуют делать.
    но:
    1. не всегда есть возможность это сделать
    2. настройки по умолчанию в БД я выставлял, но кодировка всё-равно оказывалась поломанной, т.к. есть ещё глобальные настройки сервера. Их я тоже менял, лучше не стало. Либо я что-то сделал не так, либо это баг mysql. Если не указывать явно кодировку, то по-умолчанию она всё-равно выставлялась latin1.

    Убив на это порядочно времени я полез копаться в исходниках Doctrine, чтобы понять что же за SQL она генерит, так родилась эта статья.

    ОтветитьУдалить