made the console tool more powerful
* The command names have now full support for nested namespaces. It means that abbreviations work for each sub-namespace: ./app/console doctrine:mapping:info # worked before ./app/console doctrine:map:in # works now ./app/console doc:map:in * Aliases are now first class citizen. They can have their own namespace, like the main name. So, now, there is no difference between an alias and a name. * As names and aliases can be namespaced, the Command::getFullName() and Command::getNamespace() method have been removed.
This commit is contained in:
parent
89f544afb6
commit
facff73049
@ -9,6 +9,10 @@ timeline closely anyway.
|
||||
beta4 to beta5
|
||||
--------------
|
||||
|
||||
* In the Console component: `Command::getFullname()` and
|
||||
`Command::getNamespace()` have been removed (`Command::getName()` behavior
|
||||
is now the same as the old `Command::getFullname()`).
|
||||
|
||||
* Default Twig form templates have been moved to the Twig bridge. Here is how
|
||||
you can reference them now from a template or in a configuration setting:
|
||||
|
||||
|
@ -387,7 +387,7 @@ class Application
|
||||
{
|
||||
$command->setApplication($this);
|
||||
|
||||
$this->commands[$command->getFullName()] = $command;
|
||||
$this->commands[$command->getName()] = $command;
|
||||
|
||||
foreach ($command->getAliases() as $alias) {
|
||||
$this->aliases[$alias] = $command;
|
||||
@ -452,12 +452,18 @@ class Application
|
||||
{
|
||||
$namespaces = array();
|
||||
foreach ($this->commands as $command) {
|
||||
if ($command->getNamespace()) {
|
||||
$namespaces[$command->getNamespace()] = true;
|
||||
if ($namespace = $this->extractNamespace($command->getName())) {
|
||||
$namespaces[] = $namespace;
|
||||
}
|
||||
|
||||
foreach ($command->getAliases() as $alias) {
|
||||
if ($namespace = $this->extractNamespace($alias)) {
|
||||
$namespaces[] = $namespace;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array_keys($namespaces);
|
||||
return array_unique($namespaces);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -471,17 +477,27 @@ class Application
|
||||
*/
|
||||
public function findNamespace($namespace)
|
||||
{
|
||||
$abbrevs = static::getAbbreviations($this->getNamespaces());
|
||||
$allNamespaces = array();
|
||||
foreach ($this->getNamespaces() as $n) {
|
||||
$allNamespaces[$n] = explode(':', $n);
|
||||
}
|
||||
|
||||
if (!isset($abbrevs[$namespace])) {
|
||||
$found = array();
|
||||
foreach (explode(':', $namespace) as $i => $part) {
|
||||
$abbrevs = static::getAbbreviations(array_unique(array_values(array_filter(array_map(function ($p) use ($i) { return isset($p[$i]) ? $p[$i] : ''; }, $allNamespaces)))));
|
||||
|
||||
if (!isset($abbrevs[$part])) {
|
||||
throw new \InvalidArgumentException(sprintf('There are no commands defined in the "%s" namespace.', $namespace));
|
||||
}
|
||||
|
||||
if (count($abbrevs[$namespace]) > 1) {
|
||||
if (count($abbrevs[$part]) > 1) {
|
||||
throw new \InvalidArgumentException(sprintf('The namespace "%s" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions($abbrevs[$namespace])));
|
||||
}
|
||||
|
||||
return $abbrevs[$namespace][0];
|
||||
$found[] = $abbrevs[$part][0];
|
||||
}
|
||||
|
||||
return implode(':', $found);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -502,43 +518,42 @@ class Application
|
||||
{
|
||||
// namespace
|
||||
$namespace = '';
|
||||
$searchName = $name;
|
||||
if (false !== $pos = strrpos($name, ':')) {
|
||||
$namespace = $this->findNamespace(substr($name, 0, $pos));
|
||||
$name = substr($name, $pos + 1);
|
||||
$searchName = $namespace.substr($name, $pos);
|
||||
}
|
||||
|
||||
$fullName = $namespace ? $namespace.':'.$name : $name;
|
||||
|
||||
// name
|
||||
$commands = array();
|
||||
foreach ($this->commands as $command) {
|
||||
if ($command->getNamespace() == $namespace) {
|
||||
if ($this->extractNamespace($command->getName()) == $namespace) {
|
||||
$commands[] = $command->getName();
|
||||
}
|
||||
}
|
||||
|
||||
$abbrevs = static::getAbbreviations($commands);
|
||||
if (isset($abbrevs[$name]) && 1 == count($abbrevs[$name])) {
|
||||
return $this->get($namespace ? $namespace.':'.$abbrevs[$name][0] : $abbrevs[$name][0]);
|
||||
if (isset($abbrevs[$searchName]) && 1 == count($abbrevs[$searchName])) {
|
||||
return $this->get($abbrevs[$searchName][0]);
|
||||
}
|
||||
|
||||
if (isset($abbrevs[$name]) && count($abbrevs[$name]) > 1) {
|
||||
$suggestions = $this->getAbbreviationSuggestions(array_map(function ($command) use ($namespace) { return $namespace.':'.$command; }, $abbrevs[$name]));
|
||||
if (isset($abbrevs[$searchName]) && count($abbrevs[$searchName]) > 1) {
|
||||
$suggestions = $this->getAbbreviationSuggestions($abbrevs[$searchName]);
|
||||
|
||||
throw new \InvalidArgumentException(sprintf('Command "%s" is ambiguous (%s).', $fullName, $suggestions));
|
||||
throw new \InvalidArgumentException(sprintf('Command "%s" is ambiguous (%s).', $name, $suggestions));
|
||||
}
|
||||
|
||||
// aliases
|
||||
$abbrevs = static::getAbbreviations(array_keys($this->aliases));
|
||||
if (!isset($abbrevs[$fullName])) {
|
||||
throw new \InvalidArgumentException(sprintf('Command "%s" is not defined.', $fullName));
|
||||
if (!isset($abbrevs[$searchName])) {
|
||||
throw new \InvalidArgumentException(sprintf('Command "%s" is not defined.', $name));
|
||||
}
|
||||
|
||||
if (count($abbrevs[$fullName]) > 1) {
|
||||
throw new \InvalidArgumentException(sprintf('Command "%s" is ambiguous (%s).', $fullName, $this->getAbbreviationSuggestions($abbrevs[$fullName])));
|
||||
if (count($abbrevs[$searchName]) > 1) {
|
||||
throw new \InvalidArgumentException(sprintf('Command "%s" is ambiguous (%s).', $name, $this->getAbbreviationSuggestions($abbrevs[$searchName])));
|
||||
}
|
||||
|
||||
return $this->get($abbrevs[$fullName][0]);
|
||||
return $this->get($abbrevs[$searchName][0]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -560,7 +575,7 @@ class Application
|
||||
|
||||
$commands = array();
|
||||
foreach ($this->commands as $name => $command) {
|
||||
if ($namespace === $command->getNamespace()) {
|
||||
if ($namespace === $this->extractNamespace($command->getName())) {
|
||||
$commands[$name] = $command;
|
||||
}
|
||||
}
|
||||
@ -630,7 +645,7 @@ class Application
|
||||
foreach ($commands as $command) {
|
||||
$aliases = $command->getAliases() ? '<comment> ('.implode(', ', $command->getAliases()).')</comment>' : '';
|
||||
|
||||
$messages[] = sprintf(" <info>%-${width}s</info> %s%s", ($command->getNamespace() ? ':' : '').$command->getName(), $command->getDescription(), $aliases);
|
||||
$messages[] = sprintf(" <info>%-${width}s</info> %s%s", $command->getName(), $command->getDescription(), $aliases);
|
||||
}
|
||||
}
|
||||
|
||||
@ -778,7 +793,10 @@ class Application
|
||||
{
|
||||
$namespacedCommands = array();
|
||||
foreach ($commands as $name => $command) {
|
||||
$key = $command->getNamespace() ? $command->getNamespace() : '_global';
|
||||
$key = $this->extractNamespace($command->getName());
|
||||
if (!$key) {
|
||||
$key = '_global';
|
||||
}
|
||||
|
||||
if (!isset($namespacedCommands[$key])) {
|
||||
$namespacedCommands[$key] = array();
|
||||
@ -806,4 +824,13 @@ class Application
|
||||
{
|
||||
return sprintf('%s, %s%s', $abbrevs[0], $abbrevs[1], count($abbrevs) > 2 ? sprintf(' and %d more', count($abbrevs) - 2) : '');
|
||||
}
|
||||
|
||||
private function extractNamespace($name)
|
||||
{
|
||||
if (false !== $pos = strrpos($name, ':')) {
|
||||
return substr($name, 0, $pos);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,6 @@ class Command
|
||||
{
|
||||
private $application;
|
||||
private $name;
|
||||
private $namespace;
|
||||
private $aliases;
|
||||
private $definition;
|
||||
private $help;
|
||||
@ -319,35 +318,13 @@ class Command
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
if (false !== $pos = strrpos($name, ':')) {
|
||||
$namespace = substr($name, 0, $pos);
|
||||
$name = substr($name, $pos + 1);
|
||||
} else {
|
||||
$namespace = $this->namespace;
|
||||
}
|
||||
$this->validateName($name);
|
||||
|
||||
if (!$name) {
|
||||
throw new \InvalidArgumentException('A command name cannot be empty.');
|
||||
}
|
||||
|
||||
$this->namespace = $namespace;
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the command namespace.
|
||||
*
|
||||
* @return string The command namespace
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getNamespace()
|
||||
{
|
||||
return $this->namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the command name.
|
||||
*
|
||||
@ -360,18 +337,6 @@ class Command
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the fully qualified command name.
|
||||
*
|
||||
* @return string The fully qualified command name
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getFullName()
|
||||
{
|
||||
return $this->getNamespace() ? $this->getNamespace().':'.$this->getName() : $this->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the description for the command.
|
||||
*
|
||||
@ -436,7 +401,7 @@ class Command
|
||||
*/
|
||||
public function getProcessedHelp()
|
||||
{
|
||||
$name = $this->namespace.':'.$this->name;
|
||||
$name = $this->name;
|
||||
|
||||
$placeholders = array(
|
||||
'%command.name%',
|
||||
@ -461,6 +426,10 @@ class Command
|
||||
*/
|
||||
public function setAliases($aliases)
|
||||
{
|
||||
foreach ($aliases as $alias) {
|
||||
$this->validateName($alias);
|
||||
}
|
||||
|
||||
$this->aliases = $aliases;
|
||||
|
||||
return $this;
|
||||
@ -486,7 +455,7 @@ class Command
|
||||
public function getSynopsis()
|
||||
{
|
||||
if (null === $this->synopsis) {
|
||||
$this->synopsis = trim(sprintf('%s %s', $this->getFullName(), $this->definition->getSynopsis()));
|
||||
$this->synopsis = trim(sprintf('%s %s', $this->name, $this->definition->getSynopsis()));
|
||||
}
|
||||
|
||||
return $this->synopsis;
|
||||
@ -547,9 +516,8 @@ class Command
|
||||
$dom = new \DOMDocument('1.0', 'UTF-8');
|
||||
$dom->formatOutput = true;
|
||||
$dom->appendChild($commandXML = $dom->createElement('command'));
|
||||
$commandXML->setAttribute('id', $this->getFullName());
|
||||
$commandXML->setAttribute('namespace', $this->getNamespace() ? $this->getNamespace() : '_global');
|
||||
$commandXML->setAttribute('name', $this->getName());
|
||||
$commandXML->setAttribute('id', $this->name);
|
||||
$commandXML->setAttribute('name', $this->name);
|
||||
|
||||
$commandXML->appendChild($usageXML = $dom->createElement('usage'));
|
||||
$usageXML->appendChild($dom->createTextNode(sprintf($this->getSynopsis(), '')));
|
||||
@ -573,4 +541,11 @@ class Command
|
||||
|
||||
return $asDom ? $dom : $dom->saveXml();
|
||||
}
|
||||
|
||||
private function validateName($name)
|
||||
{
|
||||
if (!preg_match('/^[^\:]+(\:[^\:]+)*$/', $name)) {
|
||||
throw new \InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ class CommandTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEquals('The command name cannot be empty.', $e->getMessage(), '__construct() throws a \LogicException if the name is null');
|
||||
}
|
||||
$command = new Command('foo:bar');
|
||||
$this->assertEquals('foo:bar', $command->getFullName(), '__construct() takes the command name as its first argument');
|
||||
$this->assertEquals('foo:bar', $command->getName(), '__construct() takes the command name as its first argument');
|
||||
}
|
||||
|
||||
public function testSetApplication()
|
||||
@ -83,30 +83,23 @@ class CommandTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertTrue($command->getDefinition()->hasOption('foo'), '->addOption() adds an option to the command');
|
||||
}
|
||||
|
||||
public function testGetNamespaceGetNameGetFullNameSetName()
|
||||
public function testGetNamespaceGetNameSetName()
|
||||
{
|
||||
$command = new \TestCommand();
|
||||
$this->assertEquals('namespace', $command->getNamespace(), '->getNamespace() returns the command namespace');
|
||||
$this->assertEquals('name', $command->getName(), '->getName() returns the command name');
|
||||
$this->assertEquals('namespace:name', $command->getFullName(), '->getNamespace() returns the full command name');
|
||||
$this->assertEquals('namespace:name', $command->getName(), '->getName() returns the command name');
|
||||
$command->setName('foo');
|
||||
$this->assertEquals('foo', $command->getName(), '->setName() sets the command name');
|
||||
|
||||
$command->setName(':bar');
|
||||
$this->assertEquals('bar', $command->getName(), '->setName() sets the command name');
|
||||
$this->assertEquals('', $command->getNamespace(), '->setName() can set the command namespace');
|
||||
|
||||
$ret = $command->setName('foobar:bar');
|
||||
$this->assertEquals($command, $ret, '->setName() implements a fluent interface');
|
||||
$this->assertEquals('bar', $command->getName(), '->setName() sets the command name');
|
||||
$this->assertEquals('foobar', $command->getNamespace(), '->setName() can set the command namespace');
|
||||
$this->assertEquals('foobar:bar', $command->getName(), '->setName() sets the command name');
|
||||
|
||||
try {
|
||||
$command->setName('');
|
||||
$this->fail('->setName() throws an \InvalidArgumentException if the name is empty');
|
||||
} catch (\Exception $e) {
|
||||
$this->assertInstanceOf('\InvalidArgumentException', $e, '->setName() throws an \InvalidArgumentException if the name is empty');
|
||||
$this->assertEquals('A command name cannot be empty.', $e->getMessage(), '->setName() throws an \InvalidArgumentException if the name is empty');
|
||||
$this->assertEquals('Command name "" is invalid.', $e->getMessage(), '->setName() throws an \InvalidArgumentException if the name is empty');
|
||||
}
|
||||
|
||||
try {
|
||||
@ -114,7 +107,7 @@ class CommandTest extends \PHPUnit_Framework_TestCase
|
||||
$this->fail('->setName() throws an \InvalidArgumentException if the name is empty');
|
||||
} catch (\Exception $e) {
|
||||
$this->assertInstanceOf('\InvalidArgumentException', $e, '->setName() throws an \InvalidArgumentException if the name is empty');
|
||||
$this->assertEquals('A command name cannot be empty.', $e->getMessage(), '->setName() throws an \InvalidArgumentException if the name is empty');
|
||||
$this->assertEquals('Command name "foo:" is invalid.', $e->getMessage(), '->setName() throws an \InvalidArgumentException if the name is empty');
|
||||
}
|
||||
}
|
||||
|
||||
@ -239,7 +232,7 @@ class CommandTest extends \PHPUnit_Framework_TestCase
|
||||
$command = new \TestCommand();
|
||||
$command->setApplication(new Application());
|
||||
$tester = new CommandTester($command);
|
||||
$tester->execute(array('command' => $command->getFullName()));
|
||||
$tester->execute(array('command' => $command->getName()));
|
||||
$this->assertStringEqualsFile(self::$fixturesPath.'/command_astext.txt', $command->asText(), '->asText() returns a text representation of the command');
|
||||
}
|
||||
|
||||
@ -248,7 +241,7 @@ class CommandTest extends \PHPUnit_Framework_TestCase
|
||||
$command = new \TestCommand();
|
||||
$command->setApplication(new Application());
|
||||
$tester = new CommandTester($command);
|
||||
$tester->execute(array('command' => $command->getFullName()));
|
||||
$tester->execute(array('command' => $command->getName()));
|
||||
$this->assertXmlStringEqualsXmlFile(self::$fixturesPath.'/command_asxml.txt', $command->asXml(), '->asXml() returns an XML representation of the command');
|
||||
}
|
||||
}
|
||||
|
@ -21,10 +21,10 @@ class ListCommandTest extends \PHPUnit_Framework_TestCase
|
||||
$application = new Application();
|
||||
|
||||
$commandTester = new CommandTester($command = $application->get('list'));
|
||||
$commandTester->execute(array('command' => $command->getFullName()));
|
||||
$commandTester->execute(array('command' => $command->getName()));
|
||||
$this->assertRegExp('/help Displays help for a command/', $commandTester->getDisplay(), '->execute() returns a list of available commands');
|
||||
|
||||
$commandTester->execute(array('command' => $command->getFullName(), '--xml' => true));
|
||||
$this->assertRegExp('/<command id="list" namespace="_global" name="list">/', $commandTester->getDisplay(), '->execute() returns a list of available commands in XML if --xml is passed');
|
||||
$commandTester->execute(array('command' => $command->getName(), '--xml' => true));
|
||||
$this->assertRegExp('/<command id="list" name="list">/', $commandTester->getDisplay(), '->execute() returns a list of available commands in XML if --xml is passed');
|
||||
}
|
||||
}
|
||||
|
@ -15,4 +15,4 @@
|
||||
<info>help </info> Displays help for a command<comment> (?)</comment>
|
||||
<info>list </info> Lists commands
|
||||
<comment>foo</comment>
|
||||
<info>:bar </info> The foo:bar command<comment> (afoobar)</comment>
|
||||
<info>foo:bar </info> The foo:bar command<comment> (afoobar)</comment>
|
@ -12,4 +12,4 @@
|
||||
<info>--no-interaction</info> <info>-n</info> Do not ask any interactive question.
|
||||
|
||||
<comment>Available commands for the "foo" namespace:</comment>
|
||||
<info>:bar </info> The foo:bar command<comment> (afoobar)</comment>
|
||||
<info>foo:bar </info> The foo:bar command<comment> (afoobar)</comment>
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<symfony>
|
||||
<commands>
|
||||
<command id="help" namespace="_global" name="help">
|
||||
<command id="help" name="help">
|
||||
<usage>help [--xml] [command_name]</usage>
|
||||
<description>Displays help for a command</description>
|
||||
<help>The <info>help</info> command displays help for a given command:
|
||||
@ -28,7 +28,7 @@
|
||||
</option>
|
||||
</options>
|
||||
</command>
|
||||
<command id="list" namespace="_global" name="list">
|
||||
<command id="list" name="list">
|
||||
<usage>list [--xml] [namespace]</usage>
|
||||
<description>Lists commands</description>
|
||||
<help>The <info>list</info> command lists all commands:
|
||||
@ -55,7 +55,7 @@
|
||||
</option>
|
||||
</options>
|
||||
</command>
|
||||
<command id="foo:bar" namespace="foo" name="bar">
|
||||
<command id="foo:bar" name="foo:bar">
|
||||
<usage>foo:bar</usage>
|
||||
<description>The foo:bar command</description>
|
||||
<help/>
|
||||
@ -72,7 +72,7 @@
|
||||
<command>list</command>
|
||||
</namespace>
|
||||
<namespace id="foo">
|
||||
<command>bar</command>
|
||||
<command>foo:bar</command>
|
||||
</namespace>
|
||||
</namespaces>
|
||||
</symfony>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<symfony>
|
||||
<commands namespace="foo">
|
||||
<command id="foo:bar" namespace="foo" name="bar">
|
||||
<command id="foo:bar" name="foo:bar">
|
||||
<usage>foo:bar</usage>
|
||||
<description>The foo:bar command</description>
|
||||
<help/>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<command id="namespace:name" namespace="namespace" name="name">
|
||||
<command id="namespace:name" name="namespace:name">
|
||||
<usage>namespace:name</usage>
|
||||
<description>description</description>
|
||||
<help>help</help>
|
||||
|
Reference in New Issue
Block a user