Skip to content

Symfony/console - change to be a pure CLI router not a dispatcher #11974

Closed
@Danack

Description

@Danack

Hi, this is a BC feature request for Symfony 3. Also let me apologize in advance if I come across as rude - the symfony/console is almost really great - but the feature change below is needed to allow it to be re-usable imho.

Currently the Symfony/console library does two main things, parse the command line options to choose which command to run, and then execute that command.

If you're using constructor dependency injection in your code, this makes it very hard to use the library in a sane way. All of the possible commands that could be run have to be completely constructed, along with all of their dependencies, which is not desirable. This kind of forces you to use Service Locator to get the dependencies for your objects. Service locators are almost always bad - but just in general having a library make other bits of code have to be written in a certain way is bad.

I think it would be much better if the console library just did the parsing and routing, and returned a ParsedCommand object which contained all of the information needed to execute the required code for the command, but left the actual 'dispatch' of the callable to other code.

I've actually done this in my fork: https://github.com/danack/console It's obviously not a big change to the actual code, though it almost certainly requires a major version to be done.

So after the refactor using the Console commands would look more like:

//Setup a command
$helloWorldCallable = function ($name) {
    echo "Hello world, and particularly $name".PHP_EOL;
};

//Create a command that will call the closure
$callableCommand = new Command($helloWorldCallable, 'greet');
$callableCommand->addArgument('name', InputArgument::REQUIRED, 'The name of the person to say hello to.');


//This callable requires a DB connection - but because it is never called, the program
$backupCallable = function (DBConnection $dbConnection) {
     // runs a backup process on the database.
};

//Create a command that will call the closure
$backupCommand = new Command($backupCallable, 'backup');

$console->add($callableCommand);
$console->add($backupCommand);


//Setup a console application
$console = new Application();


try {
    //Returns ParsedCommand on success or throws exception on parse error
    $parsedCommand = $console->parseCommandLine();
}
catch(\Exception $e) {
    $output = new BufferedOutput();
    $console->renderException($e, $output);
    echo $output->fetch();
    exit(-1);
}

//Execute the callable with the parsed params.
$provider = new Auryn\Provider();
$provider->execute(
    $parsedCommand->getCallable(),
    tagScalarParams($parsedCommand->getParams())
);

Obviously any library that acts as a DIC capable of executing code could be used, Auryn is used just as an example.

Thoughts?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions