Migração da Base de Dados

Nota: A função de migração de banco de dados está disponível desde a versão 1.1.6.

Como o código-fonte, a estrutura de um banco de dados está evoluindo conforme nós desenvolvemos e mantemos a aplicação. Por exemplo, durante o desenvolvimento, nós podemos querer adicionar uma nova tabela; ou depois de a apliação ser posta em produção, nós podemos nos dar conta da necessidade da adição de um índice em uma coluna. É importante manter o controle destas mudanças estruturais do banco de dados (chamadas migrações) da mesma maneira que fazemos com o código-fonte. Se o código-fonte e o banco de dados estão sem sincronia, é muito provável que o sistema como um todo pare de funcionar. Por esta razão, Yii fornece uma ferramenta de migração de banco de ddos que pode controlar o histórico de migrações do banco de dados, aplicar novas migrações ou reverter migrações existentes.

Os passos seguintes mostram como nós podemos usar a migração do banco de dados durante o desenvolvimento:

  1. João cria uma nova migração (por exemplo, uma nova tabela)
  2. João faz o commit da nova migração no sistem de versionamento de código-fonte (como SVN, GIT)
  3. Pedro faz um update a partir do sistema de versionamento de código-fonte e recebe a nova migração
  4. Pedro aplica a migração ao seu banco de dados local de desenvolvimento

Yii suporta migrações de banco de dados atraves da ferramenta de linha de comando yiic migrate. Esta ferramenta suporta a criação de novas migrações, a aplicação/reversão/reaplicação de migrações, e a exibição do histórico de migrações e as novas migrações.

A seguir, vamos descrever como usar esta ferramenta.

Nota: É melhor usar o yiic específico da aplicação (por exemplo, cd caminho/até/protected) quando trabalhar com o comando migrate ao invés de usar o do diretório framework. Certifique-se de que você tem um diretório protected\migrations e de que ele tem permissões de escrita. Verifique também se você configurou a conexão do banco de dados no seu arquivo protected/config/console.php.

1. Criando Migrações

Para criar uma nova migração (por exemplo, criar uma nova tabela news), nós executamos o seguinte comando:

yiic migrate create <name>

O parâmetro obrigatório name especifica uma breve descrição da migração (por exemplo, create_news_table). Como nós vamos mostrar abaixo, o parâmetro name é usado como marte de uma classe PHP. Então, ele deve coter apenas letras, números e/ou caracteres de sublinhado.

yiic migrate create create_news_table

O comando acima vai criar, sob o diretório protected/migrations um novo arquivo chamado m101129_185401_create_news_table.php, que contém o seguinte código inicial:

class m101129_185401_create_news_table extends CDbMigration
{
    public function up()
    {
    }
 
    public function down()
    {
        echo "m101129_185401_create_news_table does not support migration down.\n";
        return false;
    }
 
    /*
    // implement safeUp/safeDown instead if transaction is needed
    public function safeUp()
    {
    }
 
    public function safeDown()
    {
    }
    */
}

Note que o nome da classe é o mesmo que o nome do arquivo, o qual tem o padrão m<timestamp>_<name>, onde <timestamp> refere-se a um "carimbo de tempo" UTC (no formato yymmdd_hhmmss) de quando a migração é criada, e <name> é obtido a partir do parâmetro name da linha de comando.

O método up() deve conter o código implementando a migração de fato, enquanto o método down() pode conter o código revertendo o que é feito em up().

Algumas vezes, é impossível implementar o método down(). Por exemplo, se nós removemos linhas de uma tabela em up(), nós não poderemos recuperá-las em down(). Neste caso, a migração é chamada irreversível, o que significa que nós não podemos reertê-la para um estado anterior do banco de dados. No código gerado acima, o método down() retorna false para indicar que a migração não pode ser revertida.

Informação: A partir da versão 1.1.7, se o método up() ou down() retornar false, todas as migrações seguintes serão canceladas. Anteriormente, na versão 1.1.6, o usuário teria que lançar exceções para cancelar as migrações seguintes.

Como um exemplo, vamos mostrar uma migração para a criação de uma tabela news.

class m101129_185401_create_news_table extends CDbMigration
{
    public function up()
    {
        $this->createTable('tbl_news', array(
            'id' => 'pk',
            'title' => 'string NOT NULL',
            'content' => 'text',
        ));
    }
 
    public function down()
    {
        $this->dropTable('tbl_news');
    }
}

A classe base CDbMigration fornece um conjunto de métodos para a manupulação de dados e da estrutura de um banco de dados. Por exemplo, CDbMigration::createTable criará uma tabela, enquanto CDbMigration::insert vai inserir uma linha de dados. Todos estes métodos usam a conexão de banco de dados retornada por CDbMigration::getDbConnection(), a qual por padrão retorna Yii::app()->db.

Informação: Você pode notar que os métodos de banco de dados fornecidos pela classe CDbMigration são muito similares aos em CDbCommand. De fato, eles são praticamente os mesmos, exceto que os métodos de CDbMigration vão medir o tempo usado e imprimir algumas mensagens sobre os parâmetros passados.

2. Migrações Transacionais

Informação: A funcionalidade de migrações transacionais é suportada desde a versão 1.1.7.

Ao realizar migrações complexas do banco de dados, nós geralmente queremos ter certeza de que cada migração teve sucesso ou de que ela falhou como um todo, para que o banco de dados mantenha a consistência e a integridade. Para alcançarmos este objetivo, nós podemos fazer uso das transações do banco de dados.

Nós podemos explicitamente iniciar uma transação do banco de dados e realizar o resto do código relacionado ao banco de dados dentro da transação, como a seguir:

class m101129_185401_create_news_table extends CDbMigration
{
    public function up()
    {
        $transaction=$this->getDbConnection()->beginTransaction();
        try
        {
            $this->createTable('tbl_news', array(
                'id' => 'pk',
                'title' => 'string NOT NULL',
                'content' => 'text',
            ));
            $transaction->commit();
        }
        catch(Exception $e)
        {
            echo "Exception: ".$e->getMessage()."\n";
            $transaction->rollback();
            return false;
        }
    }
 
    // ...similar code for down()
}

Porém, uma maneira mais fácil de obter o suporte a transações é implementar o método safeUp() ao invés de up(), e safeDown() ao invés de down(). Por exemplo,

class m101129_185401_create_news_table extends CDbMigration
{
    public function safeUp()
    {
        $this->createTable('tbl_news', array(
            'id' => 'pk',
            'title' => 'string NOT NULL',
            'content' => 'text',
        ));
    }
 
    public function safeDown()
    {
        $this->dropTable('tbl_news');
    }
}

Quando o Yii realizar a migração, ele iniciará uma transação do banco de dados e então chamará safeUp() ou safeDown(). Se algum ocorrer algum erro do banco de dados em safeUp() ou safeDown(), a transação será revertida, o que garante que o banco de dados continue em boa forma.

Nota: Nem todos os SGBD suportam transações. E algumas cosultas do banco de dados não podem ser postas em uma transação. Neste caso, você terá que implementar up() e down(). E, para o MySQL, alguns comandos SQL podem causar commits implícitos.

3. Aplicação Migrações

Para aplicar todas as novas migrações disponíveis (o que significa deixar o banco de dados local atualizado),execute o seguinte comando:

yiic migrate

O comando irá mostras a lista de todas as novas migrações. Se você confirmar apply a aplicaçao das migrações, ele chamará o método up() em cada nova classe de migração, uma após a outra, na ordem do valor do "carimbo de tempo" em cada nome de classe.

Após aplicar a migração, a ferramenta de migração manterá um registro em uma tabela chamada tbl_migration no banco de dados. Isto permite que a ferramenta identifique quais migrações já foram aplicadas e quais não foram. Se a tabela tbl_migration não existir, a ferramenta a criará automaticamente no banco de dados especificado pelo componente de aplicação db.

Algumas vezes, nós podemos querer aplicar somente uma ou algumas das migrações. Nós podemos usar o comando abaixo:

yiic migrate up 3

Este comando aplicará as 3 novas migrações. Alterando o valor "3" nos permitirá alterar o número de migrações a serem aplicadas.

Nós podemos também migrar para uma versão específica do banco de dados com o seguinte comando:

yiic migrate to 101129_185401

Isto é, nós usamos a parte do "carimbo de tempo" do nome de uma migração para especificar a versão para a qual nós desejamos migrar o banco de dados. Se há múltiplas migrações entre a última migração aplicada e migração especificada, todas estas migrações serão aplicadas. Se a migração especificada já foi aplicada antes, então todas as migrações aplicadas depois dela serõ revertidas (a ser descrito na próxima seção).

4. Revertendo Migrações

Para reverter a última ou algumas das últimas migrações aplicadas, nós podemos usar o seguinte comando:

yiic migrate down [step]

Onde o parâmetro opcional step especifica quantas migrações devem ser revertidas. O padrão é 1, o que significa que a última migração aplicada será revertida.

Como nós descrevemos antes, nem todas as migrações podem ser revertidas. Se você tentar reverter uma destas migrações, será lançada uma exceção e todo o processo de reversão será encerrado.

5. Reaplicando Migrações

Reaplicar uma migração significa primeiro reverter e então aplicar a migração especificada. Isto pode ser feito com o comando a seguir:

yiic migrate redo [step]

onde o parâmetro opcionalstep especifica quantas migrações serão reaplicadas. O padrão é 1, o que significa que a última migração aplicada será reaplicada.

6. Exibindo Informações da Migração

Além de aplicar e reverter migrações, a ferramenta de migrações também pode exibir o histórico de migrações e as novas migrações a serem aplicadas.

yiic migrate history [limit]
yiic migrate new [limit]

Onde o parâmetro opcional limit especifica o número de aplicações a serem exibidas. Se limit não é especificado, todas as migrações disponíveis serão exibidas.

O primeiro comando exibe as migrações que foram aplicadas, enquanto o segundo mostra as migrações que não foram aplicadas.

7. Modificando o Histórico de Migrações

Algumas vezes, nós podemos querer modificar o histórico de migrações para uma versão de migração específica sem de fato aplicar ou reverter as migrações relevantes. Isto acontece frequentemente quando estamos criando uma nova migração. Nós podemos usar o comando a seguir para atingir este objetivo.

yiic migrate mark 101129_185401

Este comando é muito similar ao comando yiic migrate to, exceto que ele apenas modifica a tabela do histórico de migrações para a migração especificada sem aplicar ou reverter migrações.

8. Personalizando o Comando de Migração

Há algumas maneiras de personalizar o comando de migração.

Use Opções de Linha de Comando

O comando de migração possui quatro opções que podem ser especificadas na linha de comando:

  • interactive: boolean, especifica se as migrações devem ser executadas em modo interativo. O padrão é true, o que significa que o usuário será perguntado quando executar uma migração específica. Você pode alterar esta opção para false quando as migrações são feitas por um processo em background.

  • migrationPath: string, espeficica o diretório contendo todos os arquivos das classes de migrações. Esta opção deve ser especificada como um path alias (apelido para caminho), e o diretório correspondente deve existir. Se não for especificado, será usado o subdiretório migrations sob o caminho base da aplicação.

  • migrationTable: string, especifica o nome da tabela do banco de dados para armazenar o histórico de migrações. O padrão é tbl_migration. A estrutura da tabela é version varchar(255) primary key, apply_time integer.

  • connectionID: string, especifica o ID do componente de banco de dados da aplicação. O padrão é 'db'.

  • templateFile: string, especifica o caminho do arquivo que servirá de modelo para a geração das classes de migração. Esta opção deve ser especificada como um path alias (por exemplo application.migrations.template). Se não for configurado, um modelo interno será usado. Dentro do modelo, o símbolo {ClassName} será substituído pelo nome real da classe da migração.

Para especificar estas opções, execute o comando de migração com o seguinte formato

yiic migrate up --option1=value1 --option2=value2 ...

Por exemplo, se nós queremos migrar para um módulo forum cujos arquivos de migração estejam localizados no diretório migrations do módulo, nós podemos usar o comando abaixo:

yiic migrate up --migrationPath=ext.forum.migrations

Configurar o Comando Globalmente

Enquanto as opções de linha de comando nos permitem configurar o comando de migração dinamicamente, algumas vezes nós podemos querer configura o comando uma vez para todas as execuções. Por exemplo, nós podemos querer usar uma tabela diferente para armazenar o histórico de migrações, ou nós podemos querer usar um modelo de migração personalizado. Nós podemos fazer isto modificando o arquivo de configuração da aplicação de console como a seguir,

return array(
    ......
    'commandMap'=>array(
        'migrate'=>array(
            'class'=>'system.cli.commands.MigrateCommand',
            'migrationPath'=>'application.migrations',
            'migrationTable'=>'tbl_migration',
            'connectionID'=>'db',
            'templateFile'=>'application.migrations.template',
        ),
        ......
    ),
    ......
);

Agora, se nós executarmos o comando migrate, a configuração acima fará efeito sem ser necessário usar as opções de linha de comando em todas as vezes.

$Id$

Be the first person to leave a comment

Please to leave your comment.