Skip to content

Navigation Menu

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

Appearance settings

Commit 5abc30f

Browse filesBrowse files
committed
Add options to automatically run suggested command if there is only 1 alternative
1 parent a97f8b7 commit 5abc30f
Copy full SHA for 5abc30f

File tree

7 files changed

+151
-21
lines changed
Filter options

7 files changed

+151
-21
lines changed

‎UPGRADE-4.1.md

Copy file name to clipboardExpand all lines: UPGRADE-4.1.md
+21Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,27 @@
11
UPGRADE FROM 4.0 to 4.1
22
=======================
33

4+
Console
5+
-------
6+
7+
* The `Application::findNamespace` method throws an instance of `NamespaceNotFoundException` instead `CommandNotFoundException`. All catch statements should be updated to cater for both exceptions, E.G
8+
9+
Before:
10+
```php
11+
try {
12+
$app->run();
13+
} catch (CommandNotFoundException $e) {
14+
}
15+
```
16+
17+
After:
18+
```php
19+
try {
20+
$app->run();
21+
} catch (NamespaceNotFoundException | CommandNotFoundException $e) {
22+
}
23+
```
24+
425
HttpFoundation
526
--------------
627

‎UPGRADE-5.0.md

Copy file name to clipboardExpand all lines: UPGRADE-5.0.md
+21Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,27 @@
11
UPGRADE FROM 4.x to 5.0
22
=======================
33

4+
Console
5+
-------
6+
7+
* The `NamespaceNotFoundException` doesn't extend `CommandNotFoundException` anymore. All catch statements should be updated to cater for both exceptions, E.G
8+
9+
Before:
10+
```php
11+
try {
12+
$app->run();
13+
} catch (CommandNotFoundException $e) {
14+
}
15+
```
16+
17+
After:
18+
```php
19+
try {
20+
$app->run();
21+
} catch (NamespaceNotFoundException | CommandNotFoundException $e) {
22+
}
23+
```
24+
425
HttpFoundation
526
--------------
627

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Console/Application.php
+18-4Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Symfony\Component\Console\CommandLoader\CommandLoaderInterface;
1515
use Symfony\Component\Console\Exception\ExceptionInterface;
16+
use Symfony\Component\Console\Exception\NamespaceNotFoundException;
1617
use Symfony\Component\Console\Formatter\OutputFormatter;
1718
use Symfony\Component\Console\Helper\DebugFormatterHelper;
1819
use Symfony\Component\Console\Helper\Helper;
@@ -39,6 +40,7 @@
3940
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
4041
use Symfony\Component\Console\Exception\CommandNotFoundException;
4142
use Symfony\Component\Console\Exception\LogicException;
43+
use Symfony\Component\Console\Question\ConfirmationQuestion;
4244
use Symfony\Component\Debug\ErrorHandler;
4345
use Symfony\Component\Debug\Exception\FatalThrowableError;
4446
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
@@ -226,7 +228,19 @@ public function doRun(InputInterface $input, OutputInterface $output)
226228
$e = $event->getError();
227229
}
228230

229-
throw $e;
231+
if (!($e instanceof CommandNotFoundException && !$e instanceof NamespaceNotFoundException) || 1 !== count($alternatives = $e->getAlternatives()) || !$input->isInteractive()) {
232+
throw $e;
233+
}
234+
235+
$alternative = $alternatives[0];
236+
$output->writeln(sprintf('<error>Command "%s" is not defined.</error>', $name));
237+
$question = new ConfirmationQuestion(sprintf('Do you want to run "%s" instead? [y/n] ', $alternative), false);
238+
239+
if (!(new QuestionHelper())->ask($input, $output, $question)) {
240+
return 1;
241+
}
242+
243+
$command = $this->find($alternative);
230244
}
231245

232246
$this->runningCommand = $command;
@@ -525,7 +539,7 @@ public function getNamespaces()
525539
*
526540
* @return string A registered namespace
527541
*
528-
* @throws CommandNotFoundException When namespace is incorrect or ambiguous
542+
* @throws NamespaceNotFoundException When namespace is incorrect or ambiguous
529543
*/
530544
public function findNamespace($namespace)
531545
{
@@ -546,12 +560,12 @@ public function findNamespace($namespace)
546560
$message .= implode("\n ", $alternatives);
547561
}
548562

549-
throw new CommandNotFoundException($message, $alternatives);
563+
throw new NamespaceNotFoundException($message, $alternatives);
550564
}
551565

552566
$exact = in_array($namespace, $namespaces, true);
553567
if (count($namespaces) > 1 && !$exact) {
554-
throw new CommandNotFoundException(sprintf("The namespace \"%s\" is ambiguous.\nDid you mean one of these?\n%s", $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))), array_values($namespaces));
568+
throw new NamespaceNotFoundException(sprintf("The namespace \"%s\" is ambiguous.\nDid you mean one of these?\n%s", $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))), array_values($namespaces));
555569
}
556570

557571
return $exact ? $namespace : reset($namespaces);

‎src/Symfony/Component/Console/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/Console/CHANGELOG.md
+7-2Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
CHANGELOG
22
=========
33

4+
4.1.0
5+
-----
6+
7+
* added option to run suggested command if command is not found and only 1 alternative is available
8+
49
4.0.0
510
-----
611

712
* `OutputFormatter` throws an exception when unknown options are used
813
* removed `QuestionHelper::setInputStream()/getInputStream()`
914
* removed `Application::getTerminalWidth()/getTerminalHeight()` and
1015
`Application::setTerminalDimensions()/getTerminalDimensions()`
11-
* removed `ConsoleExceptionEvent`
12-
* removed `ConsoleEvents::EXCEPTION`
16+
* removed `ConsoleExceptionEvent`
17+
* removed `ConsoleEvents::EXCEPTION`
1318

1419
3.4.0
1520
-----
+23Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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+
namespace Symfony\Component\Console\Exception;
13+
14+
/**
15+
* Represents an incorrect namespace typed in the console.
16+
*
17+
* @author Pierre du Plessis <pdples@gmail.com>
18+
*
19+
* @deprecated This class won't extend CommandNotFoundException in Symfony 5
20+
*/
21+
class NamespaceNotFoundException extends CommandNotFoundException
22+
{
23+
}

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Console/Tests/ApplicationTest.php
+40-15Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Symfony\Component\Console\Command\Command;
1717
use Symfony\Component\Console\CommandLoader\FactoryCommandLoader;
1818
use Symfony\Component\Console\DependencyInjection\AddConsoleCommandPass;
19+
use Symfony\Component\Console\Exception\NamespaceNotFoundException;
1920
use Symfony\Component\Console\Helper\HelperSet;
2021
use Symfony\Component\Console\Helper\FormatterHelper;
2122
use Symfony\Component\Console\Input\ArgvInput;
@@ -56,6 +57,7 @@ public static function setUpBeforeClass()
5657
require_once self::$fixturesPath.'/BarBucCommand.php';
5758
require_once self::$fixturesPath.'/FooSubnamespaced1Command.php';
5859
require_once self::$fixturesPath.'/FooSubnamespaced2Command.php';
60+
require_once self::$fixturesPath.'/FooWithoutAliasCommand.php';
5961
require_once self::$fixturesPath.'/TestTiti.php';
6062
require_once self::$fixturesPath.'/TestToto.php';
6163
}
@@ -275,10 +277,10 @@ public function testFindAmbiguousNamespace()
275277
$expectedMsg = "The namespace \"f\" is ambiguous.\nDid you mean one of these?\n foo\n foo1";
276278

277279
if (method_exists($this, 'expectException')) {
278-
$this->expectException(CommandNotFoundException::class);
280+
$this->expectException(NamespaceNotFoundException::class);
279281
$this->expectExceptionMessage($expectedMsg);
280282
} else {
281-
$this->setExpectedException(CommandNotFoundException::class, $expectedMsg);
283+
$this->setExpectedException(NamespaceNotFoundException::class, $expectedMsg);
282284
}
283285

284286
$application->findNamespace('f');
@@ -293,7 +295,7 @@ public function testFindNonAmbiguous()
293295
}
294296

295297
/**
296-
* @expectedException \Symfony\Component\Console\Exception\CommandNotFoundException
298+
* @expectedException \Symfony\Component\Console\Exception\NamespaceNotFoundException
297299
* @expectedExceptionMessage There are no commands defined in the "bar" namespace.
298300
*/
299301
public function testFindInvalidNamespace()
@@ -457,6 +459,29 @@ public function testFindAlternativeExceptionMessageSingle($name)
457459
$application->find($name);
458460
}
459461

462+
public function testCanRunAlternativeCommandName()
463+
{
464+
$application = new Application();
465+
$application->add(new \FooWithoutAliasCommand());
466+
$application->setAutoExit(false);
467+
$tester = new ApplicationTester($application);
468+
$tester->setInputs(array('y'));
469+
$tester->run(array('command' => 'foos'), array('decorated' => false));
470+
$this->assertSame("Command \"foos\" is not defined.\nDo you want to run \"foo\" instead? [y/n] called\n", $tester->getDisplay(true));
471+
}
472+
473+
public function testDontRunAlternativeCommandName()
474+
{
475+
$application = new Application();
476+
$application->add(new \FooWithoutAliasCommand());
477+
$application->setAutoExit(false);
478+
$tester = new ApplicationTester($application);
479+
$tester->setInputs(array('n'));
480+
$exitCode = $tester->run(array('command' => 'foos'), array('decorated' => false));
481+
$this->assertSame(1, $exitCode);
482+
$this->assertSame("Command \"foos\" is not defined.\nDo you want to run \"foo\" instead? [y/n] ", $tester->getDisplay(true));
483+
}
484+
460485
public function provideInvalidCommandNamesSingle()
461486
{
462487
return array(
@@ -486,10 +511,10 @@ public function testFindAlternativeExceptionMessageMultiple()
486511
// Namespace + plural
487512
try {
488513
$application->find('foo2:bar');
489-
$this->fail('->find() throws a CommandNotFoundException if command does not exist, with alternatives');
514+
$this->fail('->find() throws a NamespaceNotFoundException if command does not exist, with alternatives');
490515
} catch (\Exception $e) {
491-
$this->assertInstanceOf('Symfony\Component\Console\Exception\CommandNotFoundException', $e, '->find() throws a CommandNotFoundException if command does not exist, with alternatives');
492-
$this->assertRegExp('/Did you mean one of these/', $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, with alternatives');
516+
$this->assertInstanceOf('Symfony\Component\Console\Exception\NamespaceNotFoundException', $e, '->find() throws a NamespaceNotFoundException if command does not exist, with alternatives');
517+
$this->assertRegExp('/Did you mean one of these/', $e->getMessage(), '->find() throws a NamespaceNotFoundException if command does not exist, with alternatives');
493518
$this->assertRegExp('/foo1/', $e->getMessage());
494519
}
495520

@@ -563,26 +588,26 @@ public function testFindAlternativeNamespace()
563588

564589
try {
565590
$application->find('Unknown-namespace:Unknown-command');
566-
$this->fail('->find() throws a CommandNotFoundException if namespace does not exist');
591+
$this->fail('->find() throws a NamespaceNotFoundException if namespace does not exist');
567592
} catch (\Exception $e) {
568-
$this->assertInstanceOf('Symfony\Component\Console\Exception\CommandNotFoundException', $e, '->find() throws a CommandNotFoundException if namespace does not exist');
593+
$this->assertInstanceOf('Symfony\Component\Console\Exception\NamespaceNotFoundException', $e, '->find() throws a NamespaceNotFoundException if namespace does not exist');
569594
$this->assertSame(array(), $e->getAlternatives());
570-
$this->assertEquals('There are no commands defined in the "Unknown-namespace" namespace.', $e->getMessage(), '->find() throws a CommandNotFoundException if namespace does not exist, without alternatives');
595+
$this->assertEquals('There are no commands defined in the "Unknown-namespace" namespace.', $e->getMessage(), '->find() throws a NamespaceNotFoundException if namespace does not exist, without alternatives');
571596
}
572597

573598
try {
574599
$application->find('foo2:command');
575-
$this->fail('->find() throws a CommandNotFoundException if namespace does not exist');
600+
$this->fail('->find() throws a NamespaceNotFoundException if namespace does not exist');
576601
} catch (\Exception $e) {
577-
$this->assertInstanceOf('Symfony\Component\Console\Exception\CommandNotFoundException', $e, '->find() throws a CommandNotFoundException if namespace does not exist');
602+
$this->assertInstanceOf('Symfony\Component\Console\Exception\NamespaceNotFoundException', $e, '->find() throws a NamespaceNotFoundException if namespace does not exist');
578603
$this->assertCount(3, $e->getAlternatives());
579604
$this->assertContains('foo', $e->getAlternatives());
580605
$this->assertContains('foo1', $e->getAlternatives());
581606
$this->assertContains('foo3', $e->getAlternatives());
582-
$this->assertRegExp('/There are no commands defined in the "foo2" namespace./', $e->getMessage(), '->find() throws a CommandNotFoundException if namespace does not exist, with alternative');
583-
$this->assertRegExp('/foo/', $e->getMessage(), '->find() throws a CommandNotFoundException if namespace does not exist, with alternative : "foo"');
584-
$this->assertRegExp('/foo1/', $e->getMessage(), '->find() throws a CommandNotFoundException if namespace does not exist, with alternative : "foo1"');
585-
$this->assertRegExp('/foo3/', $e->getMessage(), '->find() throws a CommandNotFoundException if namespace does not exist, with alternative : "foo3"');
607+
$this->assertRegExp('/There are no commands defined in the "foo2" namespace./', $e->getMessage(), '->find() throws a NamespaceNotFoundException if namespace does not exist, with alternative');
608+
$this->assertRegExp('/foo/', $e->getMessage(), '->find() throws a NamespaceNotFoundException if namespace does not exist, with alternative : "foo"');
609+
$this->assertRegExp('/foo1/', $e->getMessage(), '->find() throws a NamespaceNotFoundException if namespace does not exist, with alternative : "foo1"');
610+
$this->assertRegExp('/foo3/', $e->getMessage(), '->find() throws a NamespaceNotFoundException if namespace does not exist, with alternative : "foo3"');
586611
}
587612
}
588613

+21Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
use Symfony\Component\Console\Command\Command;
4+
use Symfony\Component\Console\Input\InputInterface;
5+
use Symfony\Component\Console\Output\OutputInterface;
6+
7+
class FooWithoutAliasCommand extends Command
8+
{
9+
protected function configure()
10+
{
11+
$this
12+
->setName('foo')
13+
->setDescription('The foo command')
14+
;
15+
}
16+
17+
protected function execute(InputInterface $input, OutputInterface $output)
18+
{
19+
$output->writeln('called');
20+
}
21+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.