如何运行 Laravel 迁移和 DB 播种机,除了一个

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35191709/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 13:10:37  来源:igfitidea点击:

How to run laravel migration and DB seeder except one

phplaravellaravel-migrationslaravel-seeding

提问by Niklesh Raut

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.

我怎么能从 laravel 迁移和 db seeder 命令中跳过一个文件。

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

我不想从迁移或种子文件夹中删除文件以跳过该文件。

采纳答案by LombaX

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 DatabaseSeederclass:

Laravel 没有给你一个默认的方法来做到这一点。但是,您可以创建自己的控制台命令和播种器来实现它。
假设您有这个默认DatabaseSeeder类:

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 DatabaseSeederclass.

目标是创建一个覆盖“db:seed”的新命令,并将一个新参数“except”参数传递给DatabaseSeeder类。

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

这是最终代码,我在 Laravel 5.2 实例上创建并尝试:

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

命令,放入app/Console/Commands,不要忘记更新你的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

php artisan db:seed-except

will give you:

会给你:

calling ExampleTableSeeder
calling UserSamplesTableSeeder

调用 ExampleTableSeeder
调用 UserSamplesTableSeeder

However, adding "except":

但是,添加“除外”:

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

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

will give you

会给你

calling UserSamplesTableSeeder

调用 UserSamplesTableSeeder

This works overriding the default callmethod of your DatabaseSeederclass and calling the parent only if the name of the class is not in the $except variable. The variable is populated by the SeedExceptcustom command.

这可以覆盖类的默认call方法,DatabaseSeeder并且仅当类的名称不在 $except 变量中时才调用父类。该变量由SeedExcept自定义命令填充。

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-exceptcommand that overrides the MigrateCommandclass (namespace Illuminate\Database\Console\Migrations, located in vendor/laravel/framework/src/Illuminate/Database/Console/Migrations/MigrateCommand.php).
  • the MigrateCommandtakes a Migratorobject (namespace Illuminate\Database\Migrations, path vendor/laravel/framework/src/Illuminate/Database/Migrations/Migrator.php) in the constructor (injected via IoC). The Migratorclass 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 MigrateExceptCommandand pass your MyMigrator: public function __construct(MyMigrator $migrator)
  • 您创建一个migrate-except覆盖MigrateCommand类的命令(命名空间 Illuminate\Database\Console\Migrations,位于 vendor/laravel/framework/src/Illuminate/Database/Console/Migrations/MigrateCommand.php)。
  • 在构造函数中MigrateCommand接受一个Migrator对象(命名空间 Illuminate\Database\Migrations,路径 vendor/laravel/framework/src/Illuminate/Database/Migrations/Migrator.php)(通过 IoC 注入)。本Migrator类拥有读取所有的文件夹内的迁移和执行它的逻辑。这个逻辑在run()方法里面
  • Migrator例如MyMigrator,创建 的子类并覆盖run()方法以跳过使用特殊选项传递的文件
  • 覆盖__construct()您的方法MigrateExceptCommand并传递您的MyMigratorpublic function __construct(MyMigrator $migrator)

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

如果我有时间,我会在赏金结束前添加示例代码

EDITas promised, here's an example for migrations:

按照承诺进行编辑,这是一个迁移示例:

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

MyMigrator 类,扩展 Migrator 并包含跳过文件的逻辑:

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

MigrateExcept 自定义命令

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

最后,您需要将其添加到服务提供者以允许 Laravel IoC 解析依赖项

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::classin the Kernel.php

不要忘记Commands\MigrateExcept::class在 Kernel.php 中添加

Now, if you execute

现在,如果你执行

php artisan migrate-except

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:

但是添加了except参数:

php artisan migrate-except --except=2014_04_24_110151_create_oauth_scopes_table

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, MigrateExceptclass, 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 MyMigratorclass
  • MyMigratoroverrides the run()method of Migratorand 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
  • 我们创建一个自定义的 migrate-except 命令,MigrateExcept类,扩展 MigrateCommand
  • 我们创建了一个自定义迁移器类MyMigrator,扩展了标准的行为Migrator
  • 当 MigrateExcept 为 fire() 时,传递文件名跳转到我们的MyMigrator
  • MyMigrator覆盖run()方法Migrator并跳过通过的迁移
  • 更多:由于我们需要向 Laravel IoC 指示新创建的类,以便它可以正确注入它们,我们创建了一个服务提供者

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

该代码已经过测试,因此它应该可以在 Laravel 5.2 上正常工作(希望剪切和粘贴工作正常:-) ...如果有人有任何疑问,请发表评论

回答by Dastur

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

跳过种子非常简单,迁移不是那么多。要跳过种子,请从 DatabaseSeeder 类中删除以下内容。

$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.
  • 将您不想迁移的课程放到不同的文件夹中。
  • 手动将您的迁移插入数据库(详细说明了 Bindesh Pandya 的回答)。
  • 将您不想迁移的文件重命名为UsersTableMigration.dud.

Hope this helps

希望这可以帮助

回答by Bindesh Pandya

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.

我在我的项目中也遇到了同样的问题,但是在研发上浪费了很长时间后,我发现 Laravel 没有提供任何方法来通过迁移和播种来做到这一点,但你有两种方法可以做到这一点。

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

1) 只需将它们放入不同的文件夹中,您就可以节省大量时间。理论上,您可以创建自己的 artisan 命令来执行您想要的操作,或者通过创建目录、移动文件和运行 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 --helpfor more details there.

对于播种机,只需制作播种机并调用其他要运行的播种机即可。然后明确说明您要运行的播种机。db:seed --help在那里尝试 php artisan以获取更多详细信息。

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

2)您可以手动创建一个表(与在您的数据库中创建的迁移表具有相同的名称)并像这样插入迁移的值

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.

所以 migrate 命令不会创建迁移表中已经存在的表。

回答by Kamil Kie?czewski

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

如果您只想省略(但保留)迁移和播种机:

  1. Rename your migration by removing .phpextension: mv your_migration_file.php your_migration_file
  2. Go to: DatabaseSeeder.phpand 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
  1. 通过删除.php扩展重命名您的迁移:mv your_migration_file.php your_migration_file
  2. 转到:DatabaseSeeder.php并注释掉您不需要的播种机的行://$this->call('YourSeeder');
  3. 跑: php artisan migrate --seed
  4. 在 db 上执行下面的 sql 查询(注意,应该有没有扩展名的迁移文件名)(这将阻止 artisan migrate 将来执行 your_migration_file):

    插入migrations( migration, batch) 值 ( your_migration_file, 1)

  5. 重命名您的迁移文件: mv your_migration_file your_migration_file.php

  6. 取消注释您的播种机 DatabaseSeeder.php

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

你已经完成了。现在,当您运行时,php artisan migrate应该执行任何迁移(如果添加一些新的迁移文件,则新迁移除外)。

回答by Hamelraj

just an idea comment seederand 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');

回答by Chibueze Opata

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

为了直接回答你的问题,Laravel 目前没有办法做到这一点。

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

如果我理解正确,我假设您正在寻找一种方法来临时禁用/跳过默认 DatabaseSeeder 中的特定类。

You can easily create your own commandwhich 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