Allow setting one info message per option

This commit is contained in:
Yonel Ceruto 2020-01-19 14:12:29 -05:00
parent 4e659cae87
commit 0477a06d8a
13 changed files with 146 additions and 4 deletions

View File

@ -108,7 +108,15 @@ abstract class Descriptor implements DescriptorInterface
protected function getOptionDefinition(OptionsResolver $optionsResolver, string $option)
{
$definition = [
$definition = [];
if ($info = $optionsResolver->getInfo($option)) {
$definition = [
'info' => $info,
];
}
$definition += [
'required' => $optionsResolver->isRequired($option),
'deprecated' => $optionsResolver->isDeprecated($option),
];

View File

@ -73,6 +73,7 @@ class JsonDescriptor extends Descriptor
}
}
$map += [
'info' => 'info',
'required' => 'required',
'default' => 'default',
'allowed_types' => 'allowedTypes',

View File

@ -114,6 +114,7 @@ class TextDescriptor extends Descriptor
];
}
$map += [
'Info' => 'info',
'Required' => 'required',
'Default' => 'default',
'Allowed types' => 'allowedTypes',

View File

@ -151,6 +151,8 @@ TXT
Symfony\Component\Form\Tests\Command\FooType (foo)
==================================================
---------------- -----------%s
Info "Info" %s
---------------- -----------%s
Required true %s
---------------- -----------%s
@ -209,5 +211,6 @@ class FooType extends AbstractType
$resolver->setNormalizer('foo', function (Options $options, $value) {
return (string) $value;
});
$resolver->setInfo('foo', 'Info');
}
}

View File

@ -2,6 +2,8 @@
Symfony\Component\Form\Extension\Core\Type\ChoiceType (choice_translation_domain)
=================================================================================
---------------- -----------%s
Info - %s
---------------- -----------%s
Required false %s
---------------- -----------%s

View File

@ -5,6 +5,8 @@ Symfony\Component\Form\Tests\Console\Descriptor\FooType (bar)
Deprecated true
--------------------- -----------------------------------
Deprecation message "The option "bar" is deprecated."
--------------------- -----------------------------------
Info -
--------------------- -----------------------------------
Required false
--------------------- -----------------------------------
@ -15,4 +17,4 @@ Symfony\Component\Form\Tests\Console\Descriptor\FooType (bar)
Allowed values -
--------------------- -----------------------------------
Normalizers -
--------------------- -----------------------------------
--------------------- -----------------------------------

View File

@ -2,6 +2,8 @@ Symfony\Component\Form\Tests\Console\Descriptor\FooType (empty_data)
====================================================================
---------------- ----------------------%s
Info - %s
---------------- ----------------------%s
Required false %s
---------------- ----------------------%s
Default Value: null %s

View File

@ -2,6 +2,8 @@
Symfony\Component\Form\Tests\Console\Descriptor\FooType (foo)
=============================================================
---------------- -----------%s
Info - %s
---------------- -----------%s
Required true %s
---------------- -----------%s

View File

@ -19,7 +19,7 @@
"php": "^7.2.5",
"symfony/event-dispatcher": "^4.4|^5.0",
"symfony/intl": "^4.4|^5.0",
"symfony/options-resolver": "^5.0",
"symfony/options-resolver": "^5.1",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.0",
"symfony/property-access": "^5.0",

View File

@ -5,6 +5,7 @@ CHANGELOG
-----
* added fluent configuration of options using `OptionResolver::define()`
* added `setInfo()` and `getInfo()` methods
5.0.0
-----

View File

@ -124,4 +124,18 @@ final class OptionConfigurator
return $this;
}
/**
* Sets an info message for an option.
*
* @return $this
*
* @throws AccessException If called from a lazy option or normalizer
*/
public function info(string $info): self
{
$this->resolver->setInfo($this->name, $info);
return $this;
}
}

View File

@ -71,6 +71,11 @@ class OptionsResolver implements Options
*/
private $allowedTypes = [];
/**
* A list of info messages for each option.
*/
private $info = [];
/**
* A list of closures for evaluating lazy options.
*/
@ -715,6 +720,41 @@ class OptionsResolver implements Options
return new OptionConfigurator($option, $this);
}
/**
* Sets an info message for an option.
*
* @return $this
*
* @throws UndefinedOptionsException If the option is undefined
* @throws AccessException If called from a lazy option or normalizer
*/
public function setInfo(string $option, string $info): self
{
if ($this->locked) {
throw new AccessException('The Info message cannot be set from a lazy option or normalizer.');
}
if (!isset($this->defined[$option])) {
throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $this->formatOptions([$option]), implode('", "', array_keys($this->defined))));
}
$this->info[$option] = $info;
return $this;
}
/**
* Gets the info message for an option.
*/
public function getInfo(string $option): ?string
{
if (!isset($this->defined[$option])) {
throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $this->formatOptions([$option]), implode('", "', array_keys($this->defined))));
}
return $this->info[$option] ?? null;
}
/**
* Removes the option with the given name.
*
@ -734,7 +774,7 @@ class OptionsResolver implements Options
foreach ((array) $optionNames as $option) {
unset($this->defined[$option], $this->defaults[$option], $this->required[$option], $this->resolved[$option]);
unset($this->lazy[$option], $this->normalizers[$option], $this->allowedTypes[$option], $this->allowedValues[$option]);
unset($this->lazy[$option], $this->normalizers[$option], $this->allowedTypes[$option], $this->allowedValues[$option], $this->info[$option]);
}
return $this;
@ -763,6 +803,7 @@ class OptionsResolver implements Options
$this->allowedTypes = [];
$this->allowedValues = [];
$this->deprecated = [];
$this->info = [];
return $this;
}
@ -996,6 +1037,10 @@ class OptionsResolver implements Options
);
}
if (isset($this->info[$option])) {
$message .= sprintf(' Info: %s.', $this->info[$option]);
}
throw new InvalidOptionsException($message);
}
}

View File

@ -14,7 +14,9 @@ namespace Symfony\Component\OptionsResolver\Tests;
use PHPUnit\Framework\Assert;
use PHPUnit\Framework\TestCase;
use Symfony\Component\OptionsResolver\Debug\OptionsResolverIntrospector;
use Symfony\Component\OptionsResolver\Exception\AccessException;
use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
use Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;
@ -2399,6 +2401,7 @@ class OptionsResolverTest extends TestCase
->normalize(static function (Options $options, $value) {
return $value;
})
->info('info message')
;
$introspector = new OptionsResolverIntrospector($this->resolver);
@ -2409,5 +2412,63 @@ class OptionsResolverTest extends TestCase
$this->assertSame(['string', 'bool'], $introspector->getAllowedTypes('foo'));
$this->assertSame(['bar', 'zab'], $introspector->getAllowedValues('foo'));
$this->assertCount(1, $introspector->getNormalizers('foo'));
$this->assertSame('info message', $this->resolver->getInfo('foo'));
}
public function testGetInfo()
{
$info = 'The option info message';
$this->resolver->setDefined('foo');
$this->resolver->setInfo('foo', $info);
$this->assertSame($info, $this->resolver->getInfo('foo'));
}
public function testSetInfoOnNormalization()
{
$this->expectException(AccessException::class);
$this->expectExceptionMessage('The Info message cannot be set from a lazy option or normalizer.');
$this->resolver->setDefined('foo');
$this->resolver->setNormalizer('foo', static function (Options $options, $value) {
$options->setInfo('foo', 'Info');
});
$this->resolver->resolve(['foo' => 'bar']);
}
public function testSetInfoOnUndefinedOption()
{
$this->expectException(UndefinedOptionsException::class);
$this->expectExceptionMessage('The option "bar" does not exist. Defined options are: "foo".');
$this->resolver->setDefined('foo');
$this->resolver->setInfo('bar', 'The option info message');
}
public function testGetInfoOnUndefinedOption2()
{
$this->expectException(UndefinedOptionsException::class);
$this->expectExceptionMessage('The option "bar" does not exist. Defined options are: "foo".');
$this->resolver->setDefined('foo');
$this->resolver->getInfo('bar');
}
public function testInfoOnInvalidValue()
{
$this->expectException(InvalidOptionsException::class);
$this->expectExceptionMessage('The option "expires" with value DateTime is invalid. Info: A future date time.');
$this->resolver
->setRequired('expires')
->setInfo('expires', 'A future date time')
->setAllowedTypes('expires', \DateTime::class)
->setAllowedValues('expires', static function ($value) {
return $value >= new \DateTime('now');
})
;
$this->resolver->resolve(['expires' => new \DateTime('-1 hour')]);
}
}