自定义 laravel 迁移命令“[Illuminate\Database\Migrations\MigrationRepositoryInterface] 不可实例化”

Posted

技术标签:

【中文标题】自定义 laravel 迁移命令“[Illuminate\\Database\\Migrations\\MigrationRepositoryInterface] 不可实例化”【英文标题】:Custom laravel migration command "[Illuminate\Database\Migrations\MigrationRepositoryInterface] is not instantiable"自定义 laravel 迁移命令“[Illuminate\Database\Migrations\MigrationRepositoryInterface] 不可实例化” 【发布时间】:2018-02-06 21:09:04 【问题描述】:

我正在尝试创建一个自定义 laravel (5.2) 迁移命令,它基本上与 migrate:status 相同,除了它只列出待处理的迁移而不是所有迁移。

为此,我非常简单地将migrate:status 复制到了我的 app/console 目录中的另一个类中,并调整了代码以满足我的需要。但是,每当我尝试运行它时,都会出现错误:

[Illuminate\Contracts\Container\BindingResolutionException] 目标 [Illuminate\Database\Migrations\MigrationRepositoryInterface] 在构建 [App\Console\Commands\PendingMigrations, Illuminate\Database\Migrations\Migrator] 时不可实例化。

类本身的内容和fire() 方法似乎并不重要,因为它没有达到那么远,它在__construct() 方法中失败了。

<?php namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Database\Migrations\Migrator;

class PendingMigrations extends Command

    /**
     * The console command name.
     *
     * @var string
     */
    protected $name = 'migrate:pending';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Shows a list of pending migrations';

    /**
     * The migrator instance.
     *
     * @var \Illuminate\Database\Migrations\Migrator
     */
    protected $migrator;

    /**
     * Create a new migration rollback command instance.
     *
     * @param  \Illuminate\Database\Migrations\Migrator $migrator
     * @return \Illuminate\Database\Console\Migrations\StatusCommand
     */
    public function __construct(Migrator $migrator)
    
        parent::__construct();

        $this->migrator = $migrator;
    

    /**
     * Execute the console command.
     *
     * @return void
     */
    public function fire()
    
    

它的原因可能与 IoC 容器和加载事物的顺序有关,但我对 Laravel 的内部工作原理了解不多,无法弄清楚更多。

一定有可能吗?

我目前卡在 5.2 上,所以我不确定这个问题是否存在于更新的版本中。

到目前为止,我唯一尝试的是将迁移服务提供商添加到 config/app.php 列表的顶部,但它似乎没有影响,无论如何这只是一个随机猜测。

providers' => [
    Illuminate\Database\MigrationServiceProvider::class,`
]

【问题讨论】:

【参考方案1】:

我解决了这个问题:

$this->migrator = app('migrator');

但这不一定是最好的方法

【讨论】:

刚刚花了 1 个小时。谢谢! 不用担心,如果您找到更好的方法,请发布答案:)【参考方案2】:

Migrator 实例未绑定到 IoC 容器中的类名,它绑定到 migrator 别名。

来自Illuminate\Database\MigrationServiceProvider

/**
 * Register the migrator service.
 *
 * @return void
 */
protected function registerMigrator()

    // The migrator is responsible for actually running and rollback the migration
    // files in the application. We'll pass in our database connection resolver
    // so the migrator can resolve any of these connections when it needs to.
    $this->app->singleton('migrator', function ($app) 
        $repository = $app['migration.repository'];

        return new Migrator($repository, $app['db'], $app['files']);
    );

由于类名未绑定在 IoC 容器中,当 Laravel 解析您的命令并尝试解析 Migrator 依赖项时,它会尝试从头开始构建一个新的并失败,因为 Illuminate\Database\Migrations\MigrationRepositoryInterface 也未绑定在 IoC 容器中(因此您收到错误)。

由于 Laravel 自己无法解决这个问题,您需要为 Migrator 类名注册绑定,或者您需要为您的命令注册绑定。 Laravel 自己在Illuminate\Foundation\Providers\ArtisanServiceProvider 中注册了所有命令的绑定。 command.migrate 绑定示例:

/**
 * Register the command.
 *
 * @return void
 */
protected function registerMigrateCommand()

    $this->app->singleton('command.migrate', function ($app) 
        return new MigrateCommand($app['migrator']);
    );

因此,在您的 AppServiceProvider 或您设置的其他服务提供商中,您可以添加以下内容之一:

在 IoC 中注册命令:

$this->app->singleton(\App\Console\Commands\PendingMigrations::class, function ($app) 
    return new \App\Console\Commands\PendingMigrations($app['migrator']);
);

或者,在 IoC 中注册 Migrator 类名:

$this->app->singleton(\Illuminate\Database\Migrations\Migrator::class, function ($app) 
    return $app['migrator'];
);

【讨论】:

这是有道理的,只是框架的 MigrateCommand 类似乎使用 IoC 来实例化其迁移器。我不知道它在那里是如何工作的,但不是在新命令中。 @Trip MigrateCommand 通过构造函数接受迁移器。当服务提供者实例化一个新的MigrateCommand 时,它会将迁移器传递给构造函数。 当然,你是对的。我确信这正在发生,但我在查看 registerCommands() 之前停止扫描 MigrationServiceProvider 类,因为它作为标准的 commands() 方法让我印象深刻。【参考方案3】:

由于我不想在应用程序的任何地方注册migrator,但我仍然想扩展MigrateCommand 本身,所以我想出了这种方法来维护我的应用程序:

public function __construct()

    app()->singleton(\App\Console\Commands\PendingMigrations::class, function ($app) 
        return new \App\Console\Commands\PendingMigrations($app['migrator']);
    );

    parent::__construct(app('migrator'));

【讨论】:

以上是关于自定义 laravel 迁移命令“[Illuminate\Database\Migrations\MigrationRepositoryInterface] 不可实例化”的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 迁移创建自定义外键

在 Laravel 迁移中创建一个具有自定义大小的小整数列

如何自定义laravel用户迁移到新的

Laravel 迁移未定义索引

Laravel用命令创建海关包

Laravel API ResourceCollection - 调用未定义的方法 Illuminate\Database\Eloquent\Builder::mapInto()