Saltar contenido

Base de datos: Migraciones

Introducción

Las migraciones son como control de versiones para tu base de datos, lo que permite a tu equipo definir y compartir la definición del esquema de la base de datos de la aplicación. Si alguna vez has tenido que decirle a un compañero de equipo que añada manualmente una columna a su esquema de base de datos local después de incorporar tus cambios desde el control de versiones, has enfrentado el problema que las migraciones de base de datos resuelven. La Schema facade de Laravel proporciona soporte agnóstico a bases de datos para crear y manipular tablas en todos los sistemas de bases de datos admitidos por Laravel. Típicamente, las migraciones utilizarán esta fachada para crear y modificar tablas y columnas de base de datos.

Generando Migraciones

Puedes usar el comando Artisan make:migration para generar una migración de base de datos. La nueva migración se colocará en tu directorio database/migrations. Cada nombre de archivo de migración contiene una marca de tiempo que permite a Laravel determinar el orden de las migraciones:

php artisan make:migration create_flights_table

Laravel utilizará el nombre de la migración para intentar adivinar el nombre de la tabla y si la migración creará o no una nueva tabla. Si Laravel puede determinar el nombre de la tabla a partir del nombre de la migración, Laravel rellenará automáticamente el archivo de migración generado con la tabla especificada. De lo contrario, puedes especificar la tabla en el archivo de migración manualmente. Si deseas especificar una ruta personalizada para la migración generada, puedes utilizar la opción --path al ejecutar el comando make:migration. La ruta dada debe ser relativa a la ruta base de tu aplicación.

[!NOTA] Los stubs de migración se pueden personalizar utilizando la publicación de stubs.

Aplanando Migraciones

A medida que construyes tu aplicación, es posible que acumules más y más migraciones con el tiempo. Esto puede llevar a que tu directorio database/migrations se vuelva engorroso con potencialmente cientos de migraciones. Si lo deseas, puedes "compactar" tus migraciones en un solo archivo SQL. Para comenzar, ejecuta el comando schema:dump:

php artisan schema:dump
 
# Dump the current database schema and prune all existing migrations...
php artisan schema:dump --prune

Cuando ejecutes este comando, Laravel escribirá un archivo "schema" en el directorio database/schema de tu aplicación. El nombre del archivo de esquema corresponderá a la conexión de base de datos. Ahora, cuando intentes migrar tu base de datos y no se hayan ejecutado otras migraciones, Laravel primero ejecutará las sentencias SQL en el archivo de esquema de la conexión de base de datos que estás utilizando. Después de ejecutar las sentencias SQL del archivo de esquema, Laravel ejecutará cualquier migración restante que no formara parte del volcado del esquema. Si las pruebas de tu aplicación utilizan una conexión de base de datos diferente a la que sueles usar durante el desarrollo local, debes asegurarte de haber volcado un archivo de esquema utilizando esa conexión de base de datos para que tus pruebas puedan construir tu base de datos. Es posible que desees hacer esto después de volcar la conexión de base de datos que sueles usar durante el desarrollo local:

php artisan schema:dump
php artisan schema:dump --database=testing --prune

Debes comprometer el archivo del esquema de tu base de datos al control de versiones para que otros desarrolladores nuevos en tu equipo puedan crear rápidamente la estructura de base de datos inicial de tu aplicación.

[!WARNING] La compactación de migraciones solo está disponible para las bases de datos MariaDB, MySQL, PostgreSQL y SQLite y utiliza el cliente de línea de comandos de la base de datos.

Estructura de Migración

Una clase de migración contiene dos métodos: up y down. El método up se utiliza para agregar nuevas tablas, columnas o índices a tu base de datos, mientras que el método down debe revertir las operaciones realizadas por el método up. Dentro de ambos métodos, puedes usar el constructor de esquema de Laravel para crear y modificar tablas de manera expresiva. Para aprender sobre todos los métodos disponibles en el constructor Schema, consulta su documentación. Por ejemplo, la siguiente migración crea una tabla flights:

<?php
 
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
 
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('flights', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('airline');
$table->timestamps();
});
}
 
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::drop('flights');
}
};

Configurando la Conexión de Migración

Si tu migración estará interactuando con una conexión a base de datos diferente de la conexión a base de datos predeterminada de tu aplicación, deberías establecer la propiedad $connection de tu migración:

/**
* The database connection that should be used by the migration.
*
* @var string
*/
protected $connection = 'pgsql';
 
/**
* Run the migrations.
*/
public function up(): void
{
// ...
}

Ejecutando Migraciones

Para ejecutar todas tus migraciones pendientes, ejecuta el comando Artisan migrate:

php artisan migrate

Si deseas ver qué migraciones se han ejecutado hasta ahora, puedes usar el comando Artisan migrate:status:

php artisan migrate:status

Si deseas ver las declaraciones SQL que se ejecutarán mediante las migraciones sin ejecutarlas realmente, puedes proporcionar la bandera --pretend al comando migrate:

php artisan migrate --pretend

Aislar la Ejecución de Migraciones

Si estás desplegando tu aplicación en múltiples servidores y ejecutando migraciones como parte de tu proceso de despliegue, es probable que no quieras que dos servidores intenten migrar la base de datos al mismo tiempo. Para evitar esto, puedes usar la opción isolated al invocar el comando migrate. Cuando se proporciona la opción isolated, Laravel adquirirá un bloqueo atómico utilizando el driver de caché de tu aplicación antes de intentar ejecutar tus migraciones. Todos los otros intentos de ejecutar el comando migrate mientras se mantiene ese bloqueo no se ejecutarán; sin embargo, el comando todavía saldrá con un código de estado de salida exitoso:

php artisan migrate --isolated

[!WARNING] Para utilizar esta función, tu aplicación debe estar utilizando el driver de caché memcached, redis, dynamodb, database, file o array como el driver de caché predeterminado de tu aplicación. Además, todos los servidores deben estar comunicándose con el mismo servidor de caché central.

Forzar la Ejecución de Migraciones en Producción

Algunas operaciones de migración son destructivas, lo que significa que pueden hacer que pierdas datos. Para protegerte de ejecutar estos comandos en tu base de datos de producción, se te pedirá confirmación antes de que se ejecuten los comandos. Para forzar la ejecución de los comandos sin un aviso, usa el flag --force:

php artisan migrate --force

Revirtiendo Migraciones

Para deshacer la última operación de migración, puedes usar el comando Artisan rollback. Este comando deshace el último "lote" de migraciones, que puede incluir varios archivos de migración:

php artisan migrate:rollback

Puedes revertir un número limitado de migraciones proporcionando la opción step al comando rollback. Por ejemplo, el siguiente comando revertirá las últimas cinco migraciones:

php artisan migrate:rollback --step=5

Puedes revertir un "batch" específico de migraciones proporcionando la opción batch al comando rollback, donde la opción batch corresponde a un valor de lote dentro de la tabla migrations de la base de datos de tu aplicación. Por ejemplo, el siguiente comando revertirá todas las migraciones en el lote tres:

php artisan migrate:rollback --batch=3

Si deseas ver las declaraciones SQL que se ejecutarán mediante las migraciones sin realmente ejecutarlas, puedes proporcionar el flag --pretend al comando migrate:rollback:

php artisan migrate:rollback --pretend

El comando migrate:reset revertirá todas las migraciones de tu aplicación:

php artisan migrate:reset

Revertir y migrar utilizando un solo comando

El comando migrate:refresh revertirá todas tus migraciones y luego ejecutará el comando migrate. Este comando efectivamente vuelve a crear toda tu base de datos:

php artisan migrate:refresh
 
# Refresh the database and run all database seeds...
php artisan migrate:refresh --seed

Puedes deshacer y reiniciar un número limitado de migraciones proporcionando la opción step al comando refresh. Por ejemplo, el siguiente comando deshará y volverá a migrar las últimas cinco migraciones:

php artisan migrate:refresh --step=5

Eliminar todas las tablas y migrar

El comando migrate:fresh eliminará todas las tablas de la base de datos y luego ejecutará el comando migrate:

php artisan migrate:fresh
 
php artisan migrate:fresh --seed

Por defecto, el comando migrate:fresh solo elimina tablas de la conexión de base de datos predeterminada. Sin embargo, puedes usar la opción --database para especificar la conexión de base de datos que se debe migrar. El nombre de la conexión de base de datos debe corresponder a una conexión definida en el archivo de configuración database de tu aplicación configuración:

php artisan migrate:fresh --database=admin

[!WARNING] El comando migrate:fresh eliminará todas las tablas de la base de datos sin importar su prefijo. Este comando debe usarse con precaución al desarrollar en una base de datos que se comparte con otras aplicaciones.

Tablas

Creando Tablas

Para crear una nueva tabla de base de datos, utiliza el método create en la fachada Schema. El método create acepta dos argumentos: el primero es el nombre de la tabla, mientras que el segundo es una función anónima que recibe un objeto Blueprint que se puede usar para definir la nueva tabla:

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
 
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email');
$table->timestamps();
});

Al crear la tabla, puedes usar cualquiera de los métodos de columna del generador de esquemas para definir las columnas de la tabla.

Determinando la Existencia de una Tabla / Columna

Puedes determinar la existencia de una tabla, columna o índice utilizando los métodos hasTable, hasColumn y hasIndex:

if (Schema::hasTable('users')) {
// The "users" table exists...
}
 
if (Schema::hasColumn('users', 'email')) {
// The "users" table exists and has an "email" column...
}
 
if (Schema::hasIndex('users', ['email'], 'unique')) {
// The "users" table exists and has a unique index on the "email" column...
}

Conexión a la base de datos y opciones de tabla

Si deseas realizar una operación de esquema en una conexión de base de datos que no sea la conexión predeterminada de tu aplicación, utiliza el método connection:

Schema::connection('sqlite')->create('users', function (Blueprint $table) {
$table->id();
});

Además, se pueden usar algunas otras propiedades y métodos para definir otros aspectos de la creación de la tabla. La propiedad engine se puede utilizar para especificar el motor de almacenamiento de la tabla al utilizar MariaDB o MySQL:

Schema::create('users', function (Blueprint $table) {
$table->engine('InnoDB');
 
// ...
});

Las propiedades charset y collation se pueden utilizar para especificar el conjunto de caracteres y la intercalación para la tabla creada al usar MariaDB o MySQL:

Schema::create('users', function (Blueprint $table) {
$table->charset('utf8mb4');
$table->collation('utf8mb4_unicode_ci');
 
// ...
});

El método temporary se puede utilizar para indicar que la tabla debe ser "temporal". Las tablas temporales solo son visibles para la sesión de base de datos de la conexión actual y se eliminan automáticamente cuando se cierra la conexión:

Schema::create('calculations', function (Blueprint $table) {
$table->temporary();
 
// ...
});

Si deseas añadir un "comentario" a una tabla de base de datos, puedes invocar el método comment en la instancia de la tabla. Los comentarios de tabla son actualmente solo soportados por MariaDB, MySQL y PostgreSQL:

Schema::create('calculations', function (Blueprint $table) {
$table->comment('Business calculations');
 
// ...
});

Actualizando Tablas

El método table en la fachada Schema se puede usar para actualizar tablas existentes. Al igual que el método create, el método table acepta dos argumentos: el nombre de la tabla y una función anónima que recibe una instancia de Blueprint que puedes usar para añadir columnas o índices a la tabla:

Renombrando / Eliminando Tablas

Para renombrar una tabla de base de datos existente, utiliza el método rename:

use Illuminate\Support\Facades\Schema;
 
Schema::rename($from, $to);

Para eliminar una tabla existente, puedes usar los métodos drop o dropIfExists:

Schema::drop('users');
 
Schema::dropIfExists('users');

Renombrando Tablas Con Claves Foráneas

Antes de renombrar una tabla, debes verificar que cualquier restricción de clave externa en la tabla tenga un nombre explícito en tus archivos de migración en lugar de dejar que Laravel asigne un nombre basado en convención. De lo contrario, el nombre de la restricción de clave externa se referirá al antiguo nombre de la tabla.

Columnas

Creando Columnas

El método table en la fachada Schema se puede usar para actualizar tablas existentes. Al igual que el método create, el método table acepta dos argumentos: el nombre de la tabla y una función anónima que recibe una instancia de Illuminate\Database\Schema\Blueprint que puedes usar para agregar columnas a la tabla:

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
 
Schema::table('users', function (Blueprint $table) {
$table->integer('votes');
});

Tipos de Columnas Disponibles

El esquema de la construcción de planos ofrece una variedad de métodos que corresponden a los diferentes tipos de columnas que puedes añadir a tus tablas de base de datos. Cada uno de los métodos disponibles se enumera en la tabla a continuación:

bigIncrements()

El método bigIncrements crea una columna equivalente UNSIGNED BIGINT (clave primaria) que se auto-incrementa:

$table->bigIncrements('id');

bigInteger()

El método bigInteger crea una columna equivalente a BIGINT:

$table->bigInteger('votes');

binary()

El método binary crea una columna equivalente a BLOB:

$table->binary('photo');

Al utilizar MySQL, MariaDB o SQL Server, puedes pasar los argumentos length y fixed para crear una columna equivalente a VARBINARY o BINARY:

$table->binary('data', length: 16); // VARBINARY(16)
 
$table->binary('data', length: 16, fixed: true); // BINARY(16)

boolean()

El método boolean crea una columna equivalente a BOOLEAN:

$table->boolean('confirmed');

char()

El método char crea una columna equivalente a CHAR con una longitud dada:

$table->char('name', length: 100);

dateTimeTz()

El método dateTimeTz crea una columna equivalente a DATETIME (con zona horaria) con una precisión opcional de segundos fraccionarios:

$table->dateTimeTz('created_at', precision: 0);

dateTime()

El método dateTime crea una columna equivalente a DATETIME con una precisión opcional de segundos fraccionarios:

$table->dateTime('created_at', precision: 0);

date()

El método date crea una columna equivalente a DATE:

$table->date('created_at');

decimal()

El método decimal crea una columna equivalente a DECIMAL con la precisión dada (dígitos totales) y la escala (dígitos decimales):

$table->decimal('amount', total: 8, places: 2);

double()

El método double crea una columna equivalente a DOUBLE:

$table->double('amount');

enum()

El método enum crea una columna equivalente a ENUM con los valores válidos dados:

$table->enum('difficulty', ['easy', 'hard']);

float()

El método float crea una columna equivalente a FLOAT con la precisión dada:

$table->float('amount', precision: 53);

foreignId()

El método foreignId crea una columna equivalente a UNSIGNED BIGINT:

$table->foreignId('user_id');

foreignIdFor()

El método foreignIdFor añade una columna equivalente {column}_id para una clase de modelo dada. El tipo de columna será UNSIGNED BIGINT, CHAR(36) o CHAR(26) dependiendo del tipo de clave del modelo:

$table->foreignIdFor(User::class);

foreignUlid()

El método foreignUlid crea una columna equivalente a ULID:

$table->foreignUlid('user_id');

foreignUuid()

El método foreignUuid crea una columna equivalente a UUID:

$table->foreignUuid('user_id');

geography()

El método geography crea una columna equivalente a GEOGRAPHY con el tipo espacial dado y el SRID (Identificador del Sistema de Referencia Espacial) dado:

$table->geography('coordinates', subtype: 'point', srid: 4326);

[!NOTE] El soporte para tipos espaciales depende de tu driver de base de datos. Consulta la documentación de tu base de datos. Si tu aplicación está utilizando una base de datos PostgreSQL, debes instalar la extensión PostGIS antes de que se pueda usar el método geography.

geometry()

El método geometry crea una columna equivalente a GEOMETRY con el tipo espacial dado y el SRID (Identificador de Sistema de Referencia Espacial):

$table->geometry('positions', subtype: 'point', srid: 0);

[!NOTE] El soporte para tipos espaciales depende de tu driver de base de datos. Por favor, consulta la documentación de tu base de datos. Si tu aplicación está utilizando una base de datos PostgreSQL, debes instalar la extensión PostGIS antes de que se pueda utilizar el método geometry.

id()

El método id es un alias del método bigIncrements. Por defecto, el método creará una columna id; sin embargo, puedes pasar un nombre de columna si deseas asignar un nombre diferente a la columna:

$table->id();

increments()

El método increments crea una columna equivalente a INTEGER UNSIGNED auto-incremental como clave primaria:

$table->increments('id');

integer()

El método integer crea una columna equivalente a INTEGER:

$table->integer('votes');

ipAddress()

El método ipAddress crea una columna equivalente a VARCHAR:

$table->ipAddress('visitor');

Al utilizar PostgreSQL, se creará una columna INET.

json()

El método json crea una columna equivalente a JSON:

$table->json('options');

jsonb()

El método jsonb crea una columna equivalente a JSONB:

$table->jsonb('options');

longText()

El método longText crea una columna equivalente a LONGTEXT:

$table->longText('description');

Al utilizar MySQL o MariaDB, puedes aplicar un conjunto de caracteres binary a la columna para crear una columna equivalente a LONGBLOB:

$table->longText('data')->charset('binary'); // LONGBLOB

macAddress()

El método macAddress crea una columna que está destinada a contener una dirección MAC. Algunos sistemas de bases de datos, como PostgreSQL, tienen un tipo de columna dedicado para este tipo de datos. Otros sistemas de bases de datos utilizarán una columna equivalente a string:

$table->macAddress('device');

mediumIncrements()

El método mediumIncrements crea una columna equivalente UNSIGNED MEDIUMINT auto-incremental como clave primaria:

$table->mediumIncrements('id');

mediumInteger()

El método mediumInteger crea una columna equivalente a MEDIUMINT:

$table->mediumInteger('votes');

mediumText()

El método mediumText crea una columna equivalente a MEDIUMTEXT:

$table->mediumText('description');

Al utilizar MySQL o MariaDB, puedes aplicar un conjunto de caracteres binary a la columna para crear una columna equivalente a MEDIUMBLOB:

$table->mediumText('data')->charset('binary'); // MEDIUMBLOB

morphs()

El método morphs es un método de conveniencia que añade una columna equivalente {column}_id y una columna VARCHAR equivalente {column}_type. El tipo de columna para el {column}_id será UNSIGNED BIGINT, CHAR(36) o CHAR(26), dependiendo del tipo de clave del modelo. Este método está destinado a ser utilizado al definir las columnas necesarias para una relación Eloquent polimórfica. En el siguiente ejemplo, se crearían las columnas taggable_id y taggable_type:

$table->morphs('taggable');

nullableTimestamps()

El método nullableTimestamps es un alias del método timestamps:

$table->nullableTimestamps(precision: 0);

nullableMorphs()

El método es similar al método morphs; sin embargo, las columnas que se crean serán "nullable":

$table->nullableMorphs('taggable');

nullableUlidMorphs()

El método es similar al método ulidMorphs; sin embargo, las columnas que se crearán serán "nullable":

$table->nullableUlidMorphs('taggable');

nullableUuidMorphs()

El método es similar al método uuidMorphs; sin embargo, las columnas que se crean serán "nullable":

$table->nullableUuidMorphs('taggable');

rememberToken()

El método rememberToken crea una columna equivalente a VARCHAR(100) que permite nulos y que está destinada a almacenar el token de autenticación "recuerdame" actual token de autenticación:

$table->rememberToken();

set()

El método set crea una columna equivalente a SET con la lista dada de valores válidos:

$table->set('flavors', ['strawberry', 'vanilla']);

smallIncrements()

El método smallIncrements crea una columna equivalente a UNSIGNED SMALLINT de auto-incremento como clave primaria:

$table->smallIncrements('id');

smallInteger()

El método smallInteger crea una columna equivalente a SMALLINT:

$table->smallInteger('votes');

softDeletesTz()

El método softDeletesTz añade una columna deleted_at TIMESTAMP (con zona horaria) equivalente y nullable, con una precisión de segundos fraccionarios opcional. Esta columna está destinada a almacenar la marca de tiempo deleted_at necesaria para la funcionalidad de "eliminación suave" de Eloquent:

$table->softDeletesTz('deleted_at', precision: 0);

softDeletes()

El método softDeletes añade una columna TIMESTAMP equivalente deleted_at que admite valores nulos, con una precisión de segundos fraccionarios opcional. Esta columna está destinada a almacenar la marca de tiempo deleted_at necesaria para la funcionalidad de "eliminación suave" de Eloquent:

$table->softDeletes('deleted_at', precision: 0);

string()

El método string crea una columna equivalente a VARCHAR de la longitud dada:

$table->string('name', length: 100);

text()

El método text crea una columna equivalente a TEXT:

$table->text('description');

Al utilizar MySQL o MariaDB, puedes aplicar un conjunto de caracteres binary a la columna para crear una columna equivalente a BLOB:

$table->text('data')->charset('binary'); // BLOB

timeTz()

El método timeTz crea una columna equivalente a TIME (con zona horaria) con una precisión de segundos fraccionales opcional:

$table->timeTz('sunrise', precision: 0);

time()

El método time crea una columna equivalente a TIME con una precisión de segundos fraccionarios opcional:

$table->time('sunrise', precision: 0);

timestampTz()

El método timestampTz crea una columna equivalente a TIMESTAMP (con zona horaria) con una precisión de fracciones de segundo opcional:

$table->timestampTz('added_at', precision: 0);

timestamp()

El método timestamp crea una columna equivalente a TIMESTAMP con una precisión de segundos fraccionarios opcional:

$table->timestamp('added_at', precision: 0);

timestampsTz()

El método timestampsTz crea columnas equivalentes created_at y updated_at TIMESTAMP (con zona horaria) con una precisión de segundos fraccionarios opcional:

$table->timestampsTz(precision: 0);

timestamps()

El método timestamps crea columnas TIMESTAMP equivalentes created_at y updated_at con una precisión de segundos fraccionarios opcional:

$table->timestamps(precision: 0);

tinyIncrements()

El método tinyIncrements crea una columna equivalente UNSIGNED TINYINT de autoincremento como clave primaria:

$table->tinyIncrements('id');

tinyInteger()

El método tinyInteger crea una columna equivalente a TINYINT:

$table->tinyInteger('votes');

tinyText()

El método tinyText crea una columna equivalente a TINYTEXT:

$table->tinyText('notes');

Al utilizar MySQL o MariaDB, puedes aplicar un conjunto de caracteres binary a la columna para crear una columna equivalente a TINYBLOB:

$table->tinyText('data')->charset('binary'); // TINYBLOB

unsignedBigInteger()

El método unsignedBigInteger crea una columna equivalente a UNSIGNED BIGINT:

$table->unsignedBigInteger('votes');

unsignedInteger()

El método unsignedInteger crea una columna equivalente a UNSIGNED INTEGER:

$table->unsignedInteger('votes');

unsignedMediumInteger()

El método unsignedMediumInteger crea una columna equivalente a UNSIGNED MEDIUMINT:

$table->unsignedMediumInteger('votes');

unsignedSmallInteger()

El método unsignedSmallInteger crea una columna equivalente a UNSIGNED SMALLINT:

$table->unsignedSmallInteger('votes');

unsignedTinyInteger()

El método unsignedTinyInteger crea una columna equivalente a UNSIGNED TINYINT:

$table->unsignedTinyInteger('votes');

ulidMorphs()

El método ulidMorphs es un método de conveniencia que añade una columna equivalente {column}_id CHAR(26) y una columna equivalente {column}_type VARCHAR. Este método está destinado a ser utilizado al definir las columnas necesarias para una relación Eloquent polimórfica que utiliza identificadores ULID. En el siguiente ejemplo, se crearían las columnas taggable_id y taggable_type:

$table->ulidMorphs('taggable');

uuidMorphs()

El método uuidMorphs es un método de conveniencia que añade una columna {column}_id CHAR(36) equivalente y una columna {column}_type VARCHAR equivalente. Este método está destinado a utilizarse al definir las columnas necesarias para una relación Eloquent polimórfica que utiliza identificadores UUID. En el siguiente ejemplo, se crearían las columnas taggable_id y taggable_type:

$table->uuidMorphs('taggable');

ulid()

El método ulid crea una columna equivalente a ULID:

$table->ulid('id');

uuid()

El método uuid crea una columna equivalente a UUID:

$table->uuid('id');

year()

El método year crea una columna equivalente a YEAR:

$table->year('birth_year');

Modificadores de Columna

Además de los tipos de columna listados anteriormente, hay varios "modificadores" de columna que puedes usar al agregar una columna a una tabla de base de datos. Por ejemplo, para hacer que la columna sea "nullable", puedes usar el método nullable:

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
 
Schema::table('users', function (Blueprint $table) {
$table->string('email')->nullable();
});

La siguiente tabla contiene todos los modificadores de columna disponibles. Esta lista no incluye modificadores de índice:

Modificador Descripción
->after('column') Coloca la columna "después" de otra columna (MariaDB / MySQL).
->autoIncrement() Establece columnas INTEGER como auto-incrementales (clave primaria).
->charset('utf8mb4') Especifica un conjunto de caracteres para la columna (MariaDB / MySQL).
->collation('utf8mb4_unicode_ci') Especifica una colación para la columna.
->comment('my comment') Añade un comentario a una columna (MariaDB / MySQL / PostgreSQL).
->default($value) Especifica un valor "por defecto" para la columna.
->first() Coloca la columna "primera" en la tabla (MariaDB / MySQL).
->from($integer) Establece el valor inicial de un campo auto-incrementable (MariaDB / MySQL / PostgreSQL).
->invisible() Hace que la columna sea "invisible" para consultas SELECT * (MariaDB / MySQL).
->nullable($value = true) Permite que se inserten valores NULL en la columna.
->storedAs($expression) Crea una columna generada almacenada (MariaDB / MySQL / PostgreSQL / SQLite).
->unsigned() Establece columnas INTEGER como UNSIGNED (MariaDB / MySQL).
->useCurrent() Establece columnas TIMESTAMP para usar CURRENT_TIMESTAMP como valor por defecto.
->useCurrentOnUpdate() Establece columnas TIMESTAMP para usar CURRENT_TIMESTAMP cuando se actualiza un registro (MariaDB / MySQL).
->virtualAs($expression) Crea una columna generada virtual (MariaDB / MySQL / SQLite).
->generatedAs($expression) Crea una columna de identidad con opciones de secuencia especificadas (PostgreSQL).
->always() Define la precedencia de los valores de secuencia sobre la entrada para una columna de identidad (PostgreSQL).

Expresiones Predeterminadas

El modificador default acepta un valor o una instancia de Illuminate\Database\Query\Expression. Usar una instancia de Expression evitará que Laravel envuelva el valor entre comillas y te permitirá usar funciones específicas de la base de datos. Una situación donde esto es especialmente útil es cuando necesitas asignar valores predeterminados a columnas JSON:

<?php
 
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Query\Expression;
use Illuminate\Database\Migrations\Migration;
 
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('flights', function (Blueprint $table) {
$table->id();
$table->json('movies')->default(new Expression('(JSON_ARRAY())'));
$table->timestamps();
});
}
};

[!WARNING] El soporte para expresiones por defecto depende de tu driver de base de datos, versión de base de datos y el tipo de campo. Por favor, consulta la documentación de tu base de datos.

Orden de Columnas

Al utilizar la base de datos MariaDB o MySQL, el método after puede usarse para añadir columnas después de una columna existente en el esquema:

$table->after('password', function (Blueprint $table) {
$table->string('address_line1');
$table->string('address_line2');
$table->string('city');
});

Modificando Columnas

El método change te permite modificar el tipo y los atributos de las columnas existentes. Por ejemplo, es posible que desees aumentar el tamaño de una columna string. Para ver el método change en acción, aumentemos el tamaño de la columna name de 25 a 50. Para lograr esto, simplemente definimos el nuevo estado de la columna y luego llamamos al método change:

Schema::table('users', function (Blueprint $table) {
$table->string('name', 50)->change();
});

Al modificar una columna, debes incluir explícitamente todos los modificadores que deseas mantener en la definición de la columna; cualquier atributo que falte será eliminado. Por ejemplo, para retener los atributos unsigned, default y comment, debes llamar a cada modificador de forma explícita al cambiar la columna:

Schema::table('users', function (Blueprint $table) {
$table->integer('votes')->unsigned()->default(1)->comment('my comment')->change();
});

El método change no cambia los índices de la columna. Por lo tanto, puedes usar modificadores de índice para agregar o eliminar explícitamente un índice al modificar la columna:

// Add an index...
$table->bigIncrements('id')->primary()->change();
 
// Drop an index...
$table->char('postal_code', 10)->unique(false)->change();

Renombrando Columnas

Para renombrar una columna, puedes usar el método renameColumn proporcionado por el constructor de esquemas:

Schema::table('users', function (Blueprint $table) {
$table->renameColumn('from', 'to');
});

Eliminando Columnas

Para eliminar una columna, puedes usar el método dropColumn en el constructor de esquemas:

Schema::table('users', function (Blueprint $table) {
$table->dropColumn('votes');
});

Puedes eliminar múltiples columnas de una tabla pasando un array de nombres de columna al método dropColumn:

Schema::table('users', function (Blueprint $table) {
$table->dropColumn(['votes', 'avatar', 'location']);
});

Aliases de Comando Disponibles

Laravel ofrece varios métodos convenientes relacionados con la eliminación de tipos comunes de columnas. Cada uno de estos métodos se describe en la tabla a continuación:

Comando Descripción
$table->dropMorphs('morphable'); Eliminar las columnas morphable_id y morphable_type.
$table->dropRememberToken(); Eliminar la columna remember_token.
$table->dropSoftDeletes(); Eliminar la columna deleted_at.
$table->dropSoftDeletesTz(); Alias del método dropSoftDeletes().
$table->dropTimestamps(); Eliminar las columnas created_at y updated_at.
$table->dropTimestampsTz(); Alias del método dropTimestamps().

Índices

Creando Índices

El constructor de esquemas de Laravel admite varios tipos de índices. El siguiente ejemplo crea una nueva columna email y especifica que sus valores deben ser únicos. Para crear el índice, podemos encadenar el método unique a la definición de la columna:

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
 
Schema::table('users', function (Blueprint $table) {
$table->string('email')->unique();
});

Alternativamente, puedes crear el índice después de definir la columna. Para hacerlo, debes llamar al método unique en el plano del generador de esquemas. Este método acepta el nombre de la columna que debe recibir un índice único:

$table->unique('email');

Puedes incluso pasar un array de columnas a un método de índice para crear un índice compuesto:

$table->index(['account_id', 'created_at']);

Al crear un índice, Laravel generará automáticamente un nombre de índice basado en la tabla, los nombres de las columnas y el tipo de índice, pero puedes pasar un segundo argumento al método para especificar el nombre del índice tú mismo:

$table->unique('email', 'unique_email');

Tipos de Índice Disponibles

La clase blueprint del constructor de esquemas de Laravel proporciona métodos para crear cada tipo de índice soportado por Laravel. Cada método de índice acepta un segundo argumento opcional para especificar el nombre del índice. Si se omite, el nombre se derivará de los nombres de la tabla y la(s) columna(s) utilizadas para el índice, así como del tipo de índice. Cada uno de los métodos de índice disponibles se describe en la tabla a continuación:

Comando Descripción
$table->primary('id'); Añade una clave primaria.
$table->primary(['id', 'parent_id']); Añade claves compuestas.
$table->unique('email'); Añade un índice único.
$table->index('state'); Añade un índice.
$table->fullText('body'); Añade un índice de texto completo (MariaDB / MySQL / PostgreSQL).
$table->fullText('body')->language('english'); Añade un índice de texto completo del idioma especificado (PostgreSQL).
$table->spatialIndex('location'); Añade un índice espacial (excepto SQLite).

Renombrando Índices

Para renombrar un índice, puedes usar el método renameIndex proporcionado por el blueprint del constructor de esquema. Este método acepta el nombre actual del índice como su primer argumento y el nombre deseado como su segundo argumento:

$table->renameIndex('from', 'to')

Eliminando Índices

Para eliminar un índice, debes especificar el nombre del índice. Por defecto, Laravel asigna automáticamente un nombre de índice basado en el nombre de la tabla, el nombre de la columna indexada y el tipo de índice. Aquí hay algunos ejemplos:

Comando Descripción
$table->dropPrimary('users_id_primary'); Eliminar una clave primaria de la tabla "users".
$table->dropUnique('users_email_unique'); Eliminar un índice único de la tabla "users".
$table->dropIndex('geo_state_index'); Eliminar un índice básico de la tabla "geo".
$table->dropFullText('posts_body_fulltext'); Eliminar un índice de texto completo de la tabla "posts".
$table->dropSpatialIndex('geo_location_spatialindex'); Eliminar un índice espacial de la tabla "geo" (excepto SQLite).
Si pasas un array de columnas a un método que elimina índices, el nombre del índice convencional se generará en base al nombre de la tabla, las columnas y el tipo de índice:
Schema::table('geo', function (Blueprint $table) {
$table->dropIndex(['state']); // Drops index 'geo_state_index'
});

Restricciones de Clave Foránea

Laravel también proporciona soporte para la creación de restricciones de clave foránea, que se utilizan para forzar la integridad referencial a nivel de base de datos. Por ejemplo, definamos una columna user_id en la tabla posts que haga referencia a la columna id en una tabla users:

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
 
Schema::table('posts', function (Blueprint $table) {
$table->unsignedBigInteger('user_id');
 
$table->foreign('user_id')->references('id')->on('users');
});

Dado que esta sintaxis es bastante verbosa, Laravel ofrece métodos adicionales y más concisos que utilizan convenciones para proporcionar una mejor experiencia al desarrollador. Al usar el método foreignId para crear tu columna, el ejemplo anterior se puede reescribir así:

Schema::table('posts', function (Blueprint $table) {
$table->foreignId('user_id')->constrained();
});

El método foreignId crea una columna equivalente de UNSIGNED BIGINT, mientras que el método constrained utilizará convenciones para determinar la tabla y la columna que se están referenciando. Si el nombre de tu tabla no coincide con las convenciones de Laravel, puedes proporcionarlo manualmente al método constrained. Además, el nombre que se debe asignar al índice generado también se puede especificar:

Schema::table('posts', function (Blueprint $table) {
$table->foreignId('user_id')->constrained(
table: 'users', indexName: 'posts_user_id'
);
});

También puedes especificar la acción deseada para las propiedades "on delete" y "on update" de la restricción:

$table->foreignId('user_id')
->constrained()
->onUpdate('cascade')
->onDelete('cascade');

También se ofrece una sintaxis alternativa y expresiva para estas acciones:

Método Descripción
$table->cascadeOnUpdate(); Las actualizaciones deben ser en cascada.
$table->restrictOnUpdate(); Las actualizaciones deben ser restringidas.
$table->noActionOnUpdate(); Sin acción en las actualizaciones.
$table->cascadeOnDelete(); Las eliminaciones deben ser en cascada.
$table->restrictOnDelete(); Las eliminaciones deben ser restringidas.
$table->nullOnDelete(); Las eliminaciones deben establecer el valor de la clave foránea en null.
Cualquier [modificador de columna](#column-modifiers) adicional debe ser llamado antes del método `constrained`:
$table->foreignId('user_id')
->nullable()
->constrained();

Eliminando Claves Foráneas

Para eliminar una clave foránea, puedes usar el método dropForeign, pasando el nombre de la restricción de clave foránea que se va a eliminar como argumento. Las restricciones de clave foránea utilizan la misma convención de nombres que los índices. En otras palabras, el nombre de la restricción de clave foránea se basa en el nombre de la tabla y las columnas en la restricción, seguido de un sufijo "_foreign":

$table->dropForeign('posts_user_id_foreign');

Alternativamente, puedes pasar un array que contenga el nombre de la columna que tiene la clave foránea al método dropForeign. El array se convertirá en un nombre de restricción de clave foránea utilizando las convenciones de nomenclatura de restricciones de Laravel:

$table->dropForeign(['user_id']);

Alternando las restricciones de clave foránea

Puedes habilitar o deshabilitar las restricciones de claves foráneas dentro de tus migraciones utilizando los siguientes métodos:

Schema::enableForeignKeyConstraints();
 
Schema::disableForeignKeyConstraints();
 
Schema::withoutForeignKeyConstraints(function () {
// Constraints disabled within this closure...
});

[!WARNING] SQLite desactiva las restricciones de claves foráneas por defecto. Al usar SQLite, asegúrate de habilitar el soporte de claves foráneas en tu configuración de base de datos antes de intentar crearlas en tus migraciones.

Eventos

Para mayor comodidad, cada operación de migración despachará un evento. Todos los siguientes eventos extienden la clase base Illuminate\Database\Events\MigrationEvent:

Clase Descripción
Illuminate\Database\Events\MigrationsStarted Un lote de migraciones está a punto de ser ejecutado.
Illuminate\Database\Events\MigrationsEnded Un lote de migraciones ha terminado de ejecutarse.
Illuminate\Database\Events\MigrationStarted Una sola migración está a punto de ser ejecutada.
Illuminate\Database\Events\MigrationEnded Una sola migración ha terminado de ejecutarse.
Illuminate\Database\Events\NoPendingMigrations Un comando de migración no encontró migraciones pendientes.
Illuminate\Database\Events\SchemaDumped Se ha completado un volcado de esquema de base de datos.
Illuminate\Database\Events\SchemaLoaded Se ha cargado un volcado de esquema de base de datos existente.