23

Is there a way to make data migrations in Laravel? I've found some instructions on how to seed the database, but it doesn't cover cases where I need to split one field into multiple fields, or merge multiple fields into one.

One possible solution is to query the database and update each record on a loop. The problem with this approach is that the models may not reflect the table schema during the migration (Django provides a solution for this).

Eduardo Matos
  • 741
  • 2
  • 6
  • 14

1 Answers1

45

Laravel has migrations built in :) http://laravel.com/docs/migrations

Simply run

php artisan make:migration migration_name_here

and it will create a migration under app/database/migrations. You could then use Laravel's database classes in your up() and down() methods.

Let's use this as an example...

class SplitColumn extends Migration {

    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('table_name', function($table)
        {
            // Create new columns for table_name (1 column split into 2).
            $table->string('new_column');
            $table->string('new_column_b');
        });

        // Get records from old column.
        $results = DB::table('table_name')->select('old_column')->get();

        // Loop through the results of the old column, split the values.
        // For example, let's say you have to explode a |.
        foreach($results as $result)
        {
            $split_value = explode("|", $result->old_column);

            // Insert the split values into new columns.
            DB::table('table_name')->insert([
                "new_column"    =>  $split_value[0],
                "new_column_b"  =>  $split_value[1]
            ]);
        }

        // Delete old column.
        Schema::table('table_name', function($table)
        {
            $table->dropColumn('old_column');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('table_name', function($table)
        {
            // Re-create the old column.
            $table->string('old_column');
        });

        // Get records from old column.
        $results = DB::table('table_name')->select('new_column', 'new_column_b')->get();

        // Loop through the results of the new columns and merge them.
        foreach($results as $result)
        {
            $merged_value = implode("|", [$result->new_column, $result->new_column_b]);

            // Insert the split values into re-made old column.
            DB::table('table_name')->insert([
                "old_column"    =>  $merged_value
            ]);
        }

        // Delete new columns.
        Schema::table('table_name', function($table)
        {
            $table->dropColumn('new_column');
            $table->dropColumn('new_column_b');
        });
    }
}
Islam Murtazaev
  • 1,488
  • 2
  • 17
  • 27
Kisuka
  • 1,832
  • 1
  • 15
  • 10
  • The problem with this solution is that if there are a lot of records you are going to be making many queries, one for each record in the database and you are assuming that there is exactly one pipe in the string. There should be a way to do this with one or perhaps two queries – Zachary Weixelbaum Jan 19 '18 at 13:59
  • related answer about migration data in Laravel: https://stackoverflow.com/a/56306366/470749 – Ryan Dec 12 '19 at 21:33