Laravel
Tutorial Laravel: Migraciones y Seeders
Laravel: Aprende a gestionar cambios en la base de datos utilizando migraciones, asegurando la coherencia y fácil mantenimiento del proyecto PHP.
Aprende Laravel y certifícateCreación y ejecución de migraciones
En Laravel, las migraciones son una forma eficiente de gestionar el esquema de la base de datos. Permiten versionar y controlar los cambios estructurales, facilitando la colaboración y el mantenimiento del proyecto. Las migraciones se escriben en PHP y se integran en el sistema de control de versiones, lo que asegura coherencia entre los diferentes entornos de desarrollo.
Para crear una nueva migración, se utiliza el comando Artisan make:migration
. Por ejemplo, para generar una migración que cree una tabla usuarios
, ejecuta:
php artisan make:migration create_usuarios_table --create=usuarios
Este comando genera un archivo de migración en el directorio database/migrations
. El archivo contiene dos métodos: up
y down
. El método up
define los cambios a aplicar, mientras que down
especifica cómo revertirlos.
Para definir la estructura de la tabla usuarios
, edita el método up
:
public function up()
{
Schema::create('usuarios', function (Blueprint $table) {
$table->id();
$table->string('nombre');
$table->string('email')->unique();
$table->string('contraseña');
$table->timestamps();
});
}
En este ejemplo, se establece un esquema con campos comunes como nombre
, email
y contraseña
. El método timestamps()
añade automáticamente las columnas created_at
y updated_at
.
Una vez definida la migración, puedes ejecutarla utilizando el comando:
php artisan migrate
Este comando aplica todas las migraciones pendientes a la base de datos configurada en el archivo .env
. Laravel registra las migraciones ejecutadas en la tabla migrations
para evitar duplicidades.
Si necesitas crear una migración para modificar una tabla existente, como añadir una columna telefono
a la tabla usuarios
, utiliza:
php artisan make:migration add_telefono_to_usuarios_table --table=usuarios
Luego, en el método up
, agrega la nueva columna:
public function up()
{
Schema::table('usuarios', function (Blueprint $table) {
$table->string('telefono')->nullable();
});
}
Y en el método down
, defines cómo eliminarla:
public function down()
{
Schema::table('usuarios', function (Blueprint $table) {
$table->dropColumn('telefono');
});
}
Para aplicar esta migración, vuelve a ejecutar:
php artisan migrate
Si deseas revertir la última migración ejecutada, utiliza:
php artisan migrate:rollback
Este comando llama al método down
de la migración más reciente. Para revertir todas las migraciones y volver a ejecutarlas, puedes usar:
php artisan migrate:refresh
Esto es útil cuando necesitas restablecer el estado de la base de datos durante el desarrollo.
Es posible también ejecutar migraciones específicas indicando su ruta:
php artisan migrate --path=/database/migrations/2024_01_01_000000_create_usuarios_table.php
Utilizar migraciones permite mantener un historial detallado de los cambios en el esquema y facilita la implementación de nuevas funcionalidades. Además, garantiza que todos los entornos de desarrollo y producción estén sincronizados en cuanto a la estructura de la base de datos.
Para confirmar que las migraciones se han ejecutado correctamente, puedes consultar la tabla migrations
en tu base de datos o utilizar el comando:
php artisan migrate:status
Este comando muestra una lista de todas las migraciones y su estado actual.
Al integrar las migraciones en el flujo de trabajo, aseguras una gestión eficaz y controlada de los cambios en el esquema, lo que es fundamental para el éxito a largo plazo de un proyecto Laravel.
Modificación de tablas existentes
Modificar tablas existentes en Laravel es una tarea común que se realiza mediante migraciones. Las migraciones permiten mantener el control de los cambios en la estructura de la base de datos de forma segura y organizada. A continuación, se detallan diferentes operaciones que se pueden realizar para modificar tablas ya creadas.
Para modificar una tabla existente, se crea una nueva migración específica para dicha modificación. Por ejemplo, si necesitamos cambiar el nombre de una columna en la tabla usuarios
, primero generamos la migración con el comando Artisan:
php artisan make:migration rename_nombre_to_nombre_completo_in_usuarios_table --table=usuarios
En el archivo de migración generado, utilizamos el método renameColumn
dentro del método up
:
public function up()
{
Schema::table('usuarios', function (Blueprint $table) {
$table->renameColumn('nombre', 'nombre_completo');
});
}
Es importante destacar que para renombrar columnas, Laravel requiere el paquete doctrine/dbal. Se instala mediante Composer ejecutando:
composer require doctrine/dbal
Este paquete proporciona las herramientas necesarias para que Laravel pueda manipular las columnas existentes de la base de datos.
Si queremos cambiar el tipo de dato de una columna, como ampliar el tamaño del campo email
, modificamos la migración de la siguiente manera:
public function up()
{
Schema::table('usuarios', function (Blueprint $table) {
$table->string('email', 255)->change();
});
}
El método change()
indica que se está alterando una columna existente. Así, establecemos el nuevo tamaño para el campo email
. Recuerda que al cambiar tipos de datos, también es necesario tener instalado doctrine/dbal.
Para añadir nuevas columnas a una tabla, podemos simplemente agregarlas en la migración:
public function up()
{
Schema::table('usuarios', function (Blueprint $table) {
$table->date('fecha_nacimiento')->nullable();
});
}
En caso de que necesitemos eliminar una columna, utilizamos el método dropColumn
:
public function up()
{
Schema::table('usuarios', function (Blueprint $table) {
$table->dropColumn('telefono');
});
}
Si queremos renombrar una tabla completa, empleamos el método rename
:
public function up()
{
Schema::rename('usuarios', 'clientes');
}
Este cambio se reflejará en todas las operaciones futuras sobre la tabla renombrada. Es fundamental revisar el código para actualizar las referencias a la nueva tabla clientes
.
Para modificar varios aspectos de una tabla en una sola migración, podemos combinar las operaciones:
public function up()
{
Schema::table('usuarios', function (Blueprint $table) {
$table->string('apellidos')->after('nombre');
$table->integer('edad')->nullable();
$table->dropColumn('contraseña');
});
}
Con el método after('nombre')
, indicamos que la nueva columna apellidos
se insertará inmediatamente después de la columna nombre
. Esto es útil para mantener un orden lógico en las columnas de la tabla.
Al realizar modificaciones, es buena práctica siempre definir el método down
para revertir los cambios si es necesario. Por ejemplo:
public function down()
{
Schema::table('usuarios', function (Blueprint $table) {
$table->string('contraseña');
$table->dropColumn(['apellidos', 'edad']);
});
}
Es esencial ejecutar las migraciones después de crearlas para aplicar los cambios a la base de datos:
php artisan migrate
Además de modificar columnas y tablas, también se pueden agregar o modificar índices y claves foráneas. Por ejemplo, para añadir un índice único al campo email
:
public function up()
{
Schema::table('usuarios', function (Blueprint $table) {
$table->unique('email');
});
}
Y para eliminar un índice:
public function up()
{
Schema::table('usuarios', function (Blueprint $table) {
$table->dropUnique(['email']);
});
}
Para crear una columna de clave foránea y definir la relación, se hace lo siguiente:
public function up()
{
Schema::table('usuarios', function (Blueprint $table) {
$table->unsignedBigInteger('rol_id');
$table->foreign('rol_id')->references('id')->on('roles')->onDelete('cascade');
});
}
Esto añade una columna rol_id
y establece una clave foránea con la tabla roles
. El método onDelete('cascade')
asegura que si se elimina un rol, también se eliminarán los usuarios asociados.
Es posible modificar una clave foránea existente utilizando los métodos dropForeign
y luego crear la nueva clave:
public function up()
{
Schema::table('usuarios', function (Blueprint $table) {
$table->dropForeign(['rol_id']);
$table->foreign('rol_id')->references('id')->on('nuevos_roles');
});
}
Para eliminar una tabla completa, utilizamos el método dropIfExists
:
public function up()
{
Schema::dropIfExists('usuarios');
}
Sin embargo, esta operación es destructiva y debe utilizarse con precaución, especialmente en entornos de producción.
Las migraciones permiten realizar cambios graduales y controlados en la estructura de la base de datos. Es fundamental planificar y probar las modificaciones antes de aplicarlas, para evitar pérdidas de datos o inconsistencias.
Finalmente, para listar todas las migraciones pendientes de ejecución, se puede utilizar:
php artisan migrate:status
Con este comando, verificamos el estado de las migraciones y aseguramos que todas las modificaciones necesarias han sido aplicadas.
En resumen, la modificación de tablas existentes en Laravel se realiza de manera controlada mediante migraciones, aprovechando las herramientas que el framework proporciona para mantener una base de datos coherente y bien estructurada.
Uso de seeders para poblar datos
Los seeders en Laravel son clases que permiten poblar la base de datos con datos iniciales o de pruebas. Facilitan la inserción de registros de manera automatizada, lo que es especialmente útil durante el desarrollo y las pruebas de una aplicación.
Para crear un seeder, se utiliza el comando Artisan make:seeder
. Por ejemplo, para generar un seeder para la tabla usuarios
, ejecuta:
php artisan make:seeder UsuariosSeeder
Este comando crea una clase UsuariosSeeder
en el directorio database/seeders
. En esta clase, se define el método run
donde se especifican las operaciones de inserción de datos.
Dentro del método run
, puedes utilizar los modelos de Eloquent para insertar registros. Por ejemplo:
public function run()
{
Usuario::create([
'nombre' => 'Juan Pérez',
'email' => 'juan.perez@example.com',
'contraseña' => bcrypt('contraseña123'),
]);
Usuario::create([
'nombre' => 'María García',
'email' => 'maria.garcia@example.com',
'contraseña' => bcrypt('contraseña456'),
]);
}
En este ejemplo, se están creando dos instancias del modelo Usuario
, insertando registros en la tabla usuarios
. Es importante utilizar el método bcrypt
para encriptar las contraseñas antes de almacenarlas.
Para ejecutar el seeder, se debe llamar desde la clase DatabaseSeeder
, que se encuentra en el mismo directorio database/seeders
. Modifica el método run
de DatabaseSeeder
para incluir la llamada a UsuariosSeeder
:
public function run()
{
$this->call(UsuariosSeeder::class);
}
Ahora, puedes ejecutar todos los seeders definidos en DatabaseSeeder
utilizando el comando Artisan:
php artisan db:seed
Este comando ejecuta el método run
de DatabaseSeeder
, que a su vez llama a los seeders especificados. De esta manera, se pueblan las tablas con los datos definidos.
En caso de que necesites ejecutar un seeder específico sin pasar por DatabaseSeeder
, puedes utilizar:
php artisan db:seed --class=UsuariosSeeder
Esto es útil cuando quieres probar un seeder individualmente o cuando no deseas ejecutar todos los seeders disponibles.
Los seeders también pueden aprovechar las colecciones para insertar múltiples registros de manera más eficiente. Por ejemplo:
public function run()
{
$usuarios = [
['nombre' => 'Luis Fernández', 'email' => 'luis.fernandez@example.com', 'contraseña' => bcrypt('contraseña789')],
['nombre' => 'Ana López', 'email' => 'ana.lopez@example.com', 'contraseña' => bcrypt('contraseña012')],
];
foreach ($usuarios as $usuario) {
Usuario::create($usuario);
}
}
O incluso utilizando el método insert
para una inserción masiva:
public function run()
{
DB::table('usuarios')->insert([
['nombre' => 'Carlos Ruiz', 'email' => 'carlos.ruiz@example.com', 'contraseña' => bcrypt('contraseña345')],
['nombre' => 'Laura Sánchez', 'email' => 'laura.sanchez@example.com', 'contraseña' => bcrypt('contraseña678')],
]);
}
Es importante tener en cuenta que al utilizar el modelo directamente, eventos como los observadores y mutadores se ejecutarán, mientras que al utilizar el constructor de consultas con DB::table
, estos no se aplican.
Para resetear la base de datos y volver a ejecutar las migraciones y seeders, puedes usar el comando:
php artisan migrate:fresh --seed
Este comando elimina todas las tablas, vuelve a ejecutar las migraciones y los seeders, permitiendo empezar desde un estado limpio. Es especialmente útil durante el desarrollo cuando necesitas reiniciar el estado de la base de datos.
Además, los seeders pueden ser utilizados para poblar tablas relacionadas. Por ejemplo, si tienes una tabla posts
que depende de usuarios
, podrías crear un PostsSeeder
que asigne posts a usuarios existentes:
public function run()
{
$usuarios = Usuario::all();
foreach ($usuarios as $usuario) {
Post::create([
'titulo' => 'Título de ejemplo',
'contenido' => 'Contenido del post.',
'usuario_id' => $usuario->id,
]);
}
}
De esta manera, aseguras que los datos sean coherentes y las relaciones estén correctamente establecidas.
Es recomendable organizar los seeders de forma que sean reutilizables y que reflejen la estructura de la base de datos. Puedes crear seeders para cada tabla y llamarlos desde DatabaseSeeder
en el orden adecuado para respetar las dependencias entre tablas.
Los seeders son una herramienta esencial para mantener el control de los datos de prueba y facilitan el proceso de desarrollo al automatizar la carga de datos iniciales. Al integrarlos en el flujo de trabajo, mejoras la eficiencia y aseguras la consistencia entre los distintos entornos de desarrollo y pruebas.
Factories y datos de prueba
Los factories en Laravel son una herramienta esencial para generar datos de prueba de manera eficiente y estructurada. Permiten crear instancias de modelos con atributos predefinidos o aleatorios, facilitando la inserción de registros en la base de datos durante el desarrollo y las pruebas automatizadas.
Para crear un factory, se utiliza el comando Artisan make:factory
. Por ejemplo, para generar un factory para el modelo Usuario
, ejecuta:
php artisan make:factory UsuarioFactory --model=Usuario
Este comando crea una clase UsuarioFactory
en el directorio database/factories
. La opción --model=Usuario
indica que el factory está asociado al modelo Usuario
, lo que facilita la generación de instancias de este modelo.
En el archivo generado, se define el método definition
, que retorna un arreglo con los valores por defecto para cada atributo del modelo:
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class UsuarioFactory extends Factory
{
protected $model = Usuario::class;
public function definition()
{
return [
'nombre' => $this->faker->name,
'email' => $this->faker->unique()->safeEmail,
'contraseña' => bcrypt('contraseña'), // Contraseña por defecto
'remember_token' => Str::random(10),
];
}
}
El objeto $this->faker
es una instancia de Faker, una biblioteca que genera datos aleatorios y realistas para una amplia variedad de campos, como nombres, correos electrónicos y números de teléfono.
Una vez definido el factory, puedes utilizarlo para crear instancias del modelo Usuario
en tus pruebas o seeders. Por ejemplo, para crear un solo usuario:
$usuario = Usuario::factory()->create();
Este método crea un registro en la base de datos con los datos generados por el factory. Si deseas crear un usuario sin guardar en la base de datos, utiliza:
$usuario = Usuario::factory()->make();
El método make()
crea una instancia del modelo pero no la persiste en la base de datos. Para crear múltiples usuarios, simplemente indica la cantidad deseada:
$usuarios = Usuario::factory()->count(10)->create();
Esto generará y guardará diez usuarios en la base de datos.
Los factories se integran perfectamente con los seeders para poblar la base de datos con datos de prueba de manera eficiente. En el seeder UsuariosSeeder
, puedes utilizar el factory para generar múltiples usuarios:
public function run()
{
Usuario::factory()->count(50)->create();
}
Este código inserta cincuenta usuarios con datos aleatorios en la tabla usuarios
. Si deseas personalizar algún atributo, puedes pasar un arreglo al método create()
:
Usuario::factory()->create([
'nombre' => 'Pedro Martínez',
'email' => 'pedro.martinez@example.com',
]);
En este caso, los campos nombre
y email
serán los especificados, mientras que el resto serán generados aleatoriamente por el factory.
Los factories permiten definir estados para generar variaciones de los datos de prueba. Por ejemplo, podrías definir un estado para usuarios verificados:
public function verificado()
{
return $this->state(function (array $attributes) {
return [
'email_verificado_en' => now(),
];
});
}
Con este estado definido en el factory, puedes generar usuarios verificados de la siguiente manera:
$usuariosVerificados = Usuario::factory()
->count(5)
->verificado()
->create();
Los factories también pueden generar modelos relacionados automáticamente. Supongamos que cada Usuario
tiene varios Post
. Puedes configurar el factory de Post
para crear posts asociados a usuarios existentes:
class PostFactory extends Factory
{
protected $model = Post::class;
public function definition()
{
return [
'titulo' => $this->faker->sentence,
'contenido' => $this->faker->paragraph,
'usuario_id' => Usuario::factory(),
];
}
}
Al indicar 'usuario_id' => Usuario::factory()
, se crea un nuevo usuario cada vez que se genera un post. Para asociar posts a un usuario específico, utiliza el método for()
:
$usuario = Usuario::factory()->create();
Post::factory()
->count(3)
->for($usuario)
->create();
El método for($usuario)
asocia los posts generados al usuario indicado. Esto es útil para crear datos de prueba que reflejen relaciones reales entre modelos.
En las pruebas automatizadas, los factories son especialmente útiles para preparar el entorno de forma rápida y consistente. Por ejemplo:
public function test_crear_post()
{
$usuario = Usuario::factory()->create();
$response = $this->actingAs($usuario)
->post('/posts', [
'titulo' => 'Mi primer post',
'contenido' => 'Contenido del post.',
]);
$response->assertStatus(201);
$this->assertDatabaseHas('posts', [
'titulo' => 'Mi primer post',
'usuario_id' => $usuario->id,
]);
}
En este ejemplo, se crea un usuario de prueba y se verifica que pueda crear un post correctamente. Los factories facilitan la creación de instancias del modelo sin tener que definir manualmente cada atributo.
Para obtener datos de prueba más realistas en español, puedes configurar el locale de Faker en el archivo config/app.php
:
'faker_locale' => 'es_ES',
Esto hará que Faker genere nombres, direcciones y otros datos en español de España, aumentando la relevancia de los datos generados.
Para regenerar la base de datos y poblarla con datos de prueba utilizando migraciones, seeders y factories, puedes ejecutar:
php artisan migrate:fresh --seed
Este comando elimina todas las tablas, ejecuta las migraciones y luego los seeders, asegurando que la base de datos esté en un estado limpio y consistente.
Los datos de prueba generados con factories son fundamentales para el desarrollo y las pruebas, ya que permiten simular escenarios reales y detectar posibles errores o inconsistencias. Al integrar factories en tu flujo de trabajo, mejoras la eficiencia y la calidad de tu aplicación Laravel.
Todas las lecciones de Laravel
Accede a todas las lecciones de Laravel y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.
Introducción A Php Laravel
Introducción Y Entorno
Instalación Y Configuración Laravel
Introducción Y Entorno
Controladores Mvc
Controladores Http
Vistas Y Blade Templates
Controladores Http
Formularios Y Validación
Controladores Http
Controladores Rest
Controladores Http
Middleware Y Control De Solicitudes
Persistencia
Seguridad Autenticación Y Autorización
Persistencia
Bases De Datos Y Eloquent Orm
Persistencia
Relaciones Entre Modelos
Persistencia
Consultas Avanzadas
Persistencia
Colecciones Y Métodos Avanzados
Persistencia
Migraciones Y Seeders
Persistencia
Sistema De Autenticación Nativo Laravel
Middlewares Y Seguridad
Autorización (Policies Y Gates)
Middlewares Y Seguridad
Csrf Y Protección De Formularios En Blade
Middlewares Y Seguridad
Validaciones De Datos En Controladores Y Formularios
Middlewares Y Seguridad
Cifrado De Contraseñas
Middlewares Y Seguridad
Autenticación Jwt En Api Rest
Middlewares Y Seguridad
Pruebas Unitarias Con Phpunit
Testing
Pruebas De Integración En Laravel
Testing
En esta lección
Objetivos de aprendizaje de esta lección
- Comprender qué son las migraciones en Laravel y su finalidad.
- Generar nuevas migraciones para crear tablas.
- Modificar tablas existentes mediante migraciones.
- Aplicar y revertir migraciones con Artisan.
- Configurar y entender el ciclo de vida de una migración.