dqjcb132285 2016-02-04 03:01
浏览 80
已采纳

除了一个之外,如何运行laravel migration和DB seeder

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.

  • 写回答

6条回答 默认 最新

  • drxrgundk062317205 2016-07-27 14:04
    关注

    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 
    ";
                //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

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(5条)

报告相同问题?

悬赏问题

  • ¥15 基于卷积神经网络的声纹识别
  • ¥15 Python中的request,如何使用ssr节点,通过代理requests网页。本人在泰国,需要用大陆ip才能玩网页游戏,合法合规。
  • ¥100 为什么这个恒流源电路不能恒流?
  • ¥15 有偿求跨组件数据流路径图
  • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值
  • ¥15 我想咨询一下路面纹理三维点云数据处理的一些问题,上传的坐标文件里是怎么对无序点进行编号的,以及xy坐标在处理的时候是进行整体模型分片处理的吗
  • ¥15 CSAPPattacklab
  • ¥15 一直显示正在等待HID—ISP
  • ¥15 Python turtle 画图
  • ¥15 stm32开发clion时遇到的编译问题