Search code examples
phpsymfonysymfony-console

Defining a Symfony command as a service causes preg_match() exception


I have the following command, which successfully prints styled messages to the bash terminal when called:

class DoSomethingCommand extends Command
{
    protected function configure()
    {
        $this->setName('do:something')
            ->setDescription('Does a thing');
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $io = new SymfonyStyle($input, $output);

        $io->title('About to do something ... ');

        $io->success('Done doing something.');
    }
}

... but when I add the following in services.yml in order to try to define my command as a service ...

services:
  console_command.do_something:
    class: AppBundle\Command\DoSomethingCommand
    arguments:
      - "@doctrine.orm.entity_manager"
    tags:
      - { name: console.command }

... I get this error:

Warning: preg_match() expects parameter 2 to be string, object given in src/app/vendor/symfony/symfony/src/Symfony/Component/Console/Command/Command.php:665

What am I doing wrong here?


Solution

  • Firstly, you inject the service but your do any constructor function in your command.

    That means you are currently injecting the EntityManager (object) into the parameter of the Command class (which need a string or null , that's why you have your error)

    # Symfony\Component\Console\Command\Command
    class Command
    {
        public function __construct($name = null)
        {
    

    Then, as defined in the documentation you must call the parent constructor

    class YourCommand extends Command
    {
        private $em;
    
        public function __construct(EntityManagerInterface $em)
        {
            $this->em = $em;
    
            // you *must* call the parent constructor
            parent::__construct();
        }
    

    ContainerAwareCommand

    Note than your class can extends ContainerAwareCommand and you will be able to access public services via $this->getContainer()->get('SERVICE_ID'). This isn't a bad practice as a command can be seen as a controller. (And usually your controllers have the container injected)