47

I have a complete database and need to create migration. I guess there must be a way to do it from a dump but not sure. Is there any way automatically or at least easier to do this task?

Paul
  • 4,160
  • 3
  • 30
  • 56
vladzur
  • 503
  • 1
  • 4
  • 7

12 Answers12

64

You can import dumps in Laravel like this:

DB::unprepared(file_get_contents('full/path/to/dump.sql'));

If I were to refactor an existing app, though, I'd take the time to write migrations from scratch, import the dump into different tables (or a different db, if table names are the same) then import the content to the new structure via seeds.

Tomas Buteler
  • 3,892
  • 4
  • 29
  • 42
  • 2
    what if the filesize is too large to fit in memory? – doc_id Aug 19 '16 at 04:22
  • 1
    That's a different problem altogether. You can increase the memory limit in your PHP's ini file, or do it programatically on your seeder like this: `ini_set('memory_limit', '-1')` – Tomas Buteler Aug 19 '16 at 11:08
  • Yes it's a different problem but still file_get_contents will fail with "too large" files, like many many gigabytes. I would use your approach but with fopen and fgets. phpMyAdmin exports can be chunked with "INSERT INTO" – doc_id Aug 30 '16 at 06:57
20

Laravel can't do that, but I think this will help: Laravel migration generator

It generate migrations based on existing tables.

Kevin Gorjan
  • 1,272
  • 1
  • 17
  • 34
14

This question is answered already, but recently in a project, the provided answers did not satisfy my needs any longer. It also does not import a whole database dump, but one (large) table. I felt I should share that with you.

The problem was, I wanted to import a quite large table (list of zipcodes) during my artisan:migrate operation. The solution with DB::unprepared($dump) took way to long and I found an alternative which is MUCH faster.

Just export your table as CSV and use the following Code in your migration's up() function.

    // i had to str_replace the backslash on windows dev system... but works on linux, too
    $filename = str_replace("\\", "/", storage_path('path/in/storage/to/your/file.csv'));

    $query = "LOAD DATA LOCAL INFILE '".$filename."' INTO TABLE yourtable
        FIELDS TERMINATED BY '\t'
        ENCLOSED BY ''
        LINES TERMINATED BY '\n'
        IGNORE 0 LINES
        (col1,col2,...);";

    DB::unprepared($query);

Just update the query as you need. And of course, you should make sure, that the table with the cols 'col1', 'col2' etc... exists. I created it just before the importing of the file. with Schema::create()...

If you run into following error message:

PDO::exec(): LOAD DATA LOCAL INFILE forbidden

There is a way you can get rid of this message: Although it's not really documented you can just add an 'options' key to your config/database.php file. For example mine looks like that:

        'mysql' => [
        'driver'    => 'mysql',
        'host'      => env('DB_HOST', 'localhost'),
        'database'  => env('DB_DATABASE', 'forge'),
        'username'  => env('DB_USERNAME', 'forge'),
        'password'  => env('DB_PASSWORD', ''),
        'charset'   => 'utf8',
        'collation' => 'utf8_unicode_ci',
        'prefix'    => '',
        'strict'    => false,
        'options'   => array(
            PDO::MYSQL_ATTR_LOCAL_INFILE => true,
        )

Note: i'm currently using laravel 5 but it should work with laravel 4, too.

shock_gone_wild
  • 6,700
  • 4
  • 28
  • 52
  • 2
    this is probabily the best absolutely way, especially when the database gets huge – dynamic Apr 02 '15 at 08:55
  • 1
    That is a good solution as long as the database server exists on the same machine as the webserver, because `LOAD DATA LOCAL INFILE` will fail otherwise. – doc_id Aug 19 '16 at 04:19
  • @rahmanisback no, the file path needs to be a path to the file on the databaseserver, no matter where that database is. So if you put your dump in /tmp/dump.sql on a remote database and you call it with that path, it will work. – Ellert van Koperen Oct 13 '17 at 08:43
  • @EllertvanKoperen yes exactly but migration scripts are parts of the application code and one should never assume any code files will go to database server. Also Migration, as a term, should be bundled with application code, not uploaded to database server individually in case db server is different than web server. One should code with no initial premise of where database and application are hosted. – doc_id Oct 15 '17 at 09:33
  • @rahmanisback you are right about what one should assume and not assume. However the remote restore does work, and in some cases is a very important timesaver. – Ellert van Koperen Oct 16 '17 at 13:48
12

I have a complete database and need to create migration. I guess there must be a way to do it from a dump but not sure. Is there any way automatically or at least easier to do this task?

Not automatically, but we run dumps in a migration using DB::unprepared(). You could use file_get_contents to import from a .sql file and thus not have to worry about escaping the entire dump's " marks...

<?php

use Illuminate\Database\Migrations\Migration;

class ImportDump extends Migration {

    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        DB::unprepared("YOUR SQL DUMP HERE");
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {

    }

}
ceejayoz
  • 176,543
  • 40
  • 303
  • 368
11

Another alternative is using the PDO directly:

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;

$sql_dump = File::get('/path/to/file.sql');
DB::connection()->getPdo()->exec($sql_dump);
kio_tk
  • 47
  • 7
zmonteca
  • 2,304
  • 1
  • 26
  • 26
  • 2
    It will be pretty useful to specify what specific `File` class you suggest to use. – Akim Kelar Jun 05 '19 at 10:22
  • When using this option, you can use the file_get_contents function to get the sql dump. Also ensure you do not use LOCK TABLES, otherwise you will get an error when Laravel writes into the migrations table – rayalois22 Jul 21 '20 at 22:25
9

I am writing my answer as this might help to someone who is using new laravel 8.

In laravel 8, dumping SQL and run migration using SQL(.dump) file is possible. Please refer below link for more detail.

https://laravel.com/docs/8.x/migrations#squashing-migrations

php artisan schema:dump

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

schema:dump will create new directory under database > schema and SQL dump will stored there. After that when you try to migrate first it will run dump file from schema and then any pending migration.

Mave
  • 2,413
  • 3
  • 28
  • 54
Pragnesh Chauhan
  • 8,363
  • 9
  • 42
  • 53
  • 4
    7 years after my original question. Laravel 8 do the right with schema:dump – vladzur Apr 21 '21 at 19:00
  • 1
    Additionally, "Now, when you attempt to migrate your database and no other migrations have been executed, Laravel will first execute the SQL statements in the schema file of the database connection you are using." https://laravel.com/docs/10.x/migrations#squashing-migrations – joels Apr 05 '23 at 01:58
6

another solution work for me in Laravel 5.2:

DB::unprepared(File::get('full/path/to/dump.sql'));

Choirul MA
  • 61
  • 1
  • 2
  • Interesting and elegant approach that should work but isn't in my case. Would be interesting to know more. – Jonathan Feb 03 '17 at 09:15
  • 3
    If you use a dump from phpmyadmin, it often include option like following : ```SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; SET time_zone = "+00:00";``` Get rid of it, and it's going to work – Robin Choffardet May 04 '17 at 10:00
3

Simple solution provided by Laravel Article for generating migration file from an existing database table.

Try: https://laravelarticle.com/laravel-migration-generator-online enter image description here

Community
  • 1
  • 1
Akash khan
  • 861
  • 13
  • 25
3

If you can dump to a CSV: An alternative for some generic data tables (Countries, States, Postal Codes), not via migrations but via seeders. Although you could do it the same way in a migration file.

In your seeder file:

    public function run()
    {
        $this->insertFromCsvFile('countries', 'path/to/countries.csv');
        $this->insertFromCsvFile('states', 'path/to/states.csv');
        $this->insertFromCsvFile('postal_codes', 'path/to/postal_codes.csv');
    }

    private function insertFromCsvFile($tableName, $filePath)
    {
        if( !file_exists($filePath) ){
            echo 'File Not Found: '.$filePath."\r\n";
            return;
        }
        $headers = $rows = [];
        $file = fopen( $filePath, 'r' );
        while( ( $line = fgetcsv( $file ) ) !== false ){

            // The first row should be header values that match column names.
            if( empty( $headers ) ){
                $headers = explode( ',', implode( ',', $line ) );
                continue;
            }

            $row = array_combine( $headers, $line );
            foreach( $row as &$val ) if( $val === 'NULL' ) $val = null;
            $rows[] = $row;

            // Adjust based on memory constraints.
            if( count($rows) === 500 ){
                DB::table( $tableName )->insert($rows);
                $rows = [];
            }
        }
        fclose( $filePath );

        if( count($rows) ) DB::table( $tableName )->insert($rows);
    }

Run the seeder: php artisan db:seed --class=GenericTableSeeder

JoBar
  • 178
  • 1
  • 1
  • 7
2

You can create laravel migration and models directly from database using https://github.com/XCMer/larry-four-generator

Execute the following code after installing the package

php artisan larry:fromdb
Sriraman
  • 7,658
  • 4
  • 40
  • 60
2

i recently standing in front of the same problem. i didn't want to install a package specially for that, so i decided to write a little tool to help me and others ;)

Here is the link: http://laravel.stonelab.ch/sql-seeder-converter/

And here you can comment it, if you have any improvement proposals or questions: http://www.stonelab.ch/en/sql-to-laravel-seeder-converter/

mastercheef85
  • 2,109
  • 3
  • 18
  • 25
1

You can use Raahul/Larryfour Package, A model and migration generator for Laravel 4

Raahul/Larryfour Package

After insallation you can use a command line to create a migration from existed database like this:

php artisan raahul:fromdb --only yourdatabase

And you will find the migration in app/migrations/ folder

Tarasovych
  • 2,228
  • 3
  • 19
  • 51
JohnTaa
  • 2,722
  • 2
  • 15
  • 15