Доктрина миграций отступает - PullRequest
4 голосов
/ 17 января 2011

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

Например, если существует миграция, добавляющая 5 внешних ключей, и 5-й из них дает сбой, когда поля не имеют одинаковую длину, исправление ошибки с помощью полей и повторное создание миграций не исправляют В общем, пока есть ошибка, связанная с тем, что 4 ключа уже существуют и не позволяют успешно выполнить миграцию.

Есть ли стабильный способ использовать Doctrine-миграции без таких очевидных проблем, как упомянуто? Мы уже использовали .sql файлы, что на самом деле не намного лучше, но я уверен, что есть правильный способ управления версиями базы данных для проекта, использующего Doctrine?

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

Спасибо

Ответы [ 3 ]

2 голосов
/ 08 февраля 2011

Я вроде решил это, решение не так уж и приятно, но, тем не менее, я думаю, что оно будет полезно для других людей. Я использую CLI, действительно, я уже сделал файл, заставляя каждую миграцию обновлять номер в базе данных, аналогично тому, который был в ответе Тимо, прежде чем задавать этот вопрос, но это все еще не очень эффективно, но все равно стоит делать.

То, что я сделал, решает следующие вопросы: doctrine/lib/Doctrine/Migration/Builder.php строка 531. Существует определение класса по умолчанию, который будет распространяться на каждую миграцию. Так как я использую CLI и не смог найти способ передачи параметров в это место, я просто заменил Doctrine_Migration_Base на другой класс MY_Doctrine_Migration_Base, который ниже.

Если вы не используете CLI, я бы сказал, что вы должны попытаться передать параметры, а не заменять источник.

Таким образом, приведенный ниже класс расширяет Doctrine_Migration_Base и переписывает кучу методов на те, которые проверяют, можно ли вносить изменения, а затем вызывают родительский метод для их выполнения. Это не охватывает все методы в настоящее время, только те, с которыми я столкнулся, когда писал это.

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

<?php

class MY_Doctrine_Migration_Base extends Doctrine_Migration_Base {
    public function __construct() {
        $this->connection = Doctrine_Manager::getInstance()->getCurrentConnection();
    }

    public function addIndex($tableName, $indexName, array $definition) {
        foreach ($this->connection->execute("SHOW INDEXES IN $tableName")->fetchAll(PDO::FETCH_ASSOC) as $index) {
            if ($index['Key_name'] === $indexName.'_idx') {
                echo "Index $indexName already exists in table $tableName. Skipping\n";
                return;
            }
        }

        parent::addIndex($tableName, $indexName, $definition);
    }

    public function removeColumn($tableName, $columnName) {
        if ($this->column_exists($tableName, $columnName)) {
            parent::removeColumn($tableName, $columnName);
        } else {
            echo "Column $columnName doesn't exist in $tableName. Can't drop\n";
        }
    }

    public function createTable($tableName, array $fields = array(), array $options = array()) {
        if ($this->connection->execute("SHOW TABLES LIKE '$tableName'")->fetchAll(PDO::FETCH_ASSOC)) {
            echo "Table $tableName already exists. Can't create\n";
        } else {
            parent::createTable($tableName, $fields, $options);
        }
    }

    public function addColumn($tableName, $columnName, $type, $length = null, array $options = array()) {
        if (! $this->column_exists($tableName, $columnName)) {
            parent::addColumn($tableName, $columnName, $type, $length, $options);
        } else {
            echo "Column $columnName already exists in $tableName. Can't add\n";
        }
    }

    private function column_exists($tableName, $columnName) {
        $exception = FALSE;

        try { //parsing information_schema sucks because security will hurt too bad if we have access to it. This lame shit is still better
            $this->connection->execute("SELECT $columnName FROM $tableName")->fetchAll(PDO::FETCH_ASSOC);
        } catch (Exception $exception) {}
        //if someone knows how to check for column existence without exceptions AND WITHOUT INFORMATION SCHEMA please rewrite this stuff

        return $exception === FALSE;
    }
}

Предложения по улучшению этого положения приветствуются.

1 голос
/ 03 февраля 2011

Если вы используете doctrine-cli, вы можете написать свою собственную задачу миграции, которая создает резервную копию базы данных перед миграцией и восстанавливает резервную копию в случае сбоя миграции. Я написал нечто подобное для наших миграций Symfony / Doctrine.

Если вы поместите свой класс задач в правильный каталог, доктрина cli отобразит его в списке доступных команд

0 голосов
/ 19 января 2011

Доктрины миграции не справятся с этим.Сожалею, что у всех нас есть эти проблемы, потому что миграции не выполнялись в транзакции.

Вы можете улучшить это, добавив плагин.См .: Blog-Post

Другая возможность - сделать резервную копию базы данных перед миграцией, и если что-то пойдет не так, вы можете переустановить резервную копию.Вы можете автоматизировать это с помощью сценария оболочки

...