8000 [Console] Ease creation of single command application · Issue #34293 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[Console] Ease creation of single command application #34293

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
lyrixx opened this issue Nov 8, 2019 · 5 comments · Fixed by #34819
Closed

[Console] Ease creation of single command application #34293

lyrixx opened this issue Nov 8, 2019 · 5 comments · Fixed by #34819
Labels
Console RFC RFC = Request For Comments (proposals about features that you want to be discussed)

Comments

@lyrixx
Copy link
Member
lyrixx commented Nov 8, 2019

Description

I write lot's of "simple" Symfony CLI Application.

I already submitted many PRs to be able to use the following boilerplate code:

<?php

require __DIR__.'/vendor/autoload.php';

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

(new Application())
    ->register('processbar')
        ->setCode(function(InputInterface $input, OutputInterface $output) {
            $output->writeln('hello');
        })
    ->getApplication()
    ->setDefaultCommand('processbar', true)
    ->run()
;

Even if this is already straightforward, I think we can do better.
What do you think of the following code instead:

<?php

require __DIR__.'/vendor/autoload.php';

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

(new SingleApplicationCommand())
    ->setCode(function(InputInterface $input, OutputInterface $output) {
        $output->writeln('hello');
    })
;
@lyrixx lyrixx added Console RFC RFC = Request For Comments (proposals about features that you want to be discussed) labels Nov 8, 2019
@lyrixx lyrixx changed the title [Console] Ease creation of single command [Console] Ease creation of single command application Nov 8, 2019
@jkufner
Copy link
jkufner commented Nov 10, 2019

Passing anonymous function like that tends to make code messy. I would prefer the use of a class. Something like this:

class AppCommand extends Command {
    // ... command as usual
}
(new SingleApplicationCommand(new AppCommand()))->run();

This way, it would be easier to reuse commands later, when the app gets bigger. This also allows to easily move command into a separate executable. And also, it uses already known and well-established interface to configure the commands.

@lyrixx
Copy link
Member Author
lyrixx commented Nov 10, 2019

@jkufner the point here is to make only one command and so with the less boilerplate code. And if we could leverage the existing infrastructure, it's better. This is why I think "anonymous function like that tends to make code messy" is not relevant here.

@jkufner
Copy link
jkufner commented Nov 10, 2019

@lyrixx How simple and readable that minimalistic boilerplate code gets when the command needs a few options and a nice help? How can DI container inject few dependencies?

The anonymous function is fine for the most trivial case, but it does not scale well to handle nontrivial cases. I think that the one extra line the class declaration requires is worth the scalability.

@lyrixx
Copy link
Member Author
lyrixx commented Nov 12, 2019

How simple and readable that minimalistic boilerplate code gets when the command needs a few options and a nice help

Like before:

(new SingleApplicationCommand())
    ->setHelp()
    ->addOption(...)
    ->setCode(function(InputInterface $input, OutputInterface $output) {
        $output->writeln('hello');
    })
;

How can DI container inject few dependencies?

Usually, single command does not use a DIC, because it's not really useful here.

But anyway, if you want, you can inject your dependencies like following

A] see the use (I tested it an approoved it)

(new SingleApplicationCommand())
    ->setHelp()
    ->addOption(...)
    ->setCode(function(InputInterface $input, OutputInterface $output) use ($a, $b) {
        $output->writeln('hello');
    })
;

B] Another idea (I did not tested it)

(new class extends SingleApplicationCommand() {
    private $a;
    public function __construct($a) {
        $this->a = $a;
        parent::__construct();
    )

    public function execute(InputInterface $input, OutputInterface $output) {
        $output->writeln('hello');
    }
});

@derrabus
Copy link
Member

The whole discussion around closures is beside the point. With a regular command, you have the choice to either use setCode() with a closure or to create a subclass of Command and override execute(). A potential SingleApplicationCommand could be built the same way.

@fabpot fabpot closed this as completed Jan 8, 2020
chalasr added a commit that referenced this issue Jan 9, 2020
…n of Single Command Application (lyrixx)

This PR was merged into the 5.1-dev branch.

Discussion
----------

[Console] Add SingleCommandApplication to ease creation of Single Command Application

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Tickets       | Fix #34293
| License       | MIT
| Doc PR        |

---

```php
<?php

require __DIR__.'/vendor/autoload.php';

use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\SingleCommandApplication;

(new SingleCommandApplication())
    ->setName('My Super Command') // Optional
    ->setVersion('1.0.0') // Optional
    ->setProcessTitle('my_proc_title') // Optional
    ->addArgument('who', InputArgument::OPTIONAL, 'Who', 'World')  // Optional
    ->setCode(function(InputInterface $input, OutputInterface $output) {
        $output->writeln(sprintf('Hello %s!', $input->getArgument('who')));
    })
    ->run()
;

```

---

Note: I tried this too, and it works as expected:

```php

class MyCommand extends SingleCommandApplication
{
    public function execute(InputInterface $input, OutputInterface $output)
    {
        $output->writeln('hello');

        return 0;
    }
}

new MyCommand();
```

Commits
-------

4af513d [Console] Add SingleCommandApplication to ease creation of Single Command Application
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Console RFC RFC = Request For Comments (proposals about features that you want to be discussed)
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants
0