Migrations [Migrações] e seeders [Propagadores] são utilitários de banco de dados eficazes, fornecidos pela framework do Laravel para PHP, que permite que os desenvolvedores façam a inicialização, destruição e recriação do banco de dados de um aplicativo rapidamente. Esses utilitários ajudam a minimizar problemas de inconsistência de banco de dados que podem surgir com vários desenvolvedores trabalhando no mesmo aplicativo: novos colaboradores precisam apenas executar alguns comandos do artisan
para definir o banco de dados em uma nova instalação.
Neste guia, vamos criar migrations (migrações) e seeders (propagadores) para preencher o banco de dados de um aplicativo de demonstração do Laravel com dados de amostra. No final, você poderá destruir e recriar as tabelas de seu banco de dados quantas vezes quiser, usando apenas comandos do artisan
.
Para seguir este guia, você vai precisar do seguinte:
Nota: neste guia, utilizaremos um ambiente de desenvolvimento em contêiner, gerenciado pelo Docker Compose para executar o aplicativo, mas você também pode optar por executar o aplicativo em um servidor LEMP. Para configurar isso, siga nosso guia sobre Como instalar e configurar o Laravel com LEMP no Ubuntu 18.04.
Para começar, iremos buscar o aplicativo de demonstração do Laravel a partir de seu repositório do GitHub. Estamos interessados na ramificação do tutorial-02
, que inclui uma Configuração do Docker Compose para executar o aplicativo em contêineres. Neste exemplo, baixaremos o aplicativo para nossa pasta base, mas também é possível usar qualquer diretório de sua escolha:
- cd ~
- curl -L https://github.com/do-community/travellist-laravel-demo/archive/tutorial-2.0.1.zip -o travellist.zip
Como baixamos o código do aplicativo como um arquivo .zip
, precisaremos do comando unzip
para desempacotá-lo. Se não tiver feito isso recentemente, atualize o índice de pacotes local de sua máquina:
- sudo apt update
Depois, instale o pacote unzip
:
- sudo apt install unzip
Em seguida, descompacte o conteúdo do aplicativo:
- unzip travellist.zip
Em seguida, renomeie o diretório descompactado como travellist-demo para facilitar o acesso:
- mv travellist-laravel-demo-tutorial-2.0.1 travellist-demo
No próximo passo, vamos criar um arquivo de configuração .env
para configurar o aplicativo.
.env
do aplicativoNo Laravel, o arquivo .env
é usado para configurar as configurações dependentes de ambiente, como credenciais e quaisquer informações que possam variar entre as implantações. Esse arquivo não está incluído no controle de revisão.
Aviso: o arquivo de configuração de ambiente contém informações confidenciais sobre o seu servidor, incluindo credenciais para o banco de dados e chaves de segurança. Por esse motivo, nunca compartilhe esse arquivo publicamente.
Os valores contidos no arquivo .env
terão precedência sobre os valores definidos nos arquivos de configuração regulares, localizados no diretório config
. Cada instalação em um novo ambiente exige um arquivo de ambiente personalizado para definir coisas como as configurações de conexão com o banco de dados, as opções de depuração, o URL do aplicativo, entre outros itens que possam variar, dependendo do ambiente em que o aplicativo esteja funcionando.
Navegue até o diretório travellist-demo
:
- cd travellist-demo
Agora, vamos criar um novo arquivo .env
para personalizar as opções de configuração do ambiente de desenvolvimento que estamos preparando. O Laravel vem com um exemplo de arquivo do .env
que podemos copiar para criar o nosso:
- cp .env.example .env
Abra este arquivo, usando o nano
ou outro editor de texto de sua escolha:
- nano .env
Esta é a aparência do seu arquivo .env
agora:
APP_NAME=Travellist
APP_ENV=dev
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost:8000
LOG_CHANNEL=stack
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=travellist
DB_USERNAME=travellist_user
DB_PASSWORD=password
…
O arquivo .env
atual do aplicativo de demonstração travellist
contém configurações para usar o ambiente em contêiner que criamos com o Docker Compose na última parte desta série. Você não precisa alterar nenhum desses valores, mas fique à vontade para modificar o DB_DATABASE
, o DB_USERNAME
e o DB_PASSWORD
se quiser, uma vez que eles são puxados automaticamente pelo nosso arquivo docker-compose.yml
para configurar o banco de dados de desenvolvimento. Certifique-se apenas de que a variável DB_HOST
permaneça inalterada, uma vez que ela faz referência ao nome do nosso serviço de banco de dados dentro do ambiente do Docker Compose.
Caso faça quaisquer alterações no arquivo, certifique-se de salvar e fechar ele pressionando CTRL + X
, Y
e, então, ENTER
.
Nota: caso tenha optado por executar o aplicativo em um servidor LEMP, será necessário alterar os valores destacados para refletir as configurações do seu próprio banco de dados, incluindo a variável DB_HOST
.
Agora, usaremos o Composer, uma ferramenta de gerenciamento de dependências do PHP, para instalar as dependências do aplicativo e garantir que possamos executar os comandos do artisan
.
Abra seu ambiente do Docker Compose com o comando a seguir. Isso compilará a imagem do travellist
para o serviço do app
e extrairá imagens adicionais do Docker - exigidas pelos serviços nginx
e db
, para criar o ambiente do aplicativo:
- docker-compose up -d
OutputCreating network "travellist-demo_travellist" with driver "bridge"
Building app
Step 1/11 : FROM php:7.4-fpm
---> fa37bd6db22a
Step 2/11 : ARG user
---> Running in 9259bb2ac034
…
Creating travellist-app ... done
Creating travellist-nginx ... done
Creating travellist-db ... done
Esta operação pode levar alguns minutos para completar. Assim que o processo terminar, podemos executar o Composer para instalar as dependências do aplicativo.
Para executar o composer
e outros comandos no contêiner de serviço do app
, utilizaremos o docker-compose exec
. O comando exec
permite que executemos qualquer comando de nossa escolha em contêineres gerenciados pelo Docker Compose. Ele usa a seguinte sintaxe: docker-compose exec service_name command
.
Nota: caso tenha optado por usar um servidor LEMP para executar o aplicativo de demonstração, ignore a parte do docker-compose exec app
dos comandos listados durante todo este guia. Por exemplo, em vez de executar o seguinte comando como ele está escrito, você apenas executaria:
- composer install
Para executar o composer install
no contêiner do app
, execute:
- docker-compose exec app composer install
OutputLoading composer repositories with package information
Installing dependencies (including require-dev) from lock file
Package operations: 85 installs, 0 updates, 0 removals
- Installing doctrine/inflector (1.3.1): Downloading (100%)
- Installing doctrine/lexer (1.2.0): Downloading (100%)
- Installing dragonmantank/cron-expression (v2.3.0): Downloading (100%)
…
Quando o Composer terminar de instalar as dependências do aplicativo, você poderá executar os comandos do artisan
. Para testar se o aplicativo consegue se conectar ao banco de dados, execute o seguinte comando que limpará quaisquer tabelas pré-existentes:
- docker-compose exec app php artisan db:wipe
Esse comando removerá quaisquer tabelas pré-existentes do banco de dados configurado. Se ele foi executado com sucesso e o aplicativo conseguiu se conectar ao banco de dados, você verá um resultado parecido com este:
OutputDropped all tables successfully.
Agora que você tem as dependências do aplicativo instaladas com o Composer, você pode utilizar a ferramenta artisan
para criar migrations e seeders.
A ferramenta de linha de comando do artisan
que vem com o Laravel contém uma série de comandos auxiliares que podem ser usados para gerenciar o aplicativo e inicializar novas classes. Para gerar uma nova classe de migration, podemos usar o comando make:migration
como segue:
- docker-compose exec app php artisan make:migration create_places_table
O Laravel deduz a operação a ser executada (create
), o nome da tabela (places
) e se essa migration criará uma nova tabela ou não, com base no nome descritivo fornecido para o comando make:migration
.
Você verá um resultado semelhante a este:
OutputCreated Migration: 2020_02_03_143622_create_places_table
Isso gerará um novo arquivo no diretório database/migrations
do aplicativo. O carimbo de data/hora no arquivo gerado automaticamente é utilizado pelo Laravel para determinar em qual ordem as migrations devem ser executadas.
Utilize seu editor de texto preferido para abrir o arquivo migration gerado. Lembre-se de substituir o valor destacado pelo nome de arquivo de migration de sua escolha:
- nano database/migrations/2020_02_03_143622_create_places_table.php
O arquivo de migration gerado contém uma classe chamada CreatePlacesTable
:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreatePlacesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('places', function (Blueprint $table) {
$table->bigIncrements('id');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('places');
}
}
Essa classe tem dois métodos: up
e down
. Ambos os métodos contêm o código de inicialização que podem ser estendidos para personalizar o que acontece quando essa migration for executada e também o que acontece quando ela for revertida.
Vamos modificar o método up
, de modo que a tabela places
reflita a estrutura que já estamos usando na versão atual do aplicativo:
id
: campo de chave primária.name
: nome do lugar.visited
: se este lugar já foi visitado ou não.O compilador de esquemas do Laravel expõe métodos para a criação, atualização e exclusão de tabelas em um banco de dados. A classe Blueprint
define a estrutura da tabela e ela proporciona vários métodos para abstrair a definição de cada campo da tabela.
O código gerado automaticamente define um campo de id primário chamado id
. O método timestamps
cria dois campos de datetime
que são atualizados automaticamente pelas classes de banco de dados subjacentes, quando os dados são inseridos ou atualizados dentro dessa tabela. Além disso, precisaremos incluir um campo name
e um visited
.
Nosso campo name
será do tipo string
e nosso campo visited
será definido com o tipo boolean
. Também vamos definir um valor padrão de 0
para o campo visited
, de modo que se nenhum valor for transferido, significa que o lugar ainda não foi visitado. É assim que o método up
se parecerá agora:
…
public function up()
{
Schema::create('places', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name', 100);
$table->boolean('visited')->default(0);
$table->timestamps();
});
}
…
Nota: você pode encontrar a lista completa dos tipos de coluna disponíveis na documentação do Laravel.
Após incluir as duas linhas destacadas em seu próprio script de migration, salve e feche o arquivo.
Agora, sua migration está pronta para ser executada através do artisan migrate
. No entanto, isso criaria apenas uma tabela vazia; também precisamos conseguir inserir dados da amostra para o desenvolvimento e teste. No próximo passo, veremos como fazer isso usando os seeders de banco de dados.
Um seeder é uma classe especial utilizada para gerar e inserir dados de amostra (seeds) em um banco de dados. Essa é uma característica importante em ambientes de desenvolvimento, uma vez que permite que você recrie o aplicativo com um banco de dados novo, usando valores de amostra que, de qualquer forma você teria que inserir manualmente toda vez que o banco de dados fosse recriado.
Agora, utilizaremos o comando artisan
para gerar uma nova classe de seeders para nossa tabela de places
chamada PlacesTableSeeder
:
- docker-compose exec app php artisan make:seeder PlacesTableSeeder
O comando criará um novo arquivo chamado PlacesTableSeeder.php
dentro do diretório database/seeds
. Abra aquele arquivo usando seu editor de texto preferido:
- nano database/seeds/PlacesTableSeeder.php
É assim que o arquivo PlacesTableSeeder.php
, gerado automaticamente, se parece:
<?php
use Illuminate\Database\Seeder;
class PlacesTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
//
}
}
Nossa nova classe de seeder contém um método vazio chamado run
. Esse método será chamado quando o comando db:seed
do Artisan for executado.
Precisamos editar o método run
para incluir instruções para inserir dados de amostra no banco de dados. Vamos utilizar o compilador de consultas do Laravel para simplificar esse processo.
O compilador de consultas do Laravel oferece uma interface fluente para as operações de banco de dados como a inserção, atualização e recuperação de dados. Ele também introduz proteções contra ataques de injeção de SQL. O compilador de consulta é exposto pela facade do DB
- um proxy estático para as classes de banco de dados subjacentes no contêiner de serviço.
Para começar, criaremos uma variável de classe estática para reter todos os locais das amostras que desejamos inserir no banco de dados como uma matriz. Isso nos permitirá usar um loop foreach
para iterar em todos os valores, inserindo cada um no banco de dados utilizando o compilador de consulta.
Chamaremos essa variável de $places
:
<?php
use Illuminate\Database\Seeder;
class PlacesTableSeeder extends Seeder
{
static $places = [
'Berlin',
'Budapest',
'Cincinnati',
'Denver',
'Helsinki',
'Lisbon',
'Moscow',
'Nairobi',
'Oslo',
'Rio',
'Tokyo'
];
…
Em seguida, precisaremos incluir uma instrução use
no topo de nossa classe PlacesTableSeeder
para facilitar a referência da facade DB
em todo o código:
<?php
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class PlacesTableSeeder extends Seeder
…
Agora, podemos iterar através dos valores da matriz $places
, usando um loop foreach
e inserir cada um deles em nossa tabela places
com o compilador de consultas:
…
public function run()
{
foreach (self::$places as $place) {
DB::table('places')->insert([
'name' => $place,
'visited' => rand(0,1) == 1
]);
}
}
O loop foreach
itera através de cada valor da matriz estática $places
. Em cada iteração, usamos a facade DB
para inserir uma nova linha na tabela places
. Definimos o campo name
para o nome do lugar que acabamos de obter da matriz $places
e definimos o campo visited
para um valor aleatório de 0
ou 1
.
É assim que a classe PlacesTableSeeder
completa se parecerá após todas as atualizações:
<?php
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class PlacesTableSeeder extends Seeder
{
static $places = [
'Berlin',
'Budapest',
'Cincinnati',
'Denver',
'Helsinki',
'Lisbon',
'Moscow',
'Nairobi',
'Oslo',
'Rio',
'Tokyo'
];
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
foreach (self::$places as $place) {
DB::table('places')->insert([
'name' => $place,
'visited' => rand(0,1) == 1
]);
}
}
}
Salve e feche o arquivo quando terminar de fazer essas alterações.
As classes do seeder não são carregadas automaticamente no aplicativo. Precisamos editar a classe principal, DatabaseSeeder
, para incluir uma chamada para o seeder que acabamos de criar.
Abra o arquivo database/seeds/DatabaseSeeder.php
com o nano
ou com o seu editor favorito:
- nano database/seeds/DatabaseSeeder.php
A classe DatabaseSeeder
se parece com qualquer outro seeder: ela se estende a partir da classe Seeder
e tem um método run
. Atualizaremos esse método para incluir uma chamada para o PlacesTableSeeder
.
Atualize o método run
atual, dentro da classe DatabaseSeeder
, excluindo a linha comentada e substituindo-a pelo código destacado a seguir:
…
public function run()
{
$this->call(PlacesTableSeeder::class);
}
...
É assim que a classe DatabaseSeeder
completa se parecerá após a atualização:
<?php
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* @return void
*/
public function run()
{
$this->call(PlacesTableSeeder::class);
}
}
Salve e feche o arquivo quando terminar de atualizar seu conteúdo.
Agora, terminamos a configuração da migration e de um seeder para nossa tabela places
. No próximo passo, veremos como executá-las.
Antes de prosseguir, precisamos garantir que seu aplicativo esteja em funcionamento. Vamos configurar a chave de criptografia do aplicativo e, depois, acessar o aplicativo a partir de um navegador para testar o servidor Web.
Para gerar a chave de criptografia que o Laravel exige, utilize o comando artisan key:generate
:
- docker-compose exec app php artisan key:generate
Assim que a chave tiver sido gerada, você poderá acessar o aplicativo, apontando seu navegador para o nome do host ou endereço IP do servidor na porta 8000
:
http://server_host_or_ip:8000
Você verá uma página como esta:
Isso significa que o aplicativo conseguiu conectar-se ao banco de dados, mas que não encontrou uma tabela chamada places
. Vamos criar a tabela places
agora, utilizando o comando do artisan migrate
:
- docker-compose exec app php artisan migrate
Você obterá um resultado parecido com este:
OutputMigration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table (0.06 seconds)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table (0.06 seconds)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated: 2019_08_19_000000_create_failed_jobs_table (0.03 seconds)
Migrating: 2020_02_10_144134_create_places_table
Migrated: 2020_02_10_144134_create_places_table (0.03 seconds)
Você verá que algumas outras migrations foram executadas junto com a migration create_places_table
que configuramos. Essas migrations são geradas automaticamente quando o Laravel é instalado. Embora não estejamos usando essas tabelas adicionais agora, elas serão necessárias no futuro quando expandirmos o aplicativo para ele ter usuários registrados e trabalhos agendados. Por enquanto, deixe-as como estão.
Neste ponto, nossa tabela ainda está vazia. Precisamos executar o comando db:seed
para propagar o banco de dados com nossas amostras de locais:
- docker-compose exec app php artisan db:seed
Isso executará nosso seeder e irá inserir os valores da amostra que definimos dentro da nossa classe PlacesTableSeeder
. Você verá um resultado semelhante a este:
OutputSeeding: PlacesTableSeeder
Seeded: PlacesTableSeeder (0.06 seconds)
Database seeding completed successfully.
Agora, recarregue a página do aplicativo no seu navegador. Você verá uma página parecida com esta:
Sempre que precisar começar do zero, você poderá remover todas as tabelas de banco de dados com:
- docker-compose exec app php artisan db:wipe
OutputDropped all tables successfully.
Para executar o aplicativo migrations e propagar as tabelas em um único comando, utilize:
- docker-compose exec app php artisan migrate --seed
OutputMigration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table (0.06 seconds)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table (0.07 seconds)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated: 2019_08_19_000000_create_failed_jobs_table (0.03 seconds)
Migrating: 2020_02_10_144134_create_places_table
Migrated: 2020_02_10_144134_create_places_table (0.03 seconds)
Seeding: PlacesTableSeeder
Seeded: PlacesTableSeeder (0.06 seconds)
Database seeding completed successfully.
Se quiser reverter uma migration, você pode executar:
- docker-compose exec app php artisan migrate:rollback
Isso acionará o método down
para cada classe de migration dentro da pasta migrations
. Normalmente, ele removerá todas as tabelas que foram criadas através das classes de migration, deixando sozinha quaisquer outras tabelas que possam ter sido criadas manualmente. Você verá um resultado como este:
OutputRolling back: 2020_02_10_144134_create_places_table
Rolled back: 2020_02_10_144134_create_places_table (0.02 seconds)
Rolling back: 2019_08_19_000000_create_failed_jobs_table
Rolled back: 2019_08_19_000000_create_failed_jobs_table (0.02 seconds)
Rolling back: 2014_10_12_100000_create_password_resets_table
Rolled back: 2014_10_12_100000_create_password_resets_table (0.02 seconds)
Rolling back: 2014_10_12_000000_create_users_table
Rolled back: 2014_10_12_000000_create_users_table (0.02 seconds)
O comando de reversão é especialmente útil quando estiver fazendo alterações nos modelos do aplicativo e um comando db:wipe
não puder ser usado - por exemplo, caso vários sistemas dependerem de um mesmo banco de dados.
Neste guia, vimos como usar as migrations e os seeders de banco de dados para facilitar a configuração de bancos de dados para desenvolvimento e teste para um aplicativo Laravel 6.
Como um passo seguinte, talvez você queira conferir a documentação do Laravel para obter mais informações sobre como usar o compilador de consultas e como usar os Modelos eloquentes para se concentrar ainda mais no esquema do banco de dados do seu aplicativo.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!