В данной статье собраны наиболее часто встречающиеся варианты миграций, получается такой себе кук-бук
Миграция затрагивающая данные:
class Version20150722151547 extends AbstractMigration
{
const TABLE_WORK = 'participant';
const TABLE_BACKUP = 'participant_20150722151547';
public function up(Schema $schema)
{
// создаем бэкап-таблицу и копируем в нее данные без индексов и FK
$this->addSql('CREATE TABLE ' . self::TABLE_BACKUP . ' AS SELECT * FROM ' . self::TABLE_WORK);
// изменяем данные
$this->addSql('UPDATE ' . self::TABLE_WORK . ' SET doc_type = 1 WHERE participant_type = 1');
}
public function down(Schema $schema)
{
$this->addSql('SET FOREIGN_KEY_CHECKS = 0');
$this->addSql('SET UNIQUE_CHECKS = 0');
$this->addSql('TRUNCATE ' . self::TABLE_WORK);
$this->addSql('INSERT INTO ' . self::TABLE_WORK . ' SELECT * FROM ' . self::TABLE_BACKUP);
$this->addSql('DROP TABLE ' . self::TABLE_BACKUP);
$this->addSql('SET UNIQUE_CHECKS = 1');
$this->addSql('SET FOREIGN_KEY_CHECKS = 1');
}
}
Стоит заметить, что команда SET FOREIGN_KEY_CHECKS = 0 работает для текущей сессии (настройка текущей сессии), то есть на другом параллельном подключении будет уже стоять SET FOREIGN_KEY_CHECKS=1 (если в настройках не было указано иного).
Миграция с логикой:
class Version20140728123205 extends AbstractMigration
{
public function up(Schema $schema)
{
$resultCount = $this->connection->executeQuery("
SELECT
COUNT(*) as count
FROM
booking
")->fetchAll();
if (!array_key_exists('count', $resultCount)) {
throw new Exception('no bookings found to proceed');
}
$this->connection->commit();// закрываем транзакцию, которую начала Doctrine
$this->connection->beginTransaction();// стартуем транзакцию
try {
$this->connection->executeQuery("INSERT IGNORE INTO table SET room_id = :id", ['id' => 123]);
// $this->addSql('UPDATE table_2 SET hotel_id = :id', ['id' => 45]);
$this->connection->commit();// выполняем транзакцию
} catch (\Exception $e) {
$this->connection->rollback();// откатываем транзакцию
throw $e;
}
}
* обратите внимание, мы можем как сразу выполнить запрос, так и добавить запрос, и тогда он будет выполнен в транзакции открытой Doctrine.
Добавление поля (с предварительной проверкой на существование этого поля)
$this->addSql("
SET @s = (SELECT IF(
(SELECT COUNT(*)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'my_table'
AND table_schema = DATABASE()
AND column_name = 'my_field'
) > 0,
'',
'ALTER TABLE my_table ADD my_field VARCHAR(20)'
));
PREPARE stmt FROM @s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
");
На самом деле вариантов решения данной проблемы много, так что просто гуглите: mysql IF NOT EXISTS field.
Если Вы пользуетесь Doctrine, то при изменении описания схемы данных, удобно создать миграцию автоматом - запустив в следующей последовательности команды:
app/console doctrine:generate:entities NameOfYouBundle - обновит Ваши Entity-классы согласно Yml-схемам
app/console doctrine:migrations:diff - непосредственно создаст файл миграции
Удачки.