laravel_migraciones_y_seeders

Seguimos adentrándonos en el mundo de las bases de datos con Laravel.

En esta ocasión vamos a adentrarnos en dos utilidades a las que a mi me gusta llamar "utilidades de la nueva escuela".

A los que venimos de la programación de principios del 2000, con bases de datos relacionales, nos chocan un poco los conceptos que vamos a ver hoy. Y es que tener un control de versiones en la base de datos nos puede sonar un poco a chino.

Antes que nada, para que no perdáis el hilo, os dejo por aquí toda la serie, por si habéis llegado directamente a este artículo y os interesa profundizar en el mundo de Laravel:

Hoy nos metemos de lleno en dos conceptos, las migraciones y los seeders.

Los que lleváis años en esto de la programación, seguro que os habéis llevado más de un susto cuando en local, habéis tenido que añadir una o varias columnas a la base de datos y en el momento de poner el código en producción: ¡zasca!, en código no funciona. Se nos ha olvidado crear la/las columnas pertinentes en la base de datos de producción.

Esto sin hablar de las pruebas, en las que metemos registros "fake" en la base de datos. Posteriormente borramos un registro aquí, cambiamos otro registro allá; y ¿cómo volvemos a tener todos estos registros iniciales para hacer pruebas?

Las migraciones

Las migraciones de bases de datos vienen a dar solución a un problema intrínseco del periodo de pruebas, y es que nos permiten volver a una versión de la estructura de base de datos en cualquier momento.

Las migraciones nos dan la posibilidad de crear un histórico de creación, modificación y eliminación de elementos de la base de datos (expresamente de la estructura), para que si en algún momento cambiamos la estructura de la misma, podamos volver a una versión anterior en el tiempo.

Imaginaos que tenemos una base de datos sencillita en la que sólo existen tres tablas: usuarios, productos y clientes.

En un ejemplo de los pasos que daríamos para crear la estructura a través de la historia del desarrollo de la aplicación, podríamos tener algo como esto:

  • Creamos la tabla de usuarios con los campos: id, nombre, apellidos, email.
  • Creamos la tabla de productos con los campos: id, nombre, precio.
  • Creamos la tabla de clientes con los campos: id, nombre, email.
  • Añadimos una columna a la tabla de productos: stock.
  • El encargado de proyecto nos pide que añadamos una columna a la tabla de clientes: CIF.

Dependiendo del modo en el que programemos esta aplicación, nos podemos encontrar con estos escollos a la hora de modificar la estructura de la base de datos:

  • Si trabajamos en equipo, hay que ir comunicando a todos los integrantes los cambios en la base de datos para que a mano, vayan añadiendo tablas y columnas. No sólo esto, hay que comunicarles el tipo de dato de la columna, longitud, comentarios, etc.
  • Tenemos la posibilidad de exportar la base de datos e importarla en la base de datos del compañero, pero nos arriesgamos a que nuestro compañero, en su local, haya introducido datos de prueba que se eliminarían a la hora de importar la base de datos.
  • En producción, si tenemos ya una versión de la aplicación, es arriesgado tener que introducir las columnas a mano, es muy posible que fallemos.

Y sí, me diréis que así se han hecho las cosas siempre, pero ¿qué pasa cuando tenemos una solución para esto? Una utilidad en nuestro código en la que gracias a un comando podamos recrear la estructura de la base de datos en cualquier momento.

¿No sería maravilloso?

Pues aquí encajan las migraciones. Vamos a ver un ejemplo básico de creación de una migración.

Lo primero, vamos a crear una tabla de usuarios en nuestra base de datos. Tened en cuenta que ya hemos configurado la conexión a la base de datos, y de esto se ayudan las migraciones. Si andáis un poco perdidos respecto a este tema, visitad el artículo: Laravel series III (tenéis los links al inicio de este artículo), dónde os explico cómo configurar la conexión a la base de datos.

Gracias Artisan, vamos a crear nuestra primera migración, ejecutemos este comando:

php artisan make:migration create_users_table

Este comando nos crea nuestra primera migración en la ruta que contiene las migraciones: database\migrations.

El nombre del archivo correspondiente a esta migración contendrá un timestamp para que Laravel sea capaz de saber el orden de ejecución de las migraciones (al fin de al cabo tiene sentido crear primero las tablas y después modificar sus columnas, por ejemplo).

Así es como se ve el código de la migración:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('usuarios', function (Blueprint $table) {
            $table->id();
            $table->string('nombre');
            $table->string('apellidos');
            $table->string('email');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('usuarios');
    }
}

Como ya habréis podido comprobar, Laravel realizar las llamadas de librerías necesarias y además extiende la clase "Migration".

Estoy seguro que también habéis caído en la cuenta de que esta clase incluye dos métodos: up y down. Y es que sí, las migraciones no sólo se ejecutan hacia delante en el tiempo, sino que podemos revertirlas.

up es el método que se lanza cuando ejecutamos una migración, en este caso estamos creando la tabla usuarios. Pero cuando hacemos un retroceso (rollback) de la migración, porque ya hayamos ejecutado las migraciones pero queramos que se ejecuten de nuevo todas desde el principio, se ejecutará el método down.

Es por esta razón por la que vemos que el método up crea la tabla y el método down la destruye.

Para ejecutar las migraciones contenidas en database\migrations, ejecutamos el siguiente comando:

php artisan migrate

Para hacer un rollback y volver al estado inicial de la base de datos (antes de lanzar las migraciones), ejecutamos el comando:

php artisan migrate:rollback

Ahora sólo nos queda ir creando migraciones para cada una de las modificaciones de la base de datos.

Cabe decir que las migraciones no sólo crean tablas, se utilizan para eliminar columnas, modificar tipos, etc.

Una vez despleguemos nuestro código en producción o nuestro compañero actualice su código con el nuestro (a través de GIT por ejemplo), solo será necesario ejecutar todas las migraciones para tener la misma estructura de datos en todos los lugares y sin tener ningún tipo de preocupación por si tenemos la misma versión de la base de datos en local y producción, o entre integrantes del grupo de programadores.

Los Seeders

Si ya hemos visto que gracias a la migraciones podemos tener una estructura de base de datos homogénea, ¿qué pasa con los registros incluidos en la base de datos?

¡Seeders al rescate!

Respecto a los registros de la base de datos nos encontramos con al menos un par de situaciones que nos suelen incordiar:

  • Tenemos una serie de registros de pega para hacer pruebas y con el tiempo estos registros se modifican y queremos volver a su estado inicial.
  • Hay ciertas tablas que tienen datos fijos (una tabla de países por ejemplo) y no queremos tener un script de motor de base de datos a parte para rellenar esa tabla (o tener que rellenarla con los datos definitivos a mano constantemente).

Pues bien, los seeders (algo así como "sembrador" en español) son algo parecido a las migraciones pero con registros introducidos dentro de la base de datos. Sólo que en este caso nos haremos rollback, simplemente las tablas serán rellenas con los datos especificados.

El ejemplo de los países es bastante claro, es una tabla que siempre tenemos que rellenar y que aunque durante la fase de testing cambiemos estos datos, cuando llevamos al código a producción, queremos que tenga el contenido inicial con todos sus registros limpios.

Teniendo en cuenta que ya hemos creado una tabla de países a través de una migración (esta tabla tiene las columnas: id, nombre), vamos a crear el seeder para la tabla.

Este comando nos crea un seeder en la ruta que contiene a los mismos: database\seeders

php artisan make:seeder CountriesSeeder

Este comando nos crea el siguiente seeder que completaremos con la tabla que plataremos con datos y los datos en sí:

<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;

class CountriesSeeder extends Seeder
{
    /**
     * Run the database seeders.
     *
     * @return void
     */
    public function run()
    {
        DB::table('paises')->insert([
            'name' => "España"
        ]);
    }
}

En este caso sólo hemos añadido un páis, España, pero os podéis imaginar como podemos rellenarla con todos los países que deseemos.

Las posibilidades son varias, desde traernos los mismos desde una API, rellenar un array y recorrerlo, etc.

Para ejecutar nuestros seeders ejecutaremos el siguiente comando:

php artisan db:seed

Si queremos ejecutar un seed en concreto:

php artisan db:seed --class=CountriesSeeder

Y como colofón final, si queremos ejecutar todas las migraciones y los seeders, tenemos un comando que hace que nuestra base de datos luzca como nueva (recién salidita de la ducha):

php artisan migrate:fresh --seed

Espero que este artículo os haya abierto un poco la mente sobre la utilidad de estos elementos a la hora de tratar con estructura y registros en nuestra base de datos.

¡Nos vemos en el siguiente fragmento de código!


Escrito por Juan José Ramos

Soy programador web, artesano del código y estudiante incansable. Aunque mi carrera siempre ha ido ligada al backend , últimamente me estoy dejando llevar por las lindezas del front.
No hay nada que me guste más que indentar y pulsar [ENTER] ;).
comments powered by Disqus