Migraciones de base de datos en laravel
Las migraciones en laravel son lo más parecido a un sistema de control de versiones para una base de datos. Éstas permiten llevar un control sobre los cambios realizados al esquema de base de datos y brindan un mecanismo para la instalación de dichos cambios de manera automatizada.
Cuántas veces hemos tenido que realizar un script de instalación para modificar o agregar algún campo en la base de datos en un sistema de producción?. Cómo saber si dicho cambio ya fue instalado?. Las migraciones en Laravel buscan resolver algunas preguntas que surgen de este escenario como la sisguientes:
- Se puede automatizar el efectuar un cambio en base de datos?
- Es posible saber si se ejecutó un cambio en la base de datos?
- Es posible realizar un rollback de dicho cambio?
- Se puede realizar seguimiento de los cambios en base de datos?
Veamos pues en que consisten las migraciones.
Creación de migraciones
El comando general para crear una migración es el siguiente:
php artisan make:migration migration_name
En donde migration_name
es el nombre de la migración que deseamos crear. Asi que para ver en qué consiste una migración vamos a ejecutar el siguiente comando en un proyecto configurado con laravel.
php artisan make:migration tabla_catalogo
La salida es este comando será similar a la siguiente:
Created migration: 2019_07_09_023027_tabla_catalogo
El nombre del archivo de migración es generado aleatoriamente por artisan y corresponde a la fecha actual concatenada con un tipo de timestamp y el argumento que hemos digitado en el comando make:migration. Esta nueva migración estará situada en el directorio database/migrations y tendrá el siguiente contenido:
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class TablaCatalogo extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
//
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
}
}
Básicamente nuestra migración tiene dos métodos, up
y down
los cuáles sirven para agregar nuevas tablas, columnas, índices entre otros, y para reversar los cambios realizados respectivamente. Lo siguiente que vamos a ver ahora es cómo crear una tabla, su definición de campos, constraints y demás.
Definición de tablas
Para la definición de una tabla de base de datos resulta mucho más sencillo ejecutar el siguiente comando que crea un scaffolding para la estructura de la tabla:
php artisan make:migration create_catalogo_table
Lo primero que hay que denotar aquí (antes de revisar la migración) es que el anterior comando hace referencia a un patrón definido por create_mitabla_table el cuál siempre creará la tabla con el nombre encerrado por los caracteres _
(underscore). Para nuestro caso particular creará un archivo de migración para la tabla catalogo.
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateCatalogoTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('catalogo', function (Blueprint $table) {
$table->bigIncrements('id');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('catalogo');
}
}
En segundo lugar, podemos observar que laravel automáticamente ha creado el reverso de la migración por lo cuál no tendremos que preocuparnos por ello. Tanto el método up
como down
utilizan el facade Schema
el cual provee un gran número de utilidades para la definición del esquema de la base de datos y validaciones. Por ahora es menester ver cómo podemos crear los distintos tipos de datos (o al menos los más utilizados) en bases de datos. Veamos a continuación la definición de nuestra tabla catalogo con varios tipos de datos.
Schema::create('catalogo', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('description');
$table->string('marca')->nullable();
$table->string('modelo', 30)->nullable();
$table->text('observaciones');
$table->date('proxima_revision');
$table->integer('stock_minimo');
$table->decimal('valor_unitario', 8, 2);
$table->enum('estado', ['activo', 'inactivo']);
$table->timestamps();
});
Por simplicidad hemos colocado solamente el contenido del método up
. Analicemos pues cada línea de la anterior definición tomando como base que se ha ejecutado en el motor de base de datos Mysql.
$table->bigIncrements('id');
El método bigIncrements
crea un campo bigint de longitud 20, unsigned y que es la llave primaria de la tabla.
$table->string('description');
El método string
crea un campo de tipo varchar de longitud 255.
$table->string('marca')->nullable();
En este caso, la única diferencia con la anterior definición es que la columna se creará con posibilidad de insertar valores nulos en ella.
$table->string('modelo', 30)->nullable();
Si se agrega un segundo parámetro al método string
definirá también la longitud del campo.
$table->text('observaciones');
El método text
crea una columna de tipo text en la tabla.
$table->date('proxima_revision');
El método date
crea una columna de tipo date en la tabla.
$table->$table->integer('stock_minimo');
El método integer
crear una columna de tipo int de longitud 11 en la tabla.
$table->decimal('valor_unitario', 8, 2);
El método decimal
crea una columna de tipo decimal con precisión 8 y escala 2.
$table->enum('estado', ['activo', 'inactivo']);
El método enum
crear una columna de tipo enum con los valores permitidos pasados como segundo parámetro en el array
.
Modificación de tablas
Para modificar una definición de tabla se debe utilizar como último método de la sentencia de definición de un campo el método change
de la siguiente forma:
Schema::table('catalogo', function (Blueprint $table) {
$table->string('description', 50)->nullable()->change();
});
Este tipo de modificaciones suele utilizarse en sistema de producción en donde ya está instalada una versión funcional del software, además de hacerlo en una migración particular independiente a la de creación de la tabla. De lo contrario, en entornos de desarrollo suena mucho más lógico realizar dicha modificación sobre la migración de creación de la tabla.
Para eliminar una columna basta utilizar el método drop
.
Schema::table('catalogo', function (Blueprint $table) {
$table->dropColumn('marca');
});
Código SQL en migraciones
Si la alteración que se va a realizar a la base de datos es demasiado particular entonces y definitivamente no encuentras una manera de realizarlo de forma nativa en laravel entonces puedes utilizar el facade DB
.
DB::statement("UPDATE credit_concepts SET description = SUBSTR(description, 1, 60)");
Ejecución de migraciones
La manera de ejecutar las migraciones pendientes es mediante el comando:
php artisan migrate
Laravel realizará la ejecución de las migraciones que no se hayan ejecutado, de esta manera se asegura que en entornos de producción no se vuelvan a correr los comandos para crear las tablas que ya tenemos. Si ejecutas este comando en un proyecto limpio de laravel podrá ver una salida similar a la siguiente:
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table
Migrating: 2019_07_09_025421_create_catalogo_table
Migrated: 2019_07_09_025421_create_catalogo_table
Laravel contiene por defecto dos migraciones para crear una tabla de usuarios (users
) y recuperación de contraseñas (create_password_resets_table
). Si no lo consideras necesario puedes eliminar estas migraciones. Para consultar más a profundidad este tema de las migraciones te recomiendo consultar la documentación oficial en el siguiente link:
https://laravel.com/docs/master/migrations
Espero que este post te haya servido y que te haya dado las herramientas necesarias para seguir con temas más avanzados. Hasta la próxima!.