zenstruck / console-extra

A modular set of features to reduce configuration boilerplate for your Symfony commands.
MIT License
78 stars 3 forks source link

Proper way to share arguments and options among commands #49

Open tacman opened 1 year ago

tacman commented 1 year ago

I have several commands that follow a similar format, and I'm curious as to the best practices on how to extend from a base class.

bin/console project:create test
bin/console project:import test data.yaml 
bin/console project:translate test --target fr 
bin/console project:update test --visibility=public
bin/console project:delete test --force

Except for create, all of them look up a project in the repo and then act on it. All the commands have a --format option, so I can output the results in json for testing / integrating.

What I'd really currently doing is

        #[Argument(description: 'project Code')] string     $code,
        #[Option(description: 'translation engine')] string $engine = 'libre',
        #[Option(description: 'target locale')] ?string     $target = null,

    ): void
    {

        $project = $this->getProject($code, $io); // from a trait that assumes the projectRepository is available

I'd love to use ValueConverter like I do with controllers and somehow inject the project based on the code, e.g.

        #[Argument(description: 'project Code', name: 'projectCode')] Project  $project,

But I'm not sure where to look on how to do that.

Similarly, whatever commands can take a --format (like debug:route), is there a way to share at least the option definition? I'm guessing I can take the $io and add an option there in a trait, or maybe extend from some base command, but not sure what the best way to approach this is.

I still think this should be part of Symfony, all of my new commands use this, and it's so much cleaner than the traditional Symfony commands. Maybe Symfony 7....

kbond commented 1 year ago

A base class where you define Options/Arguments attributes on the class level could be an option (would have to change the code in this package to look for attributes on parent classes). The values wouldn't be injected into your __invoke() but could be grabbed from IO.

Another option could be using the console event system (I've done this before).

I'd love to use ValueConverter like I do with controllers and somehow inject the project based on the code, e.g.

That's an interesting idea!

I still think this should be part of Symfony, all of my new commands use this, and it's so much cleaner than the traditional Symfony commands. Maybe Symfony 7....

Some of the stuff in this bundle might be coming in Symfony 7.... We're trying to make console commands behave like controllers (with Input instead of Request). A Value resolver system for console commands would be welcome I think.