Curso de Laravel
Seeders en Laravel: poblar la base de datos
Por Víctor Peña · Publicado el
Hola, ¿cómo están? Continuando con el curso de Laravel, hoy veremos los seeders: la forma de llenar la base de datos con información sin escribir un solo INSERT a mano.
¡Empecemos!
Para qué sirven
Si las migraciones versionan la estructura de la base, los seeders versionan los datos que siempre deben estar ahí.
Dos usos que conviene distinguir desde el principio:
Datos de prueba. Necesitas cincuenta pacientes para ver cómo se comporta la paginación. No vas a crearlos a mano.
Datos reales del sistema. Hay información que la aplicación necesita para funcionar: las especialidades médicas, los roles de usuario, los estados de un pedido, los departamentos del país. Sin ellos el sistema no arranca.
Ese segundo caso es el más importante y el que más se pasa por alto. Un compañero que clona el proyecto debe poder tenerlo funcionando con dos comandos.
Crear un seeder
php artisan make:seeder EspecialidadSeeder
Se crea en database/seeders/:
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use App\Models\Especialidad;
class EspecialidadSeeder extends Seeder
{
public function run(): void
{
$especialidades = [
['nombre' => 'Cardiología', 'descripcion' => 'Corazón y sistema circulatorio'],
['nombre' => 'Pediatría', 'descripcion' => 'Atención médica a niños'],
['nombre' => 'Traumatología', 'descripcion' => 'Huesos y articulaciones'],
['nombre' => 'Dermatología', 'descripcion' => 'Enfermedades de la piel'],
];
foreach ($especialidades as $especialidad) {
Especialidad::create($especialidad);
}
}
}
Y se ejecuta:
php artisan db:seed --class=EspecialidadSeeder
El DatabaseSeeder
Es el seeder principal, el que se ejecuta por defecto. Desde ahí se llaman los demás:
class DatabaseSeeder extends Seeder
{
public function run(): void
{
$this->call([
EspecialidadSeeder::class,
DoctorSeeder::class,
PacienteSeeder::class,
CitaSeeder::class,
]);
}
}
php artisan db:seed
El orden importa. Si DoctorSeeder crea doctores con su especialidad_id, las especialidades tienen que existir antes. Es la misma lógica de las claves foráneas que vimos en MySQL.
El comando que más vas a usar
php artisan migrate:fresh --seed
Borra todas las tablas, vuelve a crearlas y ejecuta los seeders. En una máquina de desarrollo es lo que usas cada vez que quieres empezar limpio.
Y el aviso de siempre: en producción borra todos los datos. Antes de escribirlo, mira en qué entorno estás.
Insertar muchos registros
Crear los registros uno por uno con create() es cómodo pero lento: cada llamada es una consulta a la base.
Para volúmenes grandes, insert() hace una sola consulta:
public function run(): void
{
$registros = [];
for ($i = 1; $i <= 1000; $i++) {
$registros[] = [
'nombre' => "Paciente $i",
'cedula' => str_pad((string) $i, 7, '0', STR_PAD_LEFT),
'created_at' => now(),
'updated_at' => now(),
];
}
Paciente::insert($registros);
}
Dos advertencias sobre insert():
- No dispara los eventos del modelo ni aplica los casts. Es SQL casi directo.
- Hay que poner
created_atyupdated_ata mano, porque Eloquent no interviene.
Y si son decenas de miles, insértalos por lotes para no agotar la memoria:
foreach (array_chunk($registros, 500) as $lote) {
Paciente::insert($lote);
}
Seeders para datos reales del sistema
Aquí está el uso más valioso, y conviene escribirlos de forma que se puedan ejecutar más de una vez sin duplicar:
class EstadoCitaSeeder extends Seeder
{
public function run(): void
{
$estados = ['programada', 'atendida', 'cancelada', 'reprogramada'];
foreach ($estados as $estado) {
EstadoCita::firstOrCreate(['nombre' => $estado]);
}
}
}
Ese firstOrCreate() es la clave: si el estado ya existe, no hace nada. Así puedes ejecutar el seeder en producción cuando añadas un estado nuevo, sin miedo a duplicar los existentes.
Es la forma correcta de introducir datos de catálogo en un sistema ya desplegado.
Seeders con relaciones
class CitaSeeder extends Seeder
{
public function run(): void
{
$pacientes = Paciente::all();
$doctores = Doctor::all();
foreach ($pacientes as $paciente) {
Cita::create([
'paciente_id' => $paciente->id,
'doctor_id' => $doctores->random()->id,
'fecha' => now()->addDays(rand(1, 30)),
'hora' => '09:00:00',
'costo' => 250,
'estado' => 'programada',
]);
}
}
}
Fíjate en $doctores->random(): las colecciones de Eloquent traen métodos muy cómodos para este tipo de cosas.
Distinguir por entorno
Un seeder puede comportarse distinto según dónde se ejecute:
public function run(): void
{
// Datos que el sistema necesita siempre
$this->call([
EspecialidadSeeder::class,
RolSeeder::class,
]);
// Datos de prueba, solo fuera de producción
if (! app()->environment('production')) {
$this->call([
PacienteDePruebaSeeder::class,
CitaDePruebaSeeder::class,
]);
}
}
Esa separación evita el accidente de llenar producción con «Paciente 1», «Paciente 2».
Usar factories desde un seeder
Escribir a mano cincuenta pacientes con datos creíbles es tedioso. Para eso están los factories, que veremos en la siguiente lección, pero adelanto cómo se combinan:
public function run(): void
{
Paciente::factory()->count(50)->create();
}
Una línea, cincuenta pacientes con nombres, cédulas y teléfonos verosímiles.
La división de trabajo: el factory define cómo se ve un registro de prueba; el seeder decide cuántos y en qué orden.
Un seeder con salida en pantalla
Para seeders que tardan, conviene informar:
public function run(): void
{
$this->command->info('Creando pacientes...');
$barra = $this->command->getOutput()->createProgressBar(1000);
for ($i = 0; $i < 1000; $i++) {
Paciente::factory()->create();
$barra->advance();
}
$barra->finish();
$this->command->info("\nListo.");
}
Errores comunes
- Orden incorrecto en el
DatabaseSeeder, fallando por clave foránea. - No usar
firstOrCreate()en datos de catálogo, y duplicarlos al reejecutar. - Insertar miles de registros uno por uno en lugar de por lotes.
- Ejecutar
migrate:fresh --seeden producción. - Mezclar datos de prueba con datos del sistema en el mismo seeder.
- Olvidar
created_atal usarinsert().
Para cerrar
Los seeders convierten «clona el proyecto y pídeme el volcado de la base» en «clona el proyecto y ejecuta dos comandos». Eso es lo que hacen valiosos.
La distinción que quiero que te lleves: datos de catálogo con firstOrCreate() para poder reejecutar, y datos de prueba separados y solo fuera de producción.
En la siguiente lección veremos los factories, que generan datos falsos verosímiles.
Saludos y éxitos.
Norvic Software
Desarrollamos el software que tu empresa necesita
Somos una fábrica de software en Bolivia. Construimos sistemas a medida y aplicaciones móviles, y llevamos Inteligencia Artificial a las empresas que ya tienen un sistema funcionando.
- Chatbots con Inteligencia Artificial
- Creación de agentes de IA
- Integración de IA en tus sistemas
- Desarrollo de software a medida
- Aplicaciones móviles iOS y Android
- Consultoría y asesoramiento técnico
Cotización sin costo · Respuesta directa por WhatsApp