Migracions
Com crear i gestionar migracions a Laravel: crear taules, modificar columnes i fer rollback.
Què són les migracions?#
Les migracions són com un control de versions per a la teva base de dades. En lloc de crear taules manualment amb un client SQL, les migracions et permeten definir l'esquema en codi PHP que es pot versionar amb Git, compartir amb l'equip i executar de manera automàtica en qualsevol entorn. Cada migració representa un canvi concret a l'estructura de la base de dades.
Crear una migració#
Per crear una migració, utilitza la comanda Artisan make:migration. Laravel genera automàticament un fitxer amb una marca de temps que determina l'ordre d'execució:
php artisan make:migration create_articles_tableAixò crea un fitxer a database/migrations/ amb dos mètodes: up() defineix els canvis a aplicar i down() defineix com revertir-los:
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('articles', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->string('slug')->unique();
$table->text('body');
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->boolean('published')->default(false);
$table->timestamp('published_at')->nullable();
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('articles');
}
};El mètode up() utilitza Schema::create() per crear la taula amb les seves columnes. El mètode down() fa l'operació inversa: elimina la taula. Això permet fer rollback de la migració si cal.
Executar migracions#
Les comandes principals per gestionar migracions són:
# Executar totes les migracions pendents
php artisan migrate
# Veure l'estat de les migracions (quines s'han executat i quines no)
php artisan migrate:status
# Fer rollback de l'última tanda de migracions
php artisan migrate:rollback
# Fer rollback de totes les migracions
php artisan migrate:reset
# Fer rollback de tot i tornar a executar-ho
php artisan migrate:refresh
# Esborrar totes les taules i executar les migracions des de zero
php artisan migrate:fresh
# Executar migracions i seeders
php artisan migrate:fresh --seedLa diferència entre refresh i fresh és important: refresh executa el mètode down() de cada migració en ordre invers i després torna a executar up(). fresh simplement elimina totes les taules i executa les migracions des de zero, cosa que és més ràpid i evita problemes si algun mètode down() està mal definit.
Tipus de columnes#
Laravel proporciona mètodes per a tots els tipus de columnes comuns. El Blueprint ofereix una API fluida per definir l'estructura de la taula:
Schema::create('products', function (Blueprint $table) {
// Identificadors
$table->id(); // BIGINT UNSIGNED auto-increment
$table->uuid('uuid'); // UUID
// Strings
$table->string('name'); // VARCHAR(255)
$table->string('code', 50); // VARCHAR(50)
$table->text('description'); // TEXT
$table->longText('content'); // LONGTEXT
$table->char('country_code', 2); // CHAR(2)
// Numèrics
$table->integer('quantity'); // INTEGER
$table->bigInteger('views'); // BIGINT
$table->tinyInteger('rating'); // TINYINT
$table->decimal('price', 10, 2); // DECIMAL(10,2)
$table->float('weight'); // FLOAT
// Booleans i dates
$table->boolean('active'); // BOOLEAN
$table->date('birth_date'); // DATE
$table->dateTime('starts_at'); // DATETIME
$table->time('opening_time'); // TIME
$table->timestamp('verified_at'); // TIMESTAMP
$table->year('graduation_year'); // YEAR
// Altres
$table->json('options'); // JSON
$table->enum('status', ['draft', 'published', 'archived']);
// Columnes automàtiques
$table->timestamps(); // created_at i updated_at
$table->softDeletes(); // deleted_at per a soft deletes
});Modificadors de columna#
Pots encadenar modificadors per personalitzar el comportament de cada columna:
$table->string('email')->unique(); // Índex únic
$table->string('category')->nullable(); // Permet NULL
$table->integer('votes')->default(0); // Valor per defecte
$table->string('bio')->nullable()->default(null); // NULL per defecte
$table->string('phone')->after('email'); // Posició (MySQL)
$table->text('notes')->comment('Notes internes'); // Comentari a la BD
$table->integer('position')->unsigned(); // Sense signeClaus foranes#
Les claus foranes defineixen relacions entre taules i garanteixen la integritat referencial. Laravel ofereix una sintaxi curta i expressiva:
// Sintaxi curta (recomanada)
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
// Equivalent a:
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')
->references('id')
->on('users')
->onDelete('cascade');El mètode constrained() infereix automàticament el nom de la taula a partir del nom de la columna (user_id busca la taula users). Si el nom de la columna no segueix la convenció, pots especificar la taula manualment:
$table->foreignId('author_id')->constrained('users')->cascadeOnDelete();Les opcions per a onDelete i onUpdate són cascade (propaga l'acció), restrict (bloqueja l'acció), set null (estableix NULL) i no action:
$table->foreignId('category_id')
->nullable()
->constrained()
->nullOnDelete(); // Estableix NULL quan s'elimina la categoriaÍndexs#
Els índexs milloren el rendiment de les consultes. Pots afegir-los directament a la definició de la columna o com a línies separades:
// A la columna
$table->string('email')->unique();
$table->string('slug')->index();
// Com a línia separada (útil per a índexs compostos)
$table->index(['user_id', 'created_at']);
$table->unique(['email', 'tenant_id']);Modificar taules existents#
Per modificar una taula que ja existeix, crea una nova migració amb un nom descriptiu. Laravel reconeix patrons com add_*_to_*_table o remove_*_from_*_table:
php artisan make:migration add_category_to_articles_tablepublic function up(): void
{
Schema::table('articles', function (Blueprint $table) {
$table->string('category')->after('title')->nullable();
$table->index('category');
});
}
public function down(): void
{
Schema::table('articles', function (Blueprint $table) {
$table->dropIndex(['category']);
$table->dropColumn('category');
});
}Per renombrar o canviar el tipus d'una columna, necessites el paquet doctrine/dbal:
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->string('name', 100)->change(); // Canviar la mida
$table->renameColumn('name', 'full_name'); // Renombrar
});
}Eliminar taules i columnes#
// Eliminar una taula
Schema::dropIfExists('articles');
// Eliminar columnes
Schema::table('articles', function (Blueprint $table) {
$table->dropColumn(['category', 'subcategory']);
});
// Eliminar una clau forana i la columna
Schema::table('articles', function (Blueprint $table) {
$table->dropForeign(['user_id']);
$table->dropColumn('user_id');
});Squashing de migracions#
Quan un projecte acumula moltes migracions al llarg del temps, pots compactar-les en un sol fitxer SQL per mantenir el directori net:
php artisan schema:dump
# Compactar i eliminar les migracions antigues
php artisan schema:dump --pruneAixò genera un fitxer SQL a database/schema/ que es carrega automàticament abans d'executar les migracions pendents. Les noves migracions s'afegeixen amb normalitat.