¿ Cómo crear una migración en Laravel para actualizar de forma masiva a todas las claves foráneas ?

renzocastillo

Renzo Castillo

Posted on January 12, 2022

¿ Cómo crear una migración en Laravel para actualizar de forma masiva a todas las claves foráneas  ?

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');
                    }
                }
            });

        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Espero haberles ayudado y que ahora tengan más tiempo . Si tienen alguna sugerencia, preguntas o mejoras pueden escribirme y procuraré responderles pronto.

Saludos!

💖 💪 🙅 🚩
renzocastillo
Renzo Castillo

Posted on January 12, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

What was your win this week?
weeklyretro What was your win this week?

November 29, 2024

Where GitOps Meets ClickOps
devops Where GitOps Meets ClickOps

November 29, 2024

How to Use KitOps with MLflow
beginners How to Use KitOps with MLflow

November 29, 2024

Modern C++ for LeetCode 🧑‍💻🚀
leetcode Modern C++ for LeetCode 🧑‍💻🚀

November 29, 2024