Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions src/Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,36 @@ public function validate(array $arguments, array $options) : array
);
}

/**
* Apply definition defaults to the console.
*
* Any defined argument or option that was not passed on the command line
* and declares a "default" key gets its default written back into the
* Console, so getArgument() and getOption() return the resolved value.
* Values are stored as strings (or booleans for flags) because the
* Console accessors are typed that way.
*
* @param Console $console The console the command is running on
*/
public function applyDefaults(Console $console) : void
{
$arguments = $console->getArguments();
foreach ($this->argumentDefinitions as $key => $definition) {
$default = $definition['default'] ?? null;
if (!\array_key_exists($key, $arguments) && \is_scalar($default)) {
$console->setArgument((int) $key, (string) $default);
}
}
$options = $console->getOptions();
foreach ($this->optionDefinitions as $key => $definition) {
$default = $definition['default'] ?? null;
if (\array_key_exists($key, $options) || !\is_scalar($default)) {
continue;
}
$console->setOption((string) $key, \is_bool($default) ? $default : (string) $default);
}
}

/**
* Validate a set of values against their definitions.
*
Expand Down
33 changes: 33 additions & 0 deletions src/Console.php
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,38 @@ public function getArgument(int $position) : ?string
return $this->arguments[$position] ?? null;
}

/**
* Set an argument value.
*
* Used by Command::applyDefaults() to fill in definition defaults.
*
* @param int $position Argument position, starting from zero
* @param string $value The argument value
*
* @return static
*/
public function setArgument(int $position, string $value) : static
{
$this->arguments[$position] = $value;
return $this;
}

/**
* Set an option value.
*
* Used by Command::applyDefaults() to fill in definition defaults.
*
* @param string $name The option name
* @param bool|string $value The option value
*
* @return static
*/
public function setOption(string $name, bool | string $value) : static
{
$this->options[$name] = $value;
return $this;
}

/**
* Set the Language instance.
*
Expand Down Expand Up @@ -324,6 +356,7 @@ protected function dispatch() : void
$this->validationFailed($errors);
return;
}
$command->applyDefaults($this);
$command->run();
}

Expand Down
55 changes: 55 additions & 0 deletions tests/ValidationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -173,4 +173,59 @@ public function testGettersReturnTheDefinitions() : void
self::assertSame([0 => ['type' => 'int']], $command->getArgumentDefinitions());
self::assertSame(['count' => ['type' => 'int']], $command->getOptionDefinitions());
}

public function testDefaultArgumentIsAppliedWhenMissing() : void
{
$command = new ValidatedCommandMock($this->console);
$command->setArgumentDefinitions([
0 => ['type' => 'int', 'default' => '7'],
]);
$this->console->addCommand($command);
$this->console->exec('validated');
self::assertSame('7', $this->console->getArgument(0));
self::assertStringContainsString('ran', Stdout::getContents());
}

public function testDefaultOptionIsAppliedWhenMissing() : void
{
$command = new ValidatedCommandMock($this->console);
$command->setOptionDefinitions([
'count' => ['type' => 'int', 'default' => '3'],
'verbose' => ['type' => 'flag', 'default' => true],
]);
$this->console->addCommand($command);
$this->console->exec('validated');
self::assertSame('3', $this->console->getOption('count'));
self::assertTrue($this->console->getOption('verbose'));
self::assertStringContainsString('ran', Stdout::getContents());
}

public function testPassedValuesAreNotOverriddenByDefaults() : void
{
$command = new ValidatedCommandMock($this->console);
$command->setArgumentDefinitions([
0 => ['type' => 'int', 'default' => '7'],
]);
$command->setOptionDefinitions([
'count' => ['type' => 'int', 'default' => '3'],
]);
$this->console->addCommand($command);
$this->console->exec('validated 42 --count=5');
self::assertSame('42', $this->console->getArgument(0));
self::assertSame('5', $this->console->getOption('count'));
}

public function testApplyDefaultsDirectlyFillsTheConsole() : void
{
$command = new ValidatedCommandMock($this->console);
$command->setArgumentDefinitions([
0 => ['default' => 'fallback'],
]);
$command->setOptionDefinitions([
'name' => ['default' => 'cli'],
]);
$command->applyDefaults($this->console);
self::assertSame('fallback', $this->console->getArgument(0));
self::assertSame('cli', $this->console->getOption('name'));
}
}
Loading