Skip to content

[Console] Fix input validation when required arguments are missing #15533

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

Merged
merged 2 commits into from
Sep 27, 2015

Conversation

jakzal
Copy link
Contributor

@jakzal jakzal commented Aug 13, 2015

Q A
Bug fix? yes
New feature? no
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets #15505
License MIT
Doc PR -

The rule that was here in place previously only works when arguments are passed from command line, as in command line there is no way of skipping an argument. The rule does not work for arguments set on the Input after a command is run.

@jakzal
Copy link
Contributor Author

jakzal commented Aug 13, 2015

If I used a foreach loop instead of array_filter, I could improve the exception message and say 'Not enough arguments. "name" is missing.'. What do you think?

@jakzal jakzal added the Console label Aug 13, 2015
@jakzal
Copy link
Contributor Author

jakzal commented Aug 13, 2015

This broke tests in FrameworkBundle. Looking into this.

@nochso
Copy link

nochso commented Aug 13, 2015

I had a look at the tests for HelpCommand:

1) Symfony\Component\Console\Tests\Command\HelpCommandTest::testExecuteForCommandAlias
RuntimeException: Not enough arguments.

2) Symfony\Component\Console\Tests\Command\HelpCommandTest::testExecuteForApplicationCommand
RuntimeException: Not enough arguments.

3) Symfony\Component\Console\Tests\Command\HelpCommandTest::testExecuteForApplicationCommandWithXmlOption
RuntimeException: Not enough arguments.

testExecuteForCommandAlias specifically:

What is passed as arguments:
array('command_name' => 'li')

HelpCommand has no required arguments:
new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help'),

getArgumentRequiredCount() returns 1

However, the command => 'help' is missing which is the argument that's actually required. That's the default required argument for Application though, right?

@marek-pietrzak-tg
Copy link
Contributor

I had a quick look at these failing tests as well. command As you said @nochso adding $commandTester->execute(array('command' => 'help', 'command_name' => 'li')); solves the problem with failing tests for the help command test. Normally it's been added here: https://github.com/mheki/symfony/blob/2.3/src/Symfony/Component/Console/Application.php#L176-176 when you pass either --help or -h
As this PR checks also required arguments added during runtime, more difficult to fix is test for router match command as it uses router:debug internally and in order to make that test pass, the command argument should be injected here: https://github.com/mheki/symfony/blob/2.3/src/Symfony/Bundle/FrameworkBundle/Command/RouterMatchCommand.php#L83-83

return $definition->hasArgument($argument) && $definition->getArgument($argument)->isRequired();
});

if (count($requiredArguments) < $this->definition->getArgumentRequiredCount()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (count($requiredArguments) < $definition->getArgumentRequiredCount()) { would be shorter

@fabpot
Copy link
Member

fabpot commented Sep 14, 2015

@jakzal Any news on this one? And to answer your question, I would indeed give more information in the error message if possible.

Previous rule was only working when arguments are passed from command line, as in command line there is no way of skipping an argument. The rule does not work for arguments set on the Input after a command is run.
@jakzal jakzal force-pushed the console/argument-validation-fix branch from 30cbe80 to f12a4c1 Compare September 14, 2015 09:33
@jakzal
Copy link
Contributor Author

jakzal commented Sep 14, 2015

I added a better exception message: Not enough arguments (missing: "name").

Solving the problem with failing command tests is a bit more complex.

The command is a required argument added from the application's definition. It's usually omitted when command is tested with CommandTester or if the command is called directly (like in RouterMatchCommand indicated by @mheki).

The previous version of Input::validate() worked becase it was only comparing number of arguments and there was usually at least one argument given.

To fix this we need to either:

  • require the user to always pass the command argument

  • add the command in its run() method:

        if ($input->hasArgument('command') && null === $input->getArgument('command')) {
            $input->setArgument('command', $this->getName());
        }

First solution would break lots of existing command tests, and the second doesn't seem like the right place (as the command argument is added by the application).

@jakzal
Copy link
Contributor Author

jakzal commented Sep 15, 2015

I went with option 2. Happy to receive feedback. Ping @symfony/deciders.

@@ -241,6 +241,10 @@ public function run(InputInterface $input, OutputInterface $output)
$this->interact($input, $output);
}

if ($input->hasArgument('command') && null === $input->getArgument('command')) {
$input->setArgument('command', $this->getName());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain when this happens? I think it deserves a comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great suggestion. I'll add:

        // The command name argument is often omitted when a command is executed directly with its run() method.
        // It will fail the validation since the command argument is required by the application.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Writing this comment gave me another idea: is the command argument really a required argument? What if we made it optional instead of setting it here?

@jakzal jakzal force-pushed the console/argument-validation-fix branch 2 times, most recently from f2145bd to 45c1cc6 Compare September 16, 2015 08:02
@jakzal jakzal force-pushed the console/argument-validation-fix branch from 45c1cc6 to 4982b02 Compare September 16, 2015 08:05
@fabpot
Copy link
Member

fabpot commented Sep 16, 2015

👍

1 similar comment
@weaverryan
Copy link
Member

👍

@xabbuh
Copy link
Member

xabbuh commented Sep 27, 2015

@jakzal Usually, when using the CommandTester class, the command argument should be added automatically when missing: https://github.com/symfony/symfony/blob/2.8/src/Symfony/Component/Console/Tester/CommandTester.php#L60-65 Can't we just fix those lines to get rid of adding the argument in the Console class itself?

@jakzal
Copy link
Contributor Author

jakzal commented Sep 27, 2015

@xabbuh that's not gonna fix the case of calling commands directly, like here: https://github.com/symfony/symfony/blob/2.3/src/Symfony/Bundle/FrameworkBundle/Command/RouterMatchCommand.php#L83-83

@xabbuh
Copy link
Member

xabbuh commented Sep 27, 2015

Hm, indeed. 👍

Status: Reviewed

@fabpot
Copy link
Member

fabpot commented Sep 27, 2015

Thank you @jakzal.

@fabpot fabpot merged commit 4982b02 into symfony:2.3 Sep 27, 2015
fabpot added a commit that referenced this pull request Sep 27, 2015
… missing (jakzal)

This PR was merged into the 2.3 branch.

Discussion
----------

[Console] Fix input validation when required arguments are missing

| Q             | A
| ------------- | ---
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #15505
| License       | MIT
| Doc PR        | -

The rule that was here in place previously only works when arguments are passed from command line, as in command line there is no way of skipping an argument. The rule does not work for arguments set on the Input after a command is run.

Commits
-------

4982b02 [Console] Add the command name to input arguments if it's missing
f12a4c1 [Console] Fix input validation when required arguments are missing
@jakzal jakzal deleted the console/argument-validation-fix branch September 27, 2015 13:38
This was referenced Oct 27, 2015
@fabpot fabpot mentioned this pull request Oct 27, 2015
xabbuh added a commit to xabbuh/PandaBundle that referenced this pull request Dec 7, 2015
This makes test pass again given the improvements to the message of the
exception that is thrown since symfony/symfony#15533 when a required
argument is missing.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants