Пользовательская команда ремесленника Laravel 7 вызывает исключение BindingResolutionException с существующим классом

#php #exception #laravel-7 #laravel-artisan #laravel-migrations

#php #исключение #laravel-7 #laravel-artisan #laravel-миграции

Вопрос:

Я создаю команду в Laravel 7, которая создает некоторые миграции в папке внутри database / migrations и сеялки. Затем он запускает dumpAutoloads(), чтобы убедиться, что созданные миграции и сеялка зарегистрированы в автозагрузке classmap. Затем моя команда вызывает команду php artisan migrate и последовательно команду php artisan db:seed с флагом —class, чтобы заполнить только созданную сеялку.

Все работает нормально, пока не будет вызвана команда db:seed . Программа-сеялка действительно создана, но она продолжает выдавать мне следующее исключение:

 IlluminateContractsContainerBindingResolutionException

Target class [StudentOperationTypesSeeder] does not exist
  

Очевидно, это всего лишь пример, но я проверил, что имя созданного сеялки точно такое же, как и то, которое показывает исключение, и оно совпадает. Кроме того, сразу после того, как мне выдается это исключение, я сам запускаю команду db:seed —class=StudentOperationTypesSeeder, и это работает!

Это заставляет меня думать, что, возможно, автозагрузка classmap не обновляется до тех пор, пока процесс выполнения команды не будет завершен или что-то в этом роде… Я действительно понятия не имею.

Мой код следующий:

TimeMachineGeneratorCommand.php

 <?php

namespace AppConsoleCommands;

use IlluminateConsoleCommand;
use IlluminateSupportStr;
use IlluminateSupportFacadesSchema;
use IlluminateSupportFacadesDB;

class TimeMachineGeneratorCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'time-machine:generate {table_name}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Generates the tables and structure of a time machine for the given table.';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        // Convierte a snake case singular el nombre de la entidad.
        $entity = Str::singular(
            Str::snake(class_basename($this->argument('table_name')))
        );

        // Revisa que el nombre del modelo esté en el formato adecuado. 
        $modelName = Str::singular(
            Str::studly($this->argument('table_name'))
        );

        $seederClassName = "{$modelName}OperationTypesSeeder";

        // Crea las migraciones para la estructura de la máquina del tiempo.
        $this->createMigrations($entity);

        // Genera el Seeder del los operation types básicos.
        $this->createSeeder($seederClassName);

        // Para asegurarse que las migrations y el seeder está registrada en 
        // los class loaders se ejecuta el dump-autoload.
        $this->line("<fg=yellow>Dumping Autoloads...</>");
        $this->laravel->composer->dumpAutoloads();
        $this->info("Autoloads dumped.");

        // Ejecuta las migraciones.
        $this->call('migrate', [
            '--path' => '/database/migrations/'.Str::plural(Str::snake($modelName)).'/'
        ]);
        // Ejecuta el seeder recién creado.
        $this->call('db:seed', [
            '--class' => $seederClassName
        ]);
        
        (...) // <-- Some other code that isn't executed because of the exception
    }

    /**
     * Genera los archivos de código de las migraciones necesarias
     * para la estructura de la máquina del tiempo.
     */
    private function createMigrations($entity)
    {
        // Genera la migración para los tipos de operación de la entidad.
        $this->call('time-machine:operation-type-migration', [
            'entity' => $entity
        ]);

        // Genera la migración para los logs de la entidad.
        $this->call('time-machine:log-migration', [
            'entity' => $entity
        ]);

        // Genera la migración para los logs de la entidad.
        $this->call('time-machine:required-fields-migration', [
            'entity' => $entity
        ]);
    }

    /**
     * Crea el seeder de operationt types basado en el 
     * template diseñado para la máquina del tiempo.
     *
     * @param  string | $seederClassName | El nombre de la clase para el seeder.
     * @return void.
     */
    private function createSeeder($seederClassName)
    {
        $this->call('time-machine:seeder', [
            'name' => $seederClassName
        ]);

        // Agrega el seeder recién creado al DatabaseSeeder.php. 
        $this->updateDatabaseSeeder($seederClassName);
    }

    /**
     * Agrega el seeder recién creado al DatabaseSeeder.php.
     *
     * @var    $seederClassName.
     * @return void.
     */
    private function updateDatabaseSeeder($seederClassName)
    {
        $filePath = base_path().'\database\seeds\DatabaseSeeder.php';

        // Lee el archivo del DataBaseSeeder.
        $seeder = file_get_contents($filePath);

        // Si el seeder no ha sido agregado ya al DatabaseSeeder.php...
        if(preg_match('/$this->call('.$seederClassName.'::class);/', $seeder) == 0) {
            // Agrega el seeder recién creado.
            $newContent = preg_replace(
                '/public function run()s*{/',
    "public function run()
    {
        $this->call({$seederClassName}::class);", 
                
                $seeder, 1
            );
            
            // Guarda el contenido del archivo.
            file_put_contents($filePath, $newContent);

            $this->info('Seeder added to DatabaseSeeder.php.');
        } else {
            $this->error('Seeder is already in DataBaseSeeder.php.');
        }
    }
}
  

Кроме того, это раздел автозагрузки моего composer.json (я читал, что с этим может быть что-то или что-то в этом роде, я все равно не смог найти решение своей проблемы).

     "autoload": {
        "psr-4": {
            "App\": "app/"
        },
        "classmap": [
            "database/seeds",
            "database/factories"
        ]
    },
  

StudentOperationTypesSeeder.php

 <?php

use IlluminateDatabaseSeeder;

class StudentOperationTypesSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $studentOperationType = new AppStudentOperationType();
        $studentOperationType->description = "Created";
        $studentOperationType->save();

        $studentOperationType = new AppStudentOperationType();
        $studentOperationType->description = "Updated";
        $studentOperationType->save();

        $studentOperationType = new AppStudentOperationType();
        $studentOperationType->description = "Deleted";
        $studentOperationType->save();
    }
}
  

Пожалуйста, помогите. Команда успешно генерирует миграции и средство просмотра, затем запускает миграции, и все работает точно так, как задумано, за исключением средства просмотра, и я не понимаю, почему.

Примечание: другие команды «машины времени«, которые я вызываю в функциях TimeMachineGeneratorCommand.php есть другие пользовательские команды, которые я создал, которые буквально только расширяют существующие команды миграции поставщика и меняют заглушку на пользовательскую.

Комментарии:

1. Ну, как выглядит файл seeder?

2. Я отредактирую его в

3. этот новый файл сеялки не будет частью classmap в этот момент (он не загружается автоматически PSR4), потенциально он может потребоваться в этот момент, хотя в PHP загружен класс, поскольку для этого класса нет сопоставления

4. как я могу это потребовать?

Ответ №1:

Я последовал подходу, предложенному lagbox, и нашел то, что работает.

Я включил сгенерированный файл, добавив следующую строку кода перед вызовом команды bd:seed, очевидно, после строки, которая генерирует средство просмотра.

 include base_path()."\database\seeds\".$seederClassName.".php";
  

После выполнения этого сеялка выполняется правильно, и вся команда работает так, как ожидалось.

Окончательный метод обработки выглядит следующим образом.

 /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        // Convierte a snake case singular el nombre de la entidad.
        $entity = Str::singular(
            Str::snake(class_basename($this->argument('table_name')))
        );

        // Revisa que el nombre del modelo esté en el formato adecuado. 
        $modelName = Str::singular(
            Str::studly($this->argument('table_name'))
        );

        $seederClassName = "{$modelName}OperationTypesSeeder";

        // Crea las migraciones para la estructura de la máquina del tiempo.
        $this->createMigrations($entity);

        // Genera el Seeder del los operation types básicos.
        $this->createSeeder($seederClassName);

        // Para asegurarse que las migrations y el seeder está registrada en 
        // los class loaders se ejecuta el dump-autoload.
        $this->line("<fg=yellow>Dumping Autoloads...</>");
        $this->laravel->composer->dumpAutoloads();
        $this->info("Autoloads dumped.");

        // Ejecuta las migraciones.
        $this->call('migrate', [
            '--path' => '/database/migrations/'.Str::plural(Str::snake($modelName)).'/'
        ]);

        include base_path()."\database\seeds\".$seederClassName.".php";

        // Ejecuta el seeder recién creado.
        $this->call('db:seed', [
            '--class' => $seederClassName
        ]);
        
        (...) // <-- Some other code that isn't executed because of the exception
    }