如何将依赖项注入Symfony控制台命令?

osm*_*osm 34 console dependency-injection symfony

我正在编写一个开源应用程序使用一些Symfony组件,并使用Symfony Console组件与shell进行交互.

但是,我需要注入依赖项(在所有命令中使用),如Logger,Config对象,Yaml解析器......我通过扩展Symfony\Component\Console\Command\Command类解决了这个问题.但这使得单元测试变得更难,而且看起来不正确.

我怎么解决这个问题?

Ise*_*ngo 26

从Symfony 4.2开始,不推荐使用ContainerAwareCommand.请改用DI.

namespace App\Command;

use Symfony\Component\Console\Command\Command;
use Doctrine\ORM\EntityManagerInterface;

final class YourCommand extends Command
{
    /**
     * @var EntityManagerInterface
     */
    private $entityManager;

    public function __construct(EntityManagerInterface $entityManager)
    {
        $this->entityManager = $entityManager;

        parent::__construct();
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        // YOUR CODE
        $this->entityManager->persist($object1);    
    }
}
Run Code Online (Sandbox Code Playgroud)

  • Command 父构造函数将 `string $name = null` 作为它的第一个参数,它应该放在任何注入的服务之前。 (3认同)
  • 这是目前最好的解决方案! (2认同)

小智 23

use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
Run Code Online (Sandbox Code Playgroud)

ContainerAwareCommand扩展Command类并获取服务$this->getContainer()->get('my_service_id');

  • 这*事实上是不正确的*.使用这个,你不是*"注入依赖关系"问题 - 你注入了一个服务定位器,然后用于检索这些服务.(反模式). (23认同)
  • Symfony 3中不再存在AFAICT ContainerAwareCommand. (6认同)
  • 这是2017 + / Symfony 3.3+中过时的解决方案 (3认同)

oro*_*edd 17

最好不要注入容器本身,而是将容器中的服务注入到对象中.如果您正在使用Symfony2的容器,那么您可以执行以下操作:

MyBundle/Resources/config/services(或者您决定放置此文件的位置):

...
    <services>
        <service id="mybundle.command.somecommand" class="MyBundle\Command\SomeCommand">
        <call method="setSomeService">
             <argument type="service" id="some_service_id" />
        </call>
        </service>
    </services>
...
Run Code Online (Sandbox Code Playgroud)

然后你的命令类应如下所示:

<?php
namespace MyBundle\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use The\Class\Of\The\Service\I\Wanted\Injected;

class SomeCommand extends Command
{
   protected $someService;
   public function setSomeService(Injected $someService)
   {
       $this->someService = $someService;
   }
...
Run Code Online (Sandbox Code Playgroud)

我知道你说你没有使用依赖注入容器,但是为了从@ramon实现上述答案,你必须使用它.至少这种方式可以对您的命令进行适当的单元测试.