2

For a project that I'm working on, using Symfony which I'm quite new to, I am trying to create an object of a class that uses Dependency Injection but also needs some custom parameters.

Now let's say I have a Command:

<?php

class ServerCommand extends Command {
    public function __construct(Server $server) {
        $this->server = $server;
    }

    protected function execute(InputInterface $input, OutputInterface $output) {
        ...
    }
}

And a Server class:

<?php
class Server {
    public function __construct(MessageManager $messageManager, InputInterface $input, OutputInterface $output) {
        ...
    }
}

Now, the Server class is injected into the Command class and the MessageManager class is injected into the Server class.

The problem that I'm having is getting the $input and $ouput variables in the Command class into the constructor of the Server class.

And to make it even more difficult, I also want the $input and $output variables accessible in the MessageManager class.

Is this possible, and if so, how do I achieve this?

2 Answers 2

8

EDIT: SymfonyStyle actually only uses Input, but doesn't allow to access it. What exactly do you need Input for? You should use only variables it provides outside the Command.


So, basically you need Input and Output as a service?

The class that combines them is called SymfonyStyle and it was introduced in in Symfony 2.8 with nice blog post.

There are many ways to get input/output to SymfonyStyle, but I'll show you the most straighforward one. I use it in Symplify packages and Rector for over 3 years and it is very reliable.

<?php declare(strict_types=1);

namespace App\Console;

use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Style\SymfonyStyle;

final class SymfonyStyleFactory
{
    public function create(): SymfonyStyle
    {
        $input = new ArgvInput();
        $output = new ConsoleOutput();

        return new SymfonyStyle($input, $output);
    }
}

Then register this factory as a sevice:

# app/config/services.yaml
services:
    App\Console\SymfonyStyleFactory: ~

    Symfony\Component\Console\Style\SymfonyStyle:
        factory: ['@App\Console\SymfonyStyleFactory', 'create']

Then just require SymfonyStyle in any service you need it in and use it:

<?php declare(strict_types=1); 

class MessageManager
{
    /**
     * @var SymfonyStyle
     */
    private $symfonyStyle;

    public function __construct(SymfonyStyle $symfonyStyle)
    {
        $this->symfonStyle = $symfonyStyle;
    }

    public function run()
    {
        // some code
        $this->symfonyStyle->writeln('It works!');
        // some code
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

That seems like what I'm trying to achieve, I'll try this when I get home. Thanks!
Awesome! Works in Symfony 6.1 in Fixtures like a charm. Thanks! Of course you can just do return new SymfonyStyle(new ArgvInput(), new ConsoleOutput()); ;)
-1

The data that is in the concrete instance of the InputInterface is only created when the command is run, the same for Output. These would therefore be parameters that are passed into a function, from the execute() method, or another method that is eventually called. Similarly, they are parameters that can be given to a Server class method (and likely from there, to a MessageManager method).

They hold data, but they are not a service.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.