12

I am having many migration and seeder files to run, Although I will need to run all files but currently I need to skip one migration and seeder.

How could I skip one file from laravel migration and db seeder command.

I do not want to delete files from the migrations or seeds folder to skip the file.

Niklesh Raut
  • 34,013
  • 16
  • 75
  • 109

6 Answers6

8

Laravel doesn't give you a default method to do it. However, you can create your own console commands and seeder to achieve it.
Let's say you have this default DatabaseSeeder class:

class DatabaseSeeder extends Seeder
{
    public function run()
    {
        $this->call(ExampleTableSeeder::class);
        $this->call(UserSamplesTableSeeder::class);
    }
}

the goal is to create a new command overriding "db:seed" and pass a new parameter, an "except" parameter, to the DatabaseSeeder class.

This is the final code, I created on my Laravel 5.2 instance and tried:

Command, put in app/Console/Commands, don't forget to update your Kernel.php:

namespace App\Console\Commands;
use Illuminate\Console\Command;
class SeedExcept extends Command
{
    protected $signature = 'db:seed-except {--except=class name to jump}';
    protected $description = 'Seed all except one';
    public function handle()
    {
        $except = $this->option('except');
        $seeder = new \DatabaseSeeder($except);
        $seeder->run();
    }
}

DatabaseSeeder

use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
    protected $except;

    public function __construct($except = null) {
        $this->except = $except;
    }

    public function call($class)
    {
        if ($class != $this->except)
        {
            echo "calling $class \n";
            //parent::call($class);  // uncomment this to execute after tests
        }
    }

    public function run()
    {
        $this->call(ExampleTableSeeder::class);
        $this->call(UserSamplesTableSeeder::class);
    }
}

It the code, you'll find that I commented the line that calls the seed and added an echo for testing purposes.

Executing this command:

php artisan db:seed-except

will give you:

calling ExampleTableSeeder
calling UserSamplesTableSeeder

However, adding "except":

php artisan db:seed-except --except=ExampleTableSeeder

will give you

calling UserSamplesTableSeeder

This works overriding the default call method of your DatabaseSeeder class and calling the parent only if the name of the class is not in the $except variable. The variable is populated by the SeedExcept custom command.

Regarding migrations, the thing is similar but a little bit more difficult.

I can't give you tested code for this by now, but the thing is:

  • you create a migrate-except command that overrides the MigrateCommand class (namespace Illuminate\Database\Console\Migrations, located in vendor/laravel/framework/src/Illuminate/Database/Console/Migrations/MigrateCommand.php).
  • the MigrateCommand takes a Migrator object (namespace Illuminate\Database\Migrations, path vendor/laravel/framework/src/Illuminate/Database/Migrations/Migrator.php) in the constructor (injected via IoC). The Migrator class owns the logic that reads all the migrations inside the folder and execute it. This logic is inside the run() method
  • create a subclass of Migrator, for example MyMigrator, and override the run() method to skip the files passed with the special option
  • override the __construct() method of your MigrateExceptCommand and pass your MyMigrator: public function __construct(MyMigrator $migrator)

If I have time I'll add the code for an example before the bounty ends

EDIT as promised, here's an example for migrations:

MyMigrator class, extends Migrator and contains the logic to skip files:

namespace App\Helpers;
use Illuminate\Database\Migrations\Migrator;
class MyMigrator extends Migrator
{
    public $except = null;

    // run() method copied from it's superclass adding the skip logic
    public function run($path, array $options = [])
    {
        $this->notes = [];

        $files = $this->getMigrationFiles($path);

        // skip logic
        // remove file from array
        if (isset($this->except))
        {
            $index = array_search($this->except,$files);
            if($index !== FALSE){
                unset($files[$index]);
            }
        }
        var_dump($files); // debug

        $ran = $this->repository->getRan();
        $migrations = array_diff($files, $ran);
        $this->requireFiles($path, $migrations);

        //$this->runMigrationList($migrations, $options);  // commented for debugging purposes
    }
}

The MigrateExcept custom command

namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Database\Console\Migrations\MigrateCommand;
use App\Helpers\MyMigrator;
use Illuminate\Database\Migrations\Migrator;
use Symfony\Component\Console\Input\InputOption;

class MigrateExcept extends MigrateCommand
{
    protected $name = 'migrate-except'; 

    public function __construct(MyMigrator $migrator)
    {   
        parent::__construct($migrator);
    }

    public function fire()
    {
        // set the "except" param, containing the name of the file to skip, on our custom migrator
        $this->migrator->except = $this->option('except');
        parent::fire();
    }

    // add the 'except' option to the command
    protected function getOptions()
    {
        return [
            ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use.'],

            ['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production.'],

            ['path', null, InputOption::VALUE_OPTIONAL, 'The path of migrations files to be executed.'],

            ['pretend', null, InputOption::VALUE_NONE, 'Dump the SQL queries that would be run.'],

            ['seed', null, InputOption::VALUE_NONE, 'Indicates if the seed task should be re-run.'],

            ['step', null, InputOption::VALUE_NONE, 'Force the migrations to be run so they can be rolled back individually.'],

            ['except', null, InputOption::VALUE_OPTIONAL, 'Files to jump'],
        ];
    }
}

Last, you need to add this to a service provider to permit the Laravel IoC resolve the dependencies

namespace App\Providers;
use App\Helpers\MyMigrator;
use App\Console\Commands\MigrateExcept;


class CustomServiceProvider extends ServiceProvider
{
    public function boot()
    {
        parent::boot($events);

        $this->app->bind('Illuminate\Database\Migrations\MigrationRepositoryInterface', 'migration.repository');
        $this->app->bind('Illuminate\Database\ConnectionResolverInterface', 'Illuminate\Database\DatabaseManager');

        $this->app->singleton('MyMigrator', function ($app) {
            $repository = $app['migration.repository'];
            return new MyMigrator($repository, $app['db'], $app['files']);
        });
    }
}

Don't forget to add Commands\MigrateExcept::class in the Kernel.php

Now, if you execute

php artisan migrate-except

you have:

array(70) {
  [0] =>
  string(43) "2014_04_24_110151_create_oauth_scopes_table"
  [1] =>
  string(43) "2014_04_24_110304_create_oauth_grants_table"
  [2] =>
  string(49) "2014_04_24_110403_create_oauth_grant_scopes_table"
  ...

but adding the except param:

php artisan migrate-except --except=2014_04_24_110151_create_oauth_scopes_table

array(69) {
  [1] =>
  string(43) "2014_04_24_110304_create_oauth_grants_table"
  [2] =>
  string(49) "2014_04_24_110403_create_oauth_grant_scopes_table"

So, recap:

  • we create a custom migrate-except command, MigrateExcept class, extending MigrateCommand
  • we create a custom migrator class, MyMigrator, extending the behavior of the standard Migrator
  • when MigrateExcept is fire(), pass the name of the file to skip to our MyMigrator class
  • MyMigrator overrides the run() method of Migrator and skip the passed migration
  • More: since we need to instruct Laravel IoC about the new created classes, so it can inject them correctly, we create a Service Provider

The code is tested so it should work correctly on Laravel 5.2 (hoping that cut&paste worked correctly :-) ...if anyone has any doubt leave a comment

LombaX
  • 17,265
  • 5
  • 52
  • 77
4

Skipping seeds are very simple, migrations not so much. To skip a seed, remove the following from your DatabaseSeeder class.

$this->call(TableYouDontWantToSeed::class);

For migrations, There are three ways you can do it:

  • Put the class you don't want to migrate into a different folder.
  • Insert your migrations into the database manually (Bindesh Pandya's answer elaborated).
  • Rename the file that you don't want to migrate to something like UsersTableMigration.dud.

Hope this helps

Dastur
  • 684
  • 6
  • 23
  • downvote because the OP specifically said that he don't want to remove migrations manually from the seeder class – LombaX Jul 27 '16 at 17:42
  • No you just downvoted so we would have the same amount of votes...thanks a lot. – Dastur Jul 27 '16 at 17:43
  • If it was the case, why would I have commented and letting know the source of the downvote? Since now it seems that you downvoted my question for revenge (what's your age?) please explain the reason behind it. Regards – LombaX Jul 27 '16 at 17:45
  • he said specifically that he doesn't want the solution that you are proposing. So difficult to understand? – LombaX Jul 27 '16 at 17:47
  • He never said he didn't want to delete migration calls from the databasemigration file he just said he didn't want files deleted. – Dastur Jul 27 '16 at 17:50
  • Removing a file or removing a function call manually is the same. There is the need to update a source file that probably is versioned, and so each time you pull/push from repo you have to apply the update again. However, I don't have more time to waste explaining you this, keep doing things wrong and give bad advices and enjoy. Regards – LombaX Jul 27 '16 at 17:52
2

I also faced the same problem in my project but after long time wasting in R & D i have found that Laravel does not provide any way to do this with migration and seeding but you have 2 ways to do this.

1) you'll save a lot of time just putting them into different folders. You could theoretically make your own artisan command that does what you want, or spoofs its by making directories, moving files, and running php artisan migrate.

For the seeders, just make a seeder and call the others seeders you want to run from with in it. Then just be explicit about what seeder you want to run. Try php artisan db:seed --help for more details there.

2) you can create a table Manually (which has same name as migration table is creating in you db) and insert the values of migration like this

insert into migrations(migration, batch) values('2015_12_08_134409_create_tables_script',1);

so migrate command will not create table which is already exist in migration table.

Bindesh Pandya
  • 193
  • 3
  • 14
1

If you want just omit (but keep) migration and seeder:

  1. Rename your migration by removing .php extension: mv your_migration_file.php your_migration_file
  2. Go to: DatabaseSeeder.php and comment out line with your unwanted seeder: //$this->call('YourSeeder');.
  3. Run: php artisan migrate --seed
  4. Execute below sql query on db (be careful, there should be migration file name WITHOUT extension) (this will prevent artisan migrate to execute your_migration_file in future):

    INSERT INTO migrations (migration, batch) VALUES (your_migration_file, 1)

  5. Rename back your migration file: mv your_migration_file your_migration_file.php

  6. Uncomment your seeder in DatabaseSeeder.php

And you are done. Now when you run php artisan migrate any migration should be executed (except new one if you add some new migration files).

Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345
0

just an idea comment seeder and schema. this is the way i guess

//$this->call(HvAccountsSeeder::class);

//Schema::create('users', function (Blueprint $table) {
          //  $table->increments('id');
          //  $table->string('name');
          //  $table->string('email')->unique();
          //  $table->string('password');
          //  $table->rememberToken();
           // $table->timestamps();
       // });
// Schema::drop('users');
Hamelraj
  • 4,676
  • 4
  • 19
  • 42
0

To directly answer your question, Laravel does not have a way to do this currently.

If I understand you correctly, I assume you're looking for a way to temporarily disable/skip a specific class from the default DatabaseSeeder.

You can easily create your own command which will accept a string such as a model/table name and attempt to run the migration and seed for that particular table. You will simply need something like the following:

public function handle(){ //fire for Laravel 4.*

    $tables = explode(',', $this->option('tables'));//default []
    $skip = explode(',', $this->option('skip'));//default [] 
    $migrations = glob("*table*.php");//get all migrations
    foreach($migrations as $migrate){
        //if tables argument is set, check to see if part of tables
        //if file name not like any in skip.. you get the point
Chibueze Opata
  • 9,856
  • 7
  • 42
  • 65