<h2>Entendendo Migrations: Versionamento do Seu Banco de Dados</h2>
<p>Migrations no Laravel funcionam como um sistema de controle de versão para sua estrutura de banco de dados. Em vez de criar tabelas manualmente via SQL, você define-as através de código PHP que pode ser rastreado, compartilhado e revertido. Isso é fundamental em projetos colaborativos onde múltiplos desenvolvedores precisam manter o esquema do banco sincronizado.</p>
<p>Uma migration é basicamente uma classe que descreve alterações no banco de dados. Ela contém dois métodos: <code>up()</code> (o que fazer) e <code>down()</code> (como desfazer). Laravel cria um arquivo com timestamp automático para garantir que as migrações rodem sempre na ordem correta.</p>
<pre><code class="language-php">// database/migrations/2024_01_15_100000_create_users_table.php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUsersTable extends Migration
{
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('users');
}
}</code></pre>
<p>Aqui você vê a estrutura típica: o método <code>up()</code> cria a tabela com suas colunas, e <code>down()</code> a remove. O timestamp no nome do arquivo garante que esta migration rode antes de uma criada depois. Use <code>php artisan migrate</code> para executar todas as migrações pendentes e <code>php artisan migrate:rollback</code> para desfazer a última batida de migrações.</p>
<h3>Criando Migrations com Gerador</h3>
<p>O Laravel oferece um comando que cria migrations com boilerplate pronto. Para criar uma nova tabela, use:</p>
<pre><code class="language-bash">php artisan make:migration create_posts_table --create=posts</code></pre>
<p>Se você quer alterar uma tabela existente:</p>
<pre><code class="language-bash">php artisan make:migration add_status_to_users_table --table=users</code></pre>
<p>No segundo caso, o método <code>up()</code> vem com a estrutura para modificação:</p>
<pre><code class="language-php">public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->string('status')->default('active');
$table->softDeletes();
});
}</code></pre>
<p>Repare que usamos <code>Schema::table()</code> para alterar tabelas existentes, enquanto <code>Schema::create()</code> é para criar novas. Detalhes como este fazem diferença real em produção.</p>
<h2>Seeders: Populando Dados de Forma Inteligente</h2>
<p>Se migrations definem a estrutura, seeders definem os dados iniciais. Um seeder é uma classe que insere registros no banco durante desenvolvimento ou setup inicial. Isso evita que você insira dados manualmente ou através de SQL puro.</p>
<p>Crie um seeder com <code>php artisan make:seeder PostSeeder</code>. Laravel gera um arquivo em <code>database/seeders/PostSeeder.php</code>:</p>
<pre><code class="language-php">namespace Database\Seeders;
use App\Models\Post;
use Illuminate\Database\Seeder;
class PostSeeder extends Seeder
{
public function run()
{
Post::create([
'title' => 'Primeiro Post',
'content' => 'Conteúdo do post...',
'author_id' => 1,
]);
Post::create([
'title' => 'Segundo Post',
'content' => 'Mais conteúdo...',
'author_id' => 1,
]);
}
}</code></pre>
<h3>Factories: Gerando Dados em Massa</h3>
<p>Para dados de teste ou desenvolvimento, factories são muito mais práticas que inserir registros um por um. Uma factory define como gerar dados fictícios realistas usando a biblioteca Faker:</p>
<pre><code class="language-php">// database/factories/PostFactory.php
namespace Database\Factories;
use App\Models\Post;
use Illuminate\Database\Eloquent\Factories\Factory;
class PostFactory extends Factory
{
protected $model = Post::class;
public function definition()
{
return [
'title' => $this->faker->sentence(5),
'content' => $this->faker->paragraph(4),
'author_id' => \App\Models\User::factory(),
'published_at' => $this->faker->optional()->dateTime(),
];
}
}</code></pre>
<p>Agora seu seeder pode usar a factory para gerar múltiplos registros:</p>
<pre><code class="language-php">public function run()
{
// Cria 50 posts com dados realistas
Post::factory(50)->create();
// Ou criar com relações
Post::factory(10)->for(User::first())->create();
}</code></pre>
<p>Isso economiza linhas de código e torna dados de teste mais realistas.</p>
<h3>Executando Seeders de Forma Organizada</h3>
<p>O DatabaseSeeder funciona como maestro que orquestra todos os seus seeders:</p>
<pre><code class="language-php">// database/seeders/DatabaseSeeder.php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
public function run()
{
$this->call([
UserSeeder::class,
PostSeeder::class,
CommentSeeder::class,
]);
}
}</code></pre>
<p>Execute tudo com um único comando:</p>
<pre><code class="language-bash">php artisan db:seed</code></pre>
<p>Para rodar um seeder específico:</p>
<pre><code class="language-bash">php artisan db:seed --class=PostSeeder</code></pre>
<p>Uma abordagem profissional combina migrations com seeders no setup completo:</p>
<pre><code class="language-bash">php artisan migrate:fresh --seed</code></pre>
<p>Este comando apaga tudo e reconstrói o banco do zero, rodando migrations e seeders. Perfeito para desenvolvimento local ou ambientes de teste.</p>
<h2>Boas Práticas e Casos Reais</h2>
<p>Em projetos reais, você terá migrações complexas com relacionamentos, índices e constraints. Sempre crie relacionamentos corretamente:</p>
<pre><code class="language-php">Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('content');
$table->foreignId('user_id')->constrained('users')->onDelete('cascade');
$table->timestamps();
$table->index('user_id');
$table->fullText('title', 'content'); // para busca
});</code></pre>
<p>Use <code>foreignId()</code> e <code>constrained()</code> para criar foreign keys com integridade referencial. O <code>onDelete('cascade')</code> garante que posts sejam deletados se o usuário for deletado.</p>
<p>Para dados sensíveis ou padrões em produção, considere separar seeders de desenvolvimento:</p>
<pre><code class="language-bash">php artisan make:seeder --seed=local AdminUserSeeder</code></pre>
<p>Coloque dados reais apenas em seeders específicos, nunca hardcode credenciais. Use variáveis de ambiente quando necessário dados sensíveis.</p>
<h2>Conclusão</h2>
<p>Migrations e seeders são pilares de um workflow profissional em Laravel. <strong>Primeiro ponto</strong>: migrations dão versionamento e reversibilidade ao seu schema — sempre use migrations, nunca SQL direto em produção. <strong>Segundo ponto</strong>: combine seeders com factories para popular dados de forma escalável e mantível. <strong>Terceiro ponto</strong>: organize seu DatabaseSeeder para orquestrar múltiplos seeders em ordem lógica, e sempre teste <code>migrate:fresh --seed</code> antes de fazer deploy.</p>
<p>Domine estes conceitos agora e você terá uma base sólida para trabalhar com Laravel em qualquer escala.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://laravel.com/docs/migrations" target="_blank" rel="noopener noreferrer">Laravel Migrations - Documentação Oficial</a></li>
<li><a href="https://laravel.com/docs/seeding" target="_blank" rel="noopener noreferrer">Laravel Database Seeding - Documentação Oficial</a></li>
<li><a href="https://laravel.com/docs/eloquent-factories" target="_blank" rel="noopener noreferrer">Laravel Model Factories - Documentação Oficial</a></li>
<li><a href="https://github.com/fzaninotto/Faker" target="_blank" rel="noopener noreferrer">Using Faker for Realistic Test Data</a></li>
<li><a href="https://laravel.com/docs/database-testing" target="_blank" rel="noopener noreferrer">Laravel Database Testing Best Practices</a></li>
</ul>