This class is a container for {@link CommandName}, {@link CommandOption},
{@link Option} and {@link Argument} objects. The format is used to interpret
a given {@link RawArgs} instance.
You can pass the options and arguments to the constructor of the class:
php
$format = new ArgsFormat(array(
new CommandName('server'),
new CommandName('add'),
new Argument('host', Argument::REQUIRED),
new Option('port', 'p', Option::VALUE_OPTIONAL, null, 80),
));
The previous example configures a command that can be called like this:
$ console server add localhost
$ console server add localhost --port 8080
If the "add" command should be called via an option, change the format to:
php
$format = new ArgsFormat(array(
new CommandName('server'),
new CommandOption('add', 'a'),
new Argument('host', Argument::REQUIRED),
new Option('port', 'p', Option::VALUE_OPTIONAL, null, 80),
));
The command is then called like this:
$ console server --add localhost
$ console server --add localhost --port 8080
The format is immutable after its construction. This is necessary to maintain
consistency when one format inherits from another. For example, adding a
required argument to the base format of a format that already contains
optional arguments is an illegal operation that cannot be prevented if the
formats are mutable.
If you want to create a format stepwisely, use an {@link ArgsFormatBuilder}.
If multiple formats share a common set of options and arguments, extract
these options and arguments into a base format and let the other formats
inherit from this base format:
php
$baseFormat = new ArgsFormat(array(
new Option('verbose', 'v'),
));
$format = new ArgsFormat(array(
new CommandName('server'),
new CommandName('add'),
new Argument('host', Argument::REQUIRED),
new Option('port', 'p', Option::VALUE_OPTIONAL, null, 80),
), $baseFormat);
/** * {@inheritdoc} */ public function getCommandFrom($className) { if (class_exists($className)) { $accessor = PropertyAccess::createPropertyAccessor(); $reflector = new \ReflectionClass($className); $instance = $reflector->newInstanceWithoutConstructor(); foreach ($reflector->getProperties() as $property) { if ($instance instanceof ConsoleCommandInterface && $property->getName() == 'io') { continue; } if (!$this->format->hasArgument($property->getName()) && !$this->format->hasOption($property->getName())) { throw new \InvalidArgumentException(sprintf("There is not '%s' argument defined in the %s command", $property->getName(), $className)); } $value = null; if ($this->format->hasArgument($property->getName())) { $value = $this->args->getArgument($property->getName()); } elseif ($this->format->hasOption($property->getName())) { $value = $this->args->getOption($property->getName()); } $accessor->setValue($instance, $property->getName(), $value); } return $instance; } return; }
/** * Creates the arguments from the current class state. * * @param ArgsFormat $format The format. * @param RawArgs $rawArgs The raw arguments. * * @return Args The created console arguments. */ private function createArgs(ArgsFormat $format, RawArgs $rawArgs) { $args = new Args($format, $rawArgs); foreach ($this->arguments as $name => $value) { // Filter command names if ($format->hasArgument($name)) { $args->setArgument($name, $value); } } foreach ($this->options as $name => $value) { // Filter command options if ($format->hasOption($name)) { $args->setOption($name, $value); } } return $args; }
/** * Returns all options added to the builder. * * @param bool $includeBase Whether to include options of the base format * in the result. * * @return Option[] The options. */ public function getOptions($includeBase = true) { Assert::boolean($includeBase, 'The parameter $includeBase must be a boolean. Got: %s'); $options = $this->options; if ($includeBase && $this->baseFormat) { // append base options $options = array_replace($options, $this->baseFormat->getOptions()); } return $options; }
public function testInheritApplicationArgsFormat() { $baseFormat = ArgsFormat::build()->addArgument(new Argument('global-argument'))->addOption(new Option('global-option'))->getFormat(); $this->application->expects($this->any())->method('getGlobalArgsFormat')->willReturn($baseFormat); $config = new CommandConfig('command'); $config->addArgument('argument'); $config->addOption('option'); $command = new Command($config, $this->application); $argsFormat = $command->getArgsFormat(); $this->assertSame($baseFormat, $argsFormat->getBaseFormat()); $this->assertCount(2, $argsFormat->getArguments()); $this->assertTrue($argsFormat->hasArgument('argument')); $this->assertTrue($argsFormat->hasArgument('global-argument')); $this->assertCount(2, $argsFormat->getOptions()); $this->assertTrue($argsFormat->hasOption('option')); $this->assertTrue($argsFormat->hasOption('global-option')); }
/** * {@inheritdoc} */ protected function renderHelp(BlockLayout $layout) { $help = $this->application->getConfig()->getHelp(); $commands = $this->application->getNamedCommands(); $globalArgsFormat = $this->application->getGlobalArgsFormat(); $argsFormat = ArgsFormat::build()->addArgument(new Argument('command', Argument::REQUIRED, 'The command to execute'))->addArgument(new Argument('arg', Argument::MULTI_VALUED, 'The arguments of the command'))->addOptions($globalArgsFormat->getOptions())->getFormat(); $this->renderName($layout, $this->application); $this->renderUsage($layout, $this->application, $argsFormat); $this->renderArguments($layout, $argsFormat->getArguments()); if ($argsFormat->hasOptions()) { $this->renderGlobalOptions($layout, $argsFormat->getOptions()); } if (!$commands->isEmpty()) { $this->renderCommands($layout, $commands); } if ($help) { $this->renderDescription($layout, $help); } }
private function validateSubCommandName(SubCommandConfig $config) { $name = $config->getName(); if (!$name) { throw CannotAddCommandException::nameEmpty(); } if ($this->subCommands->contains($name)) { throw CannotAddCommandException::nameExists($name); } if ($config instanceof OptionCommandConfig) { if ($this->argsFormat->hasOption($name)) { throw CannotAddCommandException::optionExists($name); } if ($shortName = $config->getShortName()) { if ($this->subCommands->contains($shortName)) { throw CannotAddCommandException::nameExists($name); } if ($this->argsFormat->hasOption($shortName)) { throw CannotAddCommandException::optionExists($shortName); } } } }
/** * Creates a new adapter. * * @param ArgsFormat $format The adapted format. */ public function __construct(ArgsFormat $format) { parent::__construct(); $i = 1; foreach ($format->getCommandNames() as $commandName) { do { $argName = 'cmd' . $i++; } while ($format->hasArgument($argName)); $this->addArgument($argument = $this->adaptCommandName($commandName, $argName)); $this->commandNames[$argument->getName()] = $commandName; } foreach ($format->getCommandOptions() as $commandOption) { $this->addOption($this->adaptCommandOption($commandOption)); } foreach ($format->getOptions() as $option) { $this->addOption($this->adaptOption($option)); } foreach ($format->getArguments() as $argument) { $this->addArgument($this->adaptArgument($argument)); } }
public function testBuildAnonymousArgsFormat() { $baseFormat = new ArgsFormat(); $this->config->setName('command'); $this->config->setAliases(array('alias1', 'alias2')); $this->config->addOption('option'); $this->config->addArgument('argument'); $this->config->markAnonymous(); $expected = ArgsFormat::build($baseFormat)->addArgument(new Argument('argument'))->addOption(new Option('option'))->getFormat(); $this->assertEquals($expected, $this->config->buildArgsFormat($baseFormat)); }
public function testParseSetsRawArgs() { $rawArgs = new StringArgs('server'); $format = ArgsFormat::build()->addCommandName(new CommandName('server'))->getFormat(); $args = $this->parser->parseArgs($rawArgs, $format); $this->assertSame($rawArgs, $args->getRawArgs()); }
/** * Returns whether an argument is defined in the format. * * @param string|int $name The argument name or its 0-based position in the * argument list. * * @return bool Returns `true` if the argument exists and `false` otherwise. */ public function isArgumentDefined($name) { return $this->format->hasArgument($name); }
/** * Renders the synopsis of a console command. * * @param BlockLayout $layout The layout. * @param ArgsFormat $argsFormat The console arguments to render. * @param string $appName The name of the application binary. * @param string $prefix The prefix to insert. * @param bool $lastOptional Set to `true` if the last command of the * console arguments is optional. This * command will be enclosed in brackets in * the output. */ protected function renderSynopsis(BlockLayout $layout, ArgsFormat $argsFormat, $appName, $prefix = '', $lastOptional = false) { $nameParts = array(); $argumentParts = array(); $nameParts[] = '<u>' . ($appName ?: 'console') . '</u>'; foreach ($argsFormat->getCommandNames() as $commandName) { $nameParts[] = '<u>' . $commandName->toString() . '</u>'; } foreach ($argsFormat->getCommandOptions() as $commandOption) { $nameParts[] = $commandOption->isLongNamePreferred() ? '--' . $commandOption->getLongName() : '-' . $commandOption->getShortName(); } if ($lastOptional) { $lastIndex = count($nameParts) - 1; $nameParts[$lastIndex] = '[' . $nameParts[$lastIndex] . ']'; } foreach ($argsFormat->getOptions(false) as $option) { // \xC2\xA0 is a non-breaking space if ($option->isValueRequired()) { $format = "%s <%s>"; } elseif ($option->isValueOptional()) { $format = "%s [<%s>]"; } else { $format = '%s'; } $optionName = $option->isLongNamePreferred() ? '--' . $option->getLongName() : '-' . $option->getShortName(); $argumentParts[] = sprintf('[' . $format . ']', $optionName, $option->getValueName()); } foreach ($argsFormat->getArguments() as $argument) { $argName = $argument->getName(); $argumentParts[] = sprintf($argument->isRequired() ? '<%s>' : '[<%s>]', $argName . ($argument->isMultiValued() ? '1' : '')); if ($argument->isMultiValued()) { $argumentParts[] = sprintf('... [<%sN>]', $argName); } } $argsOpts = implode(' ', $argumentParts); $name = implode(' ', $nameParts); $layout->add(new LabeledParagraph($prefix . $name, $argsOpts, 1, false)); }
/** * @expectedException \InvalidArgumentException */ public function testHasOptionsFailsIfIncludeBaseNoBoolean() { $format = new ArgsFormat(); $format->hasOptions(1234); }
/** * {@inheritdoc} */ public function buildArgsFormat(ArgsFormat $baseFormat = null) { $formatBuilder = ArgsFormat::build($baseFormat); if (!$this->isAnonymous()) { $flags = $this->isLongNamePreferred() ? CommandOption::PREFER_LONG_NAME : CommandOption::PREFER_SHORT_NAME; $formatBuilder->addCommandOption(new CommandOption($this->getName(), $this->getShortName(), $this->getAliases(), $flags)); } $formatBuilder->addOptions($this->getOptions()); $formatBuilder->addArguments($this->getArguments()); return $formatBuilder->getFormat(); }
public function testAdaptOptionWithDescriptionAndDefault() { $argsFormat = ArgsFormat::build()->addOption(new Option('option', 'o', Option::OPTIONAL_VALUE, 'The description', 'The default'))->getFormat(); $adapter = new ArgsFormatInputDefinition($argsFormat); $this->assertEquals(array(), $adapter->getArguments()); $this->assertEquals(array('option' => new InputOption('option', 'o', InputOption::VALUE_OPTIONAL, 'The description', 'The default')), $adapter->getOptions()); }
/** * Builds an {@link ArgsFormat} instance with the given base format. * * @param ArgsFormat $baseFormat The base format. * * @return ArgsFormat The built format for the console arguments. */ public function buildArgsFormat(ArgsFormat $baseFormat = null) { $formatBuilder = ArgsFormat::build($baseFormat); if (!$this->anonymous) { $formatBuilder->addCommandName(new CommandName($this->name, $this->aliases)); } $formatBuilder->addOptions($this->getOptions()); $formatBuilder->addArguments($this->getArguments()); return $formatBuilder->getFormat(); }
/** * Returns whether the format contains options. * * @param bool $includeBase Whether to include options in the base format * in the search. * * @return bool Returns `true` if the format contains options and `false` * otherwise. */ public function hasOptions($includeBase = true) { Assert::boolean($includeBase, 'The parameter $includeBase must be a boolean. Got: %s'); if (count($this->options) > 0) { return true; } if ($includeBase && $this->baseFormat) { return $this->baseFormat->hasOptions(); } return false; }
public function testIsArgumentDefined() { $format = ArgsFormat::build()->addArgument(new Argument('argument1'))->addArgument(new Argument('argument2'))->getFormat(); $args = new Args($format); $this->assertTrue($args->isArgumentDefined('argument1')); $this->assertTrue($args->isArgumentDefined('argument2')); $this->assertFalse($args->isArgumentDefined('foo')); }