3

What would be a proper way to have a Service (that will be used by a Command) write information to the terminal? I like the same functionality to parse thousands of records to be able to be called from both a Controller and a Command. When it's called from the Command, I like to write a status to the terminal for every parsed record.

I've tried autowiring InputInterface $input, OutputInterface $output into the service but that gives me the following error:

Cannot autowire service "App\Service\Command\TestIoService": argument "$input" of method "__construct()" references interface "Symfony\Component\Console\Input\InputInterface" but no such service exists. Did you create a class that implements this interface?

I could pass the input and output to the service but I was wondering if there is a better way to do this

  • 1
    Passing them as arguments is your best bet. You could probably define ConsoleOutput as a service but some of the constructor arguments are based on arguments passed to the console command. As far as Input goes, pretty much everything in there is based on console arguments. No practical way to wire it. – Cerad Jul 23 '20 at 21:15
  • 1
    take a look at the docs. https://symfony.com/index.php/doc/current/console.html#console-output it is pretty straightforward I think. – craigh Jul 23 '20 at 21:44
  • a controller can't write to console, because the "console" in that case is the http response (stdout). a service used for both controller and command would be more abstract, and for the controller part could not be interactive, effectively: request == input, response == output. although you can have additional output into a logfile perhaps. and overall, you should just write to a log file (and maybe copy to console, if the command is used). make the output interface optional to achieve that or use the logger chainlogger or whatever. – Jakumi Jul 24 '20 at 00:22
  • Why not write the results of that service to some kind of data object, and handle the output logic both in the controller (for HTTP responses) and the command (for shell responses)? – Nico Haase Jul 24 '20 at 08:22
  • 1
    Adding to the suggestions, you could emit an event from your service and have your command subscribe to it. – msg Oct 13 '20 at 19:10

1 Answers1

1

I know this is over a year old, but I just stumbled upon the same requirement for my project. It's a bad idea to be passing around the Input/Output Interfaces.

Since Symfony 2.4 you've been able to use the Monolog component to log to the console. (https://symfony.com/doc/current/logging/monolog_console.html). It's already all wired-up for you. DI The LoggerInterface (use Psr\Log\LoggerInterface) in your constructor. Then use it like you normally would. $this->logger->debug('Hello World'). Your output is dependent on the verbosity level set via the CLI -v, -vv, -vvv options as described in the link above.

// src/Command/YourCommand.php
namespace App\Command;

use App\Service\AwesomeService;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class YourCommand extends Command
{

    public function __construct(AwesomeService $service)
    {
        $this->service = $service;
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $this->service->doMethod();
    }
}

// src/Service/AwesomeService.php
namespace App\Service;

use Psr\Log\LoggerInterface;

class AwesomeService
{
    private $logger;

    public function __construct(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }

    protected function doMethod()
    {
        $this->logger->debug('Some info');
        $this->logger->notice('Some more info');
    }
}
Dharman
  • 30,962
  • 25
  • 85
  • 135
tlorens
  • 478
  • 5
  • 16