How can i inject dependencies to Symfony Console commands?

后端 未结 7 1016
醉话见心
醉话见心 2020-12-09 08:00

I\'m writing an open source application uses some Symfony components, and using Symfony Console component for interacting with shell.

But, i need to inject dependen

相关标签:
7条回答
  • 2020-12-09 08:06

    I'm speaking for symfony2.8. You cannot add a constructor to the class that extends the ContainerAwareCommand because the extended class has a $this->getContainer() which got you covered in getting your services instead of injecting them via the constructor.

    You can do $this->getContainer()->get('service-name');

    0 讨论(0)
  • 2020-12-09 08:08
    use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
    

    Extends your Command class from ContainerAwareCommand and get the service with $this->getContainer()->get('my_service_id');

    0 讨论(0)
  • 2020-12-09 08:09

    Since Symfony 4.2 the ContainerAwareCommand is deprecated. Use the DI instead.

    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);    
        }
    }
    
    0 讨论(0)
  • 2020-12-09 08:12

    In Symfony 3.4, if autowire is configured correctly, services can be injected into the constructor of the command.

    public function __construct(
        \AppBundle\Handler\Service\AwsS3Handler $s3Handler
    ) {
        parent::__construct();
    
        $this->s3Handler = $s3Handler;
    }
    
    0 讨论(0)
  • 2020-12-09 08:18

    It is best not to inject the container itself but to inject services from the container into your object. If you're using Symfony2's container, then you can do something like this:

    MyBundle/Resources/config/services (or wherever you decide to put this file):

    ...
        <services>
            <service id="mybundle.command.somecommand" class="MyBundle\Command\SomeCommand">
            <call method="setSomeService">
                 <argument type="service" id="some_service_id" />
            </call>
            </service>
        </services>
    ...
    

    Then your command class should look like this:

    <?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;
       }
    ...
    

    I know you said you're not using the dependency injection container, but in order to implement the above answer from @ramon, you have to use it. At least this way your command can be properly unit tested.

    0 讨论(0)
  • 2020-12-09 08:18

    Go to services.yaml

    Add This to the file(I used 2 existing services as an example):

    App\Command\MyCommand:
            arguments: [
                '@request_stack',
                '@doctrine.orm.entity_manager'
            ]
    

    To see a list of all services type in terminal at the root project folder:

    php bin/console debug:autowiring --all
    

    You will get a long list of services you can use, an example of one line would look like this:

     Stores CSRF tokens.
     Symfony\Component\Security\Csrf\TokenStorage\TokenStorageInterface (security.csrf.token_storage)
    

    So if CSRF token services is what you are looking for(for example) you will use as a service the part in the parenthesis: (security.csrf.token_storage)

    So your services.yaml will look somewhat like this:

    parameters:
    
    services:
        _defaults:
            autowire: true      
            autoconfigure: true 
    
    # Here might be some other services...
    
    App\Command\MyCommand:
            arguments: [
                '@security.csrf.token_storage'
            ]
    

    Then in your command class use the service in the constructor:

    class MyCommand extends Command
    {
        private $csrfToken;
    
        public function __construct(CsrfToken $csrfToken)
        {
            parent::__construct();
            $this->csrfToken = $csrfToken;
        }
    }
    
    0 讨论(0)
提交回复
热议问题