【问题标题】:Laravel 7 custom Artisan command throws BindingResolutionException with existing classLaravel 7 自定义 Artisan 命令使用现有类抛出 BindingResolutionException
【发布时间】:2021-02-25 19:27:57
【问题描述】:

我正在 Laravel 7 中创建一个命令,该命令会在 database/migrations 和播种机内的文件夹中创建一些迁移。然后,它运行 dumpAutoloads() 以确保创建的迁移和播种器已在自动加载类映射中注册。然后,我的命令调用 php artisan migrate 命令,并连续调用带有 --class 标志的 php artisan db:seed 命令,以仅播种创建播种机。

在调用 db:seed 命令之前一切正常。确实创建了播种机,但它不断向我抛出下一个异常:

Illuminate\Contracts\Container\BindingResolutionException

Target class [StudentOperationTypesSeeder] does not exist

这显然只是一个示例,但我检查了创建的 Seeder 的名称与异常显示的名称完全相同并且匹配。此外,在向我抛出此异常之后,我自己运行 db:seed --class=StudentOperationTypesSeeder 命令并且它有效!

这让我觉得可能在命令过程完成之前自动加载类映射不会更新或其他什么......我真的不知道。

我的代码如下:

TimeMachineGeneratorCommand.php

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;

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 Illuminate\Database\Seeder;

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

        $studentOperationType = new \App\StudentOperationType();
        $studentOperationType->description = "Updated";
        $studentOperationType->save();

        $studentOperationType = new \App\StudentOperationType();
        $studentOperationType->description = "Deleted";
        $studentOperationType->save();
    }
}

请帮忙。该命令成功生成迁移和播种器,然后运行迁移,一切都按预期工作,除了播种器,我还没有找到原因。

注意: 我在 TimeMachineGeneratorCommand.php 的函数中调用的其他 "time-machine" 命令是其他自定义命令我创建的只是扩展了供应商现有的迁移命令并将存根更改为自定义的。

【问题讨论】:

  • 那么种子文件是什么样的?
  • 我会在里面编辑
  • 那个新的种子文件在那个时候不会是类映射的一部分(它不是 PSR4 自动加载的),虽然你可能会在那个时候需要它,所以 PHP 已经加载了这个类,因为没有映射到那个班级
  • 我如何要求它?

标签: php exception laravel-7 laravel-artisan laravel-migrations


【解决方案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
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-08-11
    • 1970-01-01
    • 1970-01-01
    • 2020-05-31
    • 1970-01-01
    • 2014-01-26
    • 2016-04-06
    • 1970-01-01
    相关资源
    最近更新 更多