Browse Source

Fix #18674: Added more user-friendly exception messages for `yii\i18n\Formatter`

tags/2.0.43
Bizley 3 years ago committed by GitHub
parent
commit
c8e4e0727a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      framework/CHANGELOG.md
  2. 100
      framework/i18n/Formatter.php
  3. 113
      tests/framework/i18n/FormatterNumberTest.php

1
framework/CHANGELOG.md

@ -26,6 +26,7 @@ Yii Framework 2 Change Log
- Enh #18789: Added JSONP support in `yii\web\JsonParser::parse()` (WinterSilence)
- Bug #18274: Fix `yii\log\Logger` to calculate profile timings no matter the value of the flush interval (bizley)
- Bug #18807: Fix replacing source whitespaces and optimize code of `yii\helpers\BaseStringHelper::mb_ucwords()` (WinterSilence)
- Enh #18674: Added more user-friendly exception messages for `yii\i18n\Formatter` (bizley)
2.0.42.1 May 06, 2021

100
framework/i18n/Formatter.php

@ -1732,7 +1732,7 @@ class Formatter extends Component
$oldThousandSeparator = $this->thousandSeparator;
$this->thousandSeparator = '';
if ($this->_intlLoaded && !isset($options[NumberFormatter::GROUPING_USED])) {
$options[NumberFormatter::GROUPING_USED] = false;
$options[NumberFormatter::GROUPING_USED] = 0;
}
// format the size value
$params = [
@ -1793,19 +1793,19 @@ class Formatter extends Component
$formatter = new NumberFormatter($this->locale, $style);
// set text attributes
foreach ($this->numberFormatterTextOptions as $name => $attribute) {
$formatter->setTextAttribute($name, $attribute);
foreach ($this->numberFormatterTextOptions as $attribute => $value) {
$this->setFormatterTextAttribute($formatter, $attribute, $value, 'numberFormatterTextOptions', 'numberFormatterOptions');
}
foreach ($textOptions as $name => $attribute) {
$formatter->setTextAttribute($name, $attribute);
foreach ($textOptions as $attribute => $value) {
$this->setFormatterTextAttribute($formatter, $attribute, $value, '$textOptions', '$options');
}
// set attributes
foreach ($this->numberFormatterOptions as $name => $value) {
$formatter->setAttribute($name, $value);
foreach ($this->numberFormatterOptions as $attribute => $value) {
$this->setFormatterIntAttribute($formatter, $attribute, $value, 'numberFormatterOptions', 'numberFormatterTextOptions');
}
foreach ($options as $name => $value) {
$formatter->setAttribute($name, $value);
foreach ($options as $attribute => $value) {
$this->setFormatterIntAttribute($formatter, $attribute, $value, '$options', '$textOptions');
}
if ($decimals !== null) {
$formatter->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, $decimals);
@ -1823,14 +1823,92 @@ class Formatter extends Component
$formatter->setSymbol(NumberFormatter::GROUPING_SEPARATOR_SYMBOL, $this->thousandSeparator);
$formatter->setSymbol(NumberFormatter::MONETARY_GROUPING_SEPARATOR_SYMBOL, $this->thousandSeparator);
}
foreach ($this->numberFormatterSymbols as $name => $symbol) {
$formatter->setSymbol($name, $symbol);
foreach ($this->numberFormatterSymbols as $symbol => $value) {
$this->setFormatterSymbol($formatter, $symbol, $value, 'numberFormatterSymbols');
}
return $formatter;
}
/**
* @param NumberFormatter $formatter
* @param mixed $attribute
* @param mixed $value
* @param string $source
* @param string $alternative
*/
private function setFormatterTextAttribute($formatter, $attribute, $value, $source, $alternative)
{
if (!is_int($attribute)) {
throw new InvalidArgumentException(
"The $source array keys must be integers recognizable by NumberFormatter::setTextAttribute(). \""
. gettype($attribute) . '" provided instead.'
);
}
if (!is_string($value)) {
if (is_int($value)) {
throw new InvalidArgumentException(
"The $source array values must be strings. Did you mean to use $alternative?"
);
}
throw new InvalidArgumentException(
"The $source array values must be strings. \"" . gettype($value) . '" provided instead.'
);
}
$formatter->setTextAttribute($attribute, $value);
}
/**
* @param NumberFormatter $formatter
* @param mixed $symbol
* @param mixed $value
* @param string $source
*/
private function setFormatterSymbol($formatter, $symbol, $value, $source)
{
if (!is_int($symbol)) {
throw new InvalidArgumentException(
"The $source array keys must be integers recognizable by NumberFormatter::setSymbol(). \""
. gettype($symbol) . '" provided instead.'
);
}
if (!is_string($value)) {
throw new InvalidArgumentException(
"The $source array values must be strings. \"" . gettype($value) . '" provided instead.'
);
}
$formatter->setSymbol($symbol, $value);
}
/**
* @param NumberFormatter $formatter
* @param mixed $attribute
* @param mixed $value
* @param string $source
* @param string $alternative
*/
private function setFormatterIntAttribute($formatter, $attribute, $value, $source, $alternative)
{
if (!is_int($attribute)) {
throw new InvalidArgumentException(
"The $source array keys must be integers recognizable by NumberFormatter::setAttribute(). \""
. gettype($attribute) . '" provided instead.'
);
}
if (!is_int($value)) {
if (is_string($value)) {
throw new InvalidArgumentException(
"The $source array values must be integers. Did you mean to use $alternative?"
);
}
throw new InvalidArgumentException(
"The $source array values must be integers. \"" . gettype($value) . '" provided instead.'
);
}
$formatter->setAttribute($attribute, $value);
}
/**
* Checks if string representations of given value and its normalized version are different.
* @param string|float|int $value
* @param float|int $normalizedValue

113
tests/framework/i18n/FormatterNumberTest.php

@ -823,4 +823,117 @@ class FormatterNumberTest extends TestCase
$this->assertSame('1023 bytes', $this->formatter->asSize(1023));
$this->assertSame('1023 B', $this->formatter->asShortSize(1023));
}
public function providerForDirectWrongTypeAttributes()
{
return [
'not-int key for int options' => [
['a' => 1],
[],
'The $options array keys must be integers recognizable by NumberFormatter::setAttribute(). "string" provided instead.'
],
'string value for int options' => [
[1 => 'a'],
[],
'The $options array values must be integers. Did you mean to use $textOptions?'
],
'non-string-int value for int options' => [
[1 => 1.1],
[],
'The $options array values must be integers. "double" provided instead.'
],
'not-int key for text options' => [
[],
['a' => 1],
'The $textOptions array keys must be integers recognizable by NumberFormatter::setTextAttribute(). "string" provided instead.'
],
'int value for text options' => [
[],
[1 => 1],
'The $textOptions array values must be strings. Did you mean to use $options?'
],
'non-string-int value for text options' => [
[],
[1 => 1.1],
'The $textOptions array values must be strings. "double" provided instead.'
],
];
}
/**
* @dataProvider providerForDirectWrongTypeAttributes
*/
public function testIntlAsIntegerDirectWrongTypeAttributes($intOptions, $textOptions, $message)
{
$this->expectException('yii\base\InvalidArgumentException');
$this->expectExceptionMessage($message);
$this->formatter->asInteger(1, $intOptions, $textOptions);
}
public function providerForConfiguredWrongTypeAttributes()
{
return [
'not-int key for int options' => [
['a' => 1],
[],
[],
'The numberFormatterOptions array keys must be integers recognizable by NumberFormatter::setAttribute(). "string" provided instead.'
],
'string value for int options' => [
[1 => 'a'],
[],
[],
'The numberFormatterOptions array values must be integers. Did you mean to use numberFormatterTextOptions?'
],
'non-string-int value for int options' => [
[1 => 1.1],
[],
[],
'The numberFormatterOptions array values must be integers. "double" provided instead.'
],
'not-int key for text options' => [
[],
['a' => 1],
[],
'The numberFormatterTextOptions array keys must be integers recognizable by NumberFormatter::setTextAttribute(). "string" provided instead.'
],
'int value for text options' => [
[],
[1 => 1],
[],
'The numberFormatterTextOptions array values must be strings. Did you mean to use numberFormatterOptions?'
],
'non-string-int value for text options' => [
[],
[1 => 1.1],
[],
'The numberFormatterTextOptions array values must be strings. "double" provided instead.'
],
'non-int key for symbol' => [
[],
[],
['a' => 2],
'The numberFormatterSymbols array keys must be integers recognizable by NumberFormatter::setSymbol(). "string" provided instead.'
],
'non-string value for symbol' => [
[],
[],
[1 => 3],
'The numberFormatterSymbols array values must be strings. "integer" provided instead.'
],
];
}
/**
* @dataProvider providerForConfiguredWrongTypeAttributes
*/
public function testIntlAsIntegerConfiguredWrongTypeAttributes($intOptions, $textOptions, $symbols, $message)
{
$this->expectException('yii\base\InvalidArgumentException');
$this->expectExceptionMessage($message);
$this->formatter->numberFormatterTextOptions = $textOptions;
$this->formatter->numberFormatterOptions = $intOptions;
$this->formatter->numberFormatterSymbols = $symbols;
$this->formatter->asInteger(1);
}
}

Loading…
Cancel
Save