feature #23869 [Console] Made console command shortcuts case insensitive (thanosp)

This PR was merged into the 3.4 branch.

Discussion
----------

[Console] Made console command shortcuts case insensitive

| Q             | A
| ------------- | ---
| Branch?       | 3.4
| Bug fix?      | no
| New feature?  | yes <!-- don't forget updating src/**/CHANGELOG.md files -->
| BC breaks?    | no
| Deprecations? | no <!-- don't forget updating UPGRADE-*.md files -->
| Tests pass?   | yes
| Fixed tickets | #... <!-- #-prefixed issue number(s), if any -->
| License       | MIT
| Doc PR        | symfony/symfony-docs#... <!--highly recommended for new features-->

<!--
- Bug fixes must be submitted against the lowest branch where they apply
  (lowest branches are regularly merged to upper ones so they get the fixes too).
- Features and deprecations must be submitted against the 3.4,
  legacy code removals go to the master branch.
- Please fill in this template according to the PR you're about to submit.
- Replace this comment by a description of what your PR is solving.
-->

This patch would save a lot of time wasted correcting typos.
Symfony commands are using `:` as a namespace separator.
Most keyboards require pressing shift to get this character.
As an accident a developer in hurry (me) when trying to use the shortcut of commands will often type the character after `:` also while pressing shift. Right now this will lead to an error effectively wasting the attempt to save time by using the shortcut.

e.g. `bin/console c:C`

Commits
-------

04df283 [Console] Added a case-insensitive fallback for console command names
This commit is contained in:
Robin Chalas 2017-08-12 12:15:53 +02:00
commit c82ec965e0
5 changed files with 68 additions and 3 deletions

View File

@ -578,7 +578,12 @@ class Application
$expr = preg_replace_callback('{([^:]+|)}', function ($matches) { return preg_quote($matches[1]).'[^:]*'; }, $name);
$commands = preg_grep('{^'.$expr.'}', $allCommands);
if (empty($commands) || count(preg_grep('{^'.$expr.'$}', $commands)) < 1) {
if (empty($commands)) {
$commands = preg_grep('{^'.$expr.'}i', $allCommands);
}
// if no commands matched or we just matched namespaces
if (empty($commands) || count(preg_grep('{^'.$expr.'$}i', $commands)) < 1) {
if (false !== $pos = strrpos($name, ':')) {
// check if a namespace exists and contains commands
$this->findNamespace(substr($name, 0, $pos));

View File

@ -6,6 +6,7 @@ CHANGELOG
* added `CommandLoaderInterface`, `FactoryCommandLoader` and PSR-11
`ContainerCommandLoader` for commands lazy-loading
* added a case-insensitive command name matching fallback
3.3.0
-----

View File

@ -51,6 +51,8 @@ class ApplicationTest extends TestCase
require_once self::$fixturesPath.'/Foo3Command.php';
require_once self::$fixturesPath.'/Foo4Command.php';
require_once self::$fixturesPath.'/Foo5Command.php';
require_once self::$fixturesPath.'/FooSameCaseUppercaseCommand.php';
require_once self::$fixturesPath.'/FooSameCaseLowercaseCommand.php';
require_once self::$fixturesPath.'/FoobarCommand.php';
require_once self::$fixturesPath.'/BarBucCommand.php';
require_once self::$fixturesPath.'/FooSubnamespaced1Command.php';
@ -317,6 +319,41 @@ class ApplicationTest extends TestCase
$this->assertInstanceOf('FooCommand', $application->find('a'), '->find() returns a command if the abbreviation exists for an alias');
}
public function testFindCaseSensitiveFirst()
{
$application = new Application();
$application->add(new \FooSameCaseUppercaseCommand());
$application->add(new \FooSameCaseLowercaseCommand());
$this->assertInstanceOf('FooSameCaseUppercaseCommand', $application->find('f:B'), '->find() returns a command if the abbreviation is the correct case');
$this->assertInstanceOf('FooSameCaseUppercaseCommand', $application->find('f:BAR'), '->find() returns a command if the abbreviation is the correct case');
$this->assertInstanceOf('FooSameCaseLowercaseCommand', $application->find('f:b'), '->find() returns a command if the abbreviation is the correct case');
$this->assertInstanceOf('FooSameCaseLowercaseCommand', $application->find('f:bar'), '->find() returns a command if the abbreviation is the correct case');
}
public function testFindCaseInsensitiveAsFallback()
{
$application = new Application();
$application->add(new \FooSameCaseLowercaseCommand());
$this->assertInstanceOf('FooSameCaseLowercaseCommand', $application->find('f:b'), '->find() returns a command if the abbreviation is the correct case');
$this->assertInstanceOf('FooSameCaseLowercaseCommand', $application->find('f:B'), '->find() will fallback to case insensitivity');
$this->assertInstanceOf('FooSameCaseLowercaseCommand', $application->find('FoO:BaR'), '->find() will fallback to case insensitivity');
}
/**
* @expectedException \Symfony\Component\Console\Exception\CommandNotFoundException
* @expectedExceptionMessage Command "FoO:BaR" is ambiguous
*/
public function testFindCaseInsensitiveSuggestions()
{
$application = new Application();
$application->add(new \FooSameCaseLowercaseCommand());
$application->add(new \FooSameCaseUppercaseCommand());
$this->assertInstanceOf('FooSameCaseLowercaseCommand', $application->find('FoO:BaR'), '->find() will find two suggestions with case insensitivity');
}
public function testFindWithCommandLoader()
{
$application = new Application();
@ -414,8 +451,8 @@ class ApplicationTest extends TestCase
public function provideInvalidCommandNamesSingle()
{
return array(
array('foo3:baR'),
array('foO3:bar'),
array('foo3:barr'),
array('fooo3:bar'),
);
}

View File

@ -0,0 +1,11 @@
<?php
use Symfony\Component\Console\Command\Command;
class FooSameCaseLowercaseCommand extends Command
{
protected function configure()
{
$this->setName('foo:bar')->setDescription('foo:bar command');
}
}

View File

@ -0,0 +1,11 @@
<?php
use Symfony\Component\Console\Command\Command;
class FooSameCaseUppercaseCommand extends Command
{
protected function configure()
{
$this->setName('foo:BAR')->setDescription('foo:BAR command');
}
}