将Artisan注入服务类


Injecting Artisan into Service class

我正试图将Artisan注入服务中,这样我就可以避免使用facade。查看facade类引用,我可以看到我应该注入的类是:

Illuminate'Console'Application

所以我认为这样做:

<?php
namespace App'Service;
use Illuminate'Console'Application;
class DummyDataService
{
    /**
     * @var Application
     */
    private $application;
    public function __construct(
        Application $application
    ) {
        $this->application = $application;
    }
    public function insertDummyData()
    {
        $this->application->call('db:seed', [
            '--class' => 'DummyDataSeeder'
        ]);
    }
}

会起作用。然而,我得到以下错误:

BindingResolutionException in Container.php line 824:
Unresolvable dependency resolving [Parameter #2 [ <required> $version ]] in class Illuminate'Console'Application

如果我只是这样调用门面上的方法,它就会起作用:

Artisan::call('db:seed', [
    '--class' => 'DummyDataSeeder'
]);

到目前为止我还搞不清楚问题出在哪里。有人经历过类似的问题吗?我尽量避开门面。

提前谢谢。

您应该注入Illuminate'Contracts'Console'Kernel而不是Illuminate'Console'Application来实现您想要的,所以您的类应该如下所示:

<?php
namespace App'Service;
use Illuminate'Contracts'Console'Kernel;
class DummyDataService
{
    private $kernel;
    public function __construct(Kernel $kernel) 
    {
        $this->kernel = $kernel;
    }
    public function insertDummyData()
    {
        $this->kernel->call('db:seed', [
            '--class' => 'DummyDataSeeder'
        ]);
    }
}

如果您仔细查看Illuminate'Console'Application的构造函数,您会发现它需要一个$version参数,而不提供任何类型的默认值。因此,如果没有明确地提供一个,它将由于依赖关系而失败。老实说,这对我来说似乎是个bug。如果你看看它的Symphony父类,你会发现它在构造函数中提供了一个默认字符串'UNKNOWN'。如果将Illuminate'Console'Application修改为具有相同的默认值,那么代码中的命令现在应该可以工作了。

这给您留下了两个选择。

  1. 只需将Artisan立面用于此实例。对其余立面使用构造函数注入应该很好,因为这会特别影响Artisan立面
  2. 将源代码中的构造函数更改为具有默认值。这并不理想,因为每次更新Laravel时,您的所有更改都会丢失,但这是一种选择。您可能能够编写某种服务提供商,将版本注入到所有Illuminate'Console'Application实例中,但我不确定

老实说,我不确定在构造函数中添加该默认值是否会产生不可预见的后果,尽管我认为它们会很小,因为它必须在调用它的任何地方都明确定义。我甚至可能把它做成一个PR,看看Taylor是对它发表评论还是合并它。