¿ Cómo crear una migración en Laravel para actualizar de forma masiva a todas las claves foráneas ?
Renzo Castillo
Posted on January 12, 2022
En este post te enseñaré a sacarle provecho a Doctrine , que es una librería, que está incluida como dependencia en laravel y en otros frameworks, y que permite gestionar a tus achivos de migraciones de la base de datos. Hace poco tuve que hacer una actualización de una base datos con cierta cantidad de tablas y la verdad que con sólo verlo me cansé en pensar tener que hacer un montón de migraciones secuenciales que prácticamente seguían la misma lógica.
Primero les voy a dejar el código comentado y si quieren colocar esta migración les dejaré la versión sin comentar más abajo.
Bueno el primer paso es obviamente crear tu migración con el comando
php artisan make:migration rebuild_foreign_keys_with_on_delete_cascade_on_update_cascade
Una vez creado nuestro archivo de migración entramos a éste y creamos las funciones que pasaré a explicar dentro del código:
<?php
use IlluminateSupportFacadesSchema;
use IlluminateDatabaseSchemaBlueprint;
use IlluminateDatabaseMigrationsMigration;
class RebuildForeignKeysWithOnDeleteCascadeOnUpdateCascade extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
// Nos conectamos a la BD y llamamos a DoctrineSchemaManager para hacer la magia.
$con= Schema::getConnection()->getDoctrineSchemaManager();
// Aquí recuperamos a todos los nombres de las tablas en tu bd.
$tb_names=$con->listTableNames();
// Empezaremos a rastrear a todas las claves foráneas por cada tabla
foreach($tb_names as $tb_name){
/* Aquí el nombre de la tabla será usado en la función indica la documentación
de laravel para poder modificar las columnas y demás aspectos de la tabla*/
Schema::table($tb_name, function (Blueprint $table) use ($tb_name,$con) {
// Aquí dentro llamaremos a todas las claves foráneas de esta tabla en concreto
$foreignKeys=$con->listTableForeignKeys($tb_name);
// Primero obviamente chequeamos si está vacío para evaluar si corremos o no esto.
if(count($foreignKeys)){
/* Una vez que nos aseguramos que hay claves foráneas procedemos con la actualización
de ON DELETE NO ACTION a ON DELETE CASCADE. Empezamos a ir clave por clave*/
foreach($foreignKeys as $foreignKey){
// Recuperamos la columna local o sea la columna que guarda el id de la relación foránea
$local_col=$foreignKey->getLocalColumns()[0];
// Aquí recuperamos el nombre de nuestra tabla foránea
$foreign_table=$foreignKey->getForeignTableName();
// Aquí obtenemos la columna de nuestra tabla foránea
$foreign_col=$foreignKey->getForeignColumns()[0];
// Aquí obtenemos el nombre actual que tiene la clave foránea
$fk_name=$foreignKey->getName();
/* Ahora procedemos a romper esta relación foránea,que es lo normal que haríamos
si quremos actualizar a una relación foránea de ON DELETE NO ACTION a CASCADE*/
$table->dropForeign($fk_name);
/* Una vez rota la relación la reconstruimos asumiendo el comportamiento es cascada
para los eventos ON DELETE y ON UPDATE de nuestra base de datos */
$table
->foreign($local_col, $fk_name)
->references($foreign_col)
->on($foreign_table)
->onUpdate('CASCADE')
->onDelete('CASCADE');
}
}
});
}
}
/**
* Reverse the migrations.
*
* @return void
*/
/* Para el rollback de esta migración hacemos lo mismo con la única diferencia que
ahora vamos a devolver la relación a ON DELETE NO ACTION.*/
public function down()
{
$con= Schema::getConnection()->getDoctrineSchemaManager();
$tb_names=$con->listTableNames();
foreach($tb_names as $tb_name){
Schema::table($tb_name, function (Blueprint $table) use ($tb_name,$con) {
$foreignKeys=$con->listTableForeignKeys($tb_name);
if(count($foreignKeys)){
foreach($foreignKeys as $foreignKey){
$local_col=$foreignKey->getLocalColumns()[0];
$foreign_table=$foreignKey->getForeignTableName();
$foreign_col=$foreignKey->getForeignColumns()[0];
$fk_name=$foreignKey->getName();
$table->dropForeign($fk_name);
$table
->foreign($local_col, $fk_name)
->references($foreign_col)
->on($foreign_table)
->onUpdate('NO ACTION')
->onDelete('NO ACTION');
}
}
});
}
}
}
Espero haberles ayudado y que ahora tengan más tiempo . Si tienen alguna sugerencia, preguntas o mejoras pueden escribirme y procuraré responderles pronto.
Saludos!
Posted on January 12, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.