Пользовательская команда миграции laravel [Illuminate\Database\Migrations\MigrationRepositoryInterface] не может быть создана

Я пытаюсь создать пользовательскую команду миграции 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,`
]

person John Mellor    schedule 29.08.2017    source источник


Ответы (3)


Я обошел это, используя:

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

но это не обязательно лучший способ сделать это

person John Mellor    schedule 31.08.2017
comment
Только что потратил на это 1 час. Спасибо! - person Julian; 19.09.2017
comment
Не беспокойтесь, если вы найдете лучший способ, пожалуйста, напишите ответ :) - person John Mellor; 20.09.2017

Экземпляр 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']);
});

Или зарегистрируйте имя класса Migrator в IoC:

$this->app->singleton(\Illuminate\Database\Migrations\Migrator::class, function ($app) {
    return $app['migrator'];
});
person patricus    schedule 13.08.2018
comment
Это имеет смысл, за исключением того, что класс MigrateCommand фреймворка, по-видимому, использует IoC для создания экземпляра своего средства миграции. Я не могу понять, как это работает там, но не в новой команде. - person Trip; 16.10.2019
comment
@Trip MigrateCommand принимает средство миграции через конструктор. Когда поставщик услуг создает экземпляр нового MigrateCommand, он передает средство миграции в конструктор. - person patricus; 17.10.2019
comment
Конечно, вы правы. Я был уверен, что это происходит, но я прекратил сканирование класса MigrationServiceProvider, прежде чем посмотреть на registerCommands(), потому что он показался мне стандартным методом commands(). - person Trip; 18.10.2019

Поскольку я не хочу регистрировать 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'));
}
person Lloople    schedule 20.11.2019