忽略生产中的自定义 Laravel Artisan 命令

Ignore a custom Laravel Artisan command on production

我编写了一个自定义的 Artisan 命令(我们称之为 MyDusk.php),expands/abstracts 核心 Dusk 命令的一些功能。

此自定义命令从 Dusk 包中扩展 Laravel\Dusk\Console\DuskCommand

问题是,在生产环境中没有安装 Dusk 包(它在 composer.json 中的 require-dev 下)

因此,当 composer 在生产环境中生成其自动加载文件时,它会在到达 MyDusk.php 时出错,因为它找不到 Laravel\Dusk\Console\DuskCommand.

PHP Fatal error:  Class 'Laravel\Dusk\Console\DuskCommand' not found in app/Console/Commands/Dusk.php on line 10

In Dusk.php line 10:

  Class 'Laravel\Dusk\Console\DuskCommand' not found  

我尝试将 Dusk 包移动到 require,这样它就可以在生产环境中使用(我知道这并不理想),但是核心 Dusk 服务提供者中有一行在 运行 在生产中防止这种情况:

# From: vendor/laravel/dusk/src/DuskServiceProvider.php
if ($this->app->environment('production')) {
    throw new Exception('It is unsafe to run Dusk in production.');
}

我正在考虑最优雅的解决方案,以允许我的自定义 Dusk 命令成为应用程序的一部分并在本地访问,而不会在生产中引发错误。

一个想法:将我的 Dusk 命令写成自己的包,这也只在 require-dev 中。

还有其他想法吗?

我刚刚看了一下 API,你可以这样做:

您可以将命令移动到 App\Console\Commmands\Local\DuskCommand.php

默认情况下,如果您在内核中选中 commands() 方法,它只会加载在 App\Console\Commands 中找到的命令。这将不包括子目录。

/**
 * Register the commands for the application.
 *
 * @return void
 */
protected function commands()
{
    $this->load(__DIR__.'/Commands');

    require base_path('routes/console.php');
}

这是默认的 commands() 方法。您可以将此实现切换为以下实现:

/**
 * Register the commands for the application.
 *
 * @return void
 */
protected function commands()
{
    $paths = [
        __DIR__ . '/Commands'
    ]; 

    if(app()->environment('local')) {
        $paths[] = __DIR__ . '/Commands/Local';
    }

    $this->load($paths);

    require base_path('routes/console.php');
}

因此,在本地,我们也将加载基于App\Console\Commands\Local的命令。

诚然,我自己并没有尝试过,但我认为它应该可行。

编辑:我试了一下,似乎工作得很好。我想,我会尝试多解释一下。基本上,在完成 composer dump-autoload 之后,Laravel 正在监听此事件并做两件事:

"post-autoload-dump": [
    "Illuminate\Foundation\ComposerScripts::postAutoloadDump",
    "@php artisan package:discover --ansi"
]

第二个正在尝试 运行 自动打包发现命令,这就是它会失败的地方。 Artisan 可执行文件实际上使用控制台内核启动应用程序。

$kernel = $app->make(Illuminate\Contracts\Console\Kernel::class);

$status = $kernel->handle(
    $input = new Symfony\Component\Console\Input\ArgvInput,
    new Symfony\Component\Console\Output\ConsoleOutput
);

在解析内核时,它还会尝试启动它需要的命令,以便 Artisan 可以使用它们,这就是它失败的地方。

然而,就像我上面提到的,如果你只启动你在生产中需要的命令,这个问题就不会发生。

已接受的答案似乎不适用于 Laravel 6。这对我有用:

  1. 使用 php artisan make:command YourCommand 创建您的命令并将其移动到 app/Console/Local。
  2. 将其命名空间更改为 App\Console\Local。
  3. 然后,在app/Console/Kernel.php:
protected function commands()
{
    $paths = [
        __DIR__ . '/Commands'
    ];

    if(app()->environment('local')) {
        $paths[] = __DIR__ . '/Local';
    }

    $this->load($paths);

    require base_path('routes/console.php');
}
  1. 尽情享受 ;)