Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit1567f44

Browse files
committed
[Command] Added question helper for unknown or ambiguous commands
1 parentd9f1a72 commit1567f44

10 files changed

+265
-41
lines changed

‎src/Symfony/Component/Console/Application.php‎

Lines changed: 40 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,13 @@
1111

1212
namespaceSymfony\Component\Console;
1313

14+
useSymfony\Component\Console\Exception\AmbiguousCommandException;
15+
useSymfony\Component\Console\Exception\AmbiguousNamespaceException;
1416
useSymfony\Component\Console\Exception\ExceptionInterface;
17+
useSymfony\Component\Console\Exception\InvalidArgumentException;
18+
useSymfony\Component\Console\Exception\InvalidCommandNameException;
19+
useSymfony\Component\Console\Exception\UnknownCommandException;
20+
useSymfony\Component\Console\Exception\UnknownNamespaceException;
1521
useSymfony\Component\Console\Helper\DebugFormatterHelper;
1622
useSymfony\Component\Console\Helper\ProcessHelper;
1723
useSymfony\Component\Console\Helper\QuestionHelper;
@@ -36,6 +42,8 @@
3642
useSymfony\Component\Console\Event\ConsoleTerminateEvent;
3743
useSymfony\Component\Console\Exception\CommandNotFoundException;
3844
useSymfony\Component\Console\Exception\LogicException;
45+
useSymfony\Component\Console\Question\ChoiceQuestion;
46+
useSymfony\Component\Console\Question\ConfirmationQuestion;
3947
useSymfony\Component\EventDispatcher\EventDispatcherInterface;
4048

4149
/**
@@ -181,7 +189,30 @@ public function doRun(InputInterface $input, OutputInterface $output)
181189
}
182190

183191
// the command name MUST be the first element of the input
184-
$command =$this->find($name);
192+
do {
193+
try {
194+
$command =$this->find($name);
195+
}catch (CommandNotFoundException$e) {
196+
$alternatives =$e->getAlternatives();
197+
if (0 ===count($alternatives) || !$input->isInteractive() || !$this->getHelperSet()->has('question')) {
198+
throw$e;
199+
}
200+
201+
$helper =$this->getHelperSet()->get('question');
202+
$question =newChoiceQuestion(strtok($e->getMessage(),"\n").' Please select one of these suggested commands:',$alternatives);
203+
$question->setMaxAttempts(1);
204+
205+
try {
206+
$name =$helper->ask($input,$output,$question);
207+
}catch (InvalidArgumentException$ex) {
208+
throw$e;
209+
}
210+
211+
if (null ===$name) {
212+
throw$e;
213+
}
214+
}
215+
}while (!isset($command));
185216

186217
$this->runningCommand =$command;
187218
$exitCode =$this->doRunCommand($command,$input,$output);
@@ -470,7 +501,8 @@ public function getNamespaces()
470501
*
471502
* @return string A registered namespace
472503
*
473-
* @throws CommandNotFoundException When namespace is incorrect or ambiguous
504+
* @throws UnknownNamespaceException When namespace is incorrect
505+
* @throws AmbiguousNamespaceException When namespace is ambiguous
474506
*/
475507
publicfunctionfindNamespace($namespace)
476508
{
@@ -479,24 +511,12 @@ public function findNamespace($namespace)
479511
$namespaces =preg_grep('{^'.$expr.'}',$allNamespaces);
480512

481513
if (empty($namespaces)) {
482-
$message =sprintf('There are no commands defined in the "%s" namespace.',$namespace);
483-
484-
if ($alternatives =$this->findAlternatives($namespace,$allNamespaces)) {
485-
if (1 ==count($alternatives)) {
486-
$message .="\n\nDid you mean this?\n";
487-
}else {
488-
$message .="\n\nDid you mean one of these?\n";
489-
}
490-
491-
$message .=implode("\n",$alternatives);
492-
}
493-
494-
thrownewCommandNotFoundException($message,$alternatives);
514+
thrownewUnknownNamespaceException($namespace,$this->findAlternatives($namespace,$allNamespaces,array()));
495515
}
496516

497517
$exact =in_array($namespace,$namespaces,true);
498518
if (count($namespaces) >1 && !$exact) {
499-
thrownewCommandNotFoundException(sprintf('The namespace "%s" is ambiguous (%s).',$namespace,$this->getAbbreviationSuggestions(array_values($namespaces))),array_values($namespaces));
519+
thrownewAmbiguousNamespaceException($namespace,$namespaces);
500520
}
501521

502522
return$exact ?$namespace :reset($namespaces);
@@ -512,7 +532,8 @@ public function findNamespace($namespace)
512532
*
513533
* @return Command A Command instance
514534
*
515-
* @throws CommandNotFoundException When command name is incorrect or ambiguous
535+
* @throws UnknownCommandException When command name is incorrect
536+
* @throws AmbiguousCommandException When command name is ambiguous
516537
*/
517538
publicfunctionfind($name)
518539
{
@@ -526,18 +547,7 @@ public function find($name)
526547
$this->findNamespace(substr($name,0,$pos));
527548
}
528549

529-
$message =sprintf('Command "%s" is not defined.',$name);
530-
531-
if ($alternatives =$this->findAlternatives($name,$allCommands)) {
532-
if (1 ==count($alternatives)) {
533-
$message .="\n\nDid you mean this?\n";
534-
}else {
535-
$message .="\n\nDid you mean one of these?\n";
536-
}
537-
$message .=implode("\n",$alternatives);
538-
}
539-
540-
thrownewCommandNotFoundException($message,$alternatives);
550+
thrownewUnknownCommandException($name,$this->findAlternatives($name,$allCommands,array()));
541551
}
542552

543553
// filter out aliases for commands which are already on the list
@@ -552,9 +562,7 @@ public function find($name)
552562

553563
$exact =in_array($name,$commands,true);
554564
if (count($commands) >1 && !$exact) {
555-
$suggestions =$this->getAbbreviationSuggestions(array_values($commands));
556-
557-
thrownewCommandNotFoundException(sprintf('Command "%s" is ambiguous (%s).',$name,$suggestions),array_values($commands));
565+
thrownewAmbiguousCommandException($name,array_values($commands));
558566
}
559567

560568
return$this->get($exact ?$name :reset($commands));
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespaceSymfony\Component\Console\Exception;
13+
14+
/**
15+
* @author Martin Hasoň <martin.hason@gmail.com>
16+
*/
17+
class AmbiguousCommandExceptionextends CommandNotFoundException
18+
{
19+
private$command;
20+
21+
publicfunction__construct($command,$alternatives =array(),$code =null,$previous =null)
22+
{
23+
$this->command =$command;
24+
$message =sprintf('Command "%s" is ambiguous (%s).',$command,$this->getAbbreviationSuggestions($alternatives));
25+
26+
parent::__construct($message,$alternatives,$code,$previous);
27+
}
28+
29+
/**
30+
* @return string
31+
*/
32+
publicfunctiongetCommand()
33+
{
34+
return$this->command;
35+
}
36+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespaceSymfony\Component\Console\Exception;
13+
14+
/**
15+
* @author Martin Hasoň <martin.hason@gmail.com>
16+
*/
17+
class AmbiguousNamespaceExceptionextends CommandNotFoundException
18+
{
19+
private$namespace;
20+
21+
publicfunction__construct($namespace,$alternatives =array(),$code =null,$previous =null)
22+
{
23+
$this->command =$namespace;
24+
25+
$message =sprintf('The namespace "%s" is ambiguous (%s).',$namespace,$this->getAbbreviationSuggestions($alternatives));
26+
27+
parent::__construct($message,$alternatives,$code,$previous);
28+
}
29+
30+
/**
31+
* @return string
32+
*/
33+
publicfunctiongetNamespace()
34+
{
35+
return$this->namespace;
36+
}
37+
}

‎src/Symfony/Component/Console/Exception/CommandNotFoundException.php‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,16 @@ public function getAlternatives()
4040
{
4141
return$this->alternatives;
4242
}
43+
44+
/**
45+
* Returns abbreviated suggestions in string format.
46+
*
47+
* @param array $abbrevs Abbreviated suggestions to convert
48+
*
49+
* @return string A formatted string of abbreviated suggestions
50+
*/
51+
protectedfunctiongetAbbreviationSuggestions($abbrevs)
52+
{
53+
returnsprintf('%s, %s%s',reset($abbrevs),next($abbrevs),count($abbrevs) >2 ?sprintf(' and %d more',count($abbrevs) -2) :'');
54+
}
4355
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespaceSymfony\Component\Console\Exception;
13+
14+
/**
15+
* @author Martin Hasoň <martin.hason@gmail.com>
16+
*/
17+
class UnknownCommandExceptionextends CommandNotFoundException
18+
{
19+
private$command;
20+
21+
publicfunction__construct($command,$alternatives =array(),$code =null,$previous =null)
22+
{
23+
$this->command =$command;
24+
25+
$message =sprintf('Command "%s" is not defined.',$command);
26+
27+
if ($alternatives) {
28+
if (1 ==count($alternatives)) {
29+
$message .="\n\nDid you mean this?\n";
30+
}else {
31+
$message .="\n\nDid you mean one of these?\n";
32+
}
33+
34+
$message .=implode("\n",$alternatives);
35+
}
36+
37+
parent::__construct($message,$alternatives,$code,$previous);
38+
}
39+
40+
/**
41+
* @return string
42+
*/
43+
publicfunctiongetCommand()
44+
{
45+
return$this->command;
46+
}
47+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespaceSymfony\Component\Console\Exception;
13+
14+
/**
15+
* @author Martin Hasoň <martin.hason@gmail.com>
16+
*/
17+
class UnknownNamespaceExceptionextends CommandNotFoundException
18+
{
19+
private$namespace;
20+
21+
publicfunction__construct($namespace,$alternatives =array(),$code =null,$previous =null)
22+
{
23+
$this->namespace =$namespace;
24+
25+
$message =sprintf('There are no commands defined in the "%s" namespace.',$namespace);
26+
27+
if ($alternatives) {
28+
if (1 ==count($alternatives)) {
29+
$message .="\n\nDid you mean this?\n";
30+
}else {
31+
$message .="\n\nDid you mean one of these?\n";
32+
}
33+
34+
$message .=implode("\n",$alternatives);
35+
}
36+
37+
parent::__construct($message,$alternatives,$code,$previous);
38+
}
39+
40+
/**
41+
* @return string
42+
*/
43+
publicfunctiongetNamespace()
44+
{
45+
return$this->namespace;
46+
}
47+
}

‎src/Symfony/Component/Console/Tests/ApplicationTest.php‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,33 @@ public function testFindAlternativeCommands()
405405
}
406406
}
407407

408+
publicfunctiontestFindAlternativeCommandsWithQuestion()
409+
{
410+
$application =newApplication();
411+
$application->setAutoExit(false);
412+
putenv('COLUMNS=120');
413+
putenv('SHELL_INTERACTIVE=1');
414+
$application->add(new \FooCommand());
415+
$application->add(new \Foo1Command());
416+
$application->add(new \Foo2Command());
417+
418+
$input =newArrayInput(array('command' =>'foo'));
419+
420+
$inputStream =fopen('php://memory','r+',false);
421+
fwrite($inputStream,"1\n");
422+
rewind($inputStream);
423+
$input->setStream($inputStream);
424+
425+
$output =newStreamOutput(fopen('php://memory','w',false), StreamOutput::VERBOSITY_NORMAL,false);
426+
427+
$application->run($input,$output);
428+
429+
rewind($output->getStream());
430+
$display =str_replace(PHP_EOL,"\n",stream_get_contents($output->getStream()));
431+
432+
$this->assertStringEqualsFile(self::$fixturesPath.'/application_unknown_command_question.txt',$display);
433+
}
434+
408435
publicfunctiontestFindAlternativeCommandsWithAnAlias()
409436
{
410437
$fooCommand =new \FooCommand();
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

2-
3-
[Symfony\Component\Console\Exception\CommandNotFoundException]
4-
Command "foo" is not defined.
5-
2+
3+
[Symfony\Component\Console\Exception\UnknownCommandException]
4+
Command "foo" is not defined.
5+
66

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

2-
3-
[Symfony\Component\Console\Exception\CommandNotFoundException]
4-
Command "foo" is not define
5-
d.
6-
2+
3+
[Symfony\Component\Console\Exception\UnknownCommandException]
4+
Command "foo" is not define
5+
d.
6+
77

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Command "foo" is not defined. Please select one of these suggested commands:
2+
[0] foo:bar1
3+
[1] foo:bar
4+
[2] foo1:bar
5+
[3] afoobar
6+
[4] afoobar1
7+
[5] afoobar2
8+
> 1
9+
interact called
10+
called

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp