[Form] Improved multi-byte handling of NumberToLocalizedStringTransformer
This commit is contained in:
parent
9f02b05997
commit
dcced01fd5
@ -80,6 +80,9 @@ class NumberToLocalizedStringTransformer implements DataTransformerInterface
|
||||
throw new TransformationFailedException($formatter->getErrorMessage());
|
||||
}
|
||||
|
||||
// Convert fixed spaces to normal ones
|
||||
$value = str_replace("\xc2\xa0", ' ', $value);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
@ -130,19 +133,31 @@ class NumberToLocalizedStringTransformer implements DataTransformerInterface
|
||||
throw new TransformationFailedException('I don\'t have a clear idea what infinity looks like');
|
||||
}
|
||||
|
||||
if (function_exists('mb_detect_encoding') && false !== $encoding = mb_detect_encoding($value)) {
|
||||
$strlen = function ($string) use ($encoding) {
|
||||
return mb_strlen($string, $encoding);
|
||||
};
|
||||
$substr = function ($string, $offset, $length) use ($encoding) {
|
||||
return mb_substr($string, $offset, $length, $encoding);
|
||||
};
|
||||
} else {
|
||||
$strlen = 'strlen';
|
||||
$substr = 'substr';
|
||||
}
|
||||
|
||||
$length = $strlen($value);
|
||||
|
||||
// After parsing, position holds the index of the character where the
|
||||
// parsing stopped
|
||||
if ($position < strlen($value)) {
|
||||
if ($position < $length) {
|
||||
// Check if there are unrecognized characters at the end of the
|
||||
// number
|
||||
$remainder = substr($value, $position);
|
||||
// number (excluding whitespace characters)
|
||||
$remainder = trim($substr($value, $position, $length), " \t\n\r\0\x0b\xc2\xa0");
|
||||
|
||||
// Remove all whitespace characters
|
||||
if ('' !== preg_replace('/[\s\xc2\xa0]*/', '', $remainder)) {
|
||||
if ('' !== $remainder) {
|
||||
throw new TransformationFailedException(
|
||||
sprintf('The number contains unrecognized characters: "%s"',
|
||||
$remainder
|
||||
));
|
||||
sprintf('The number contains unrecognized characters: "%s"', $remainder)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,29 +22,52 @@ class NumberToLocalizedStringTransformerTest extends LocalizedTestCase
|
||||
\Locale::setDefault('de_AT');
|
||||
}
|
||||
|
||||
public function testTransform()
|
||||
public function provideTransformations()
|
||||
{
|
||||
$transformer = new NumberToLocalizedStringTransformer();
|
||||
|
||||
$this->assertEquals('1', $transformer->transform(1));
|
||||
$this->assertEquals('1,5', $transformer->transform(1.5));
|
||||
$this->assertEquals('1234,5', $transformer->transform(1234.5));
|
||||
$this->assertEquals('12345,912', $transformer->transform(12345.9123));
|
||||
return array(
|
||||
array(null, '', 'de_AT'),
|
||||
array(1, '1', 'de_AT'),
|
||||
array(1.5, '1,5', 'de_AT'),
|
||||
array(1234.5, '1234,5', 'de_AT'),
|
||||
array(12345.912, '12345,912', 'de_AT'),
|
||||
array(1234.5, '1234,5', 'ru'),
|
||||
array(1234.5, '1234,5', 'fi'),
|
||||
);
|
||||
}
|
||||
|
||||
public function testTransformEmpty()
|
||||
/**
|
||||
* @dataProvider provideTransformations
|
||||
*/
|
||||
public function testTransform($from, $to, $locale)
|
||||
{
|
||||
\Locale::setDefault($locale);
|
||||
|
||||
$transformer = new NumberToLocalizedStringTransformer();
|
||||
|
||||
$this->assertSame('', $transformer->transform(null));
|
||||
$this->assertSame($to, $transformer->transform($from));
|
||||
}
|
||||
|
||||
public function testTransformWithGrouping()
|
||||
public function provideTransformationsWithGrouping()
|
||||
{
|
||||
return array(
|
||||
array(1234.5, '1.234,5', 'de_AT'),
|
||||
array(12345.912, '12.345,912', 'de_AT'),
|
||||
array(1234.5, '1 234,5', 'fr'),
|
||||
array(1234.5, '1 234,5', 'ru'),
|
||||
array(1234.5, '1 234,5', 'fi'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideTransformationsWithGrouping
|
||||
*/
|
||||
public function testTransformWithGrouping($from, $to, $locale)
|
||||
{
|
||||
\Locale::setDefault($locale);
|
||||
|
||||
$transformer = new NumberToLocalizedStringTransformer(null, true);
|
||||
|
||||
$this->assertEquals('1.234,5', $transformer->transform(1234.5));
|
||||
$this->assertEquals('12.345,912', $transformer->transform(12345.9123));
|
||||
$this->assertSame($to, $transformer->transform($from));
|
||||
}
|
||||
|
||||
public function testTransformWithPrecision()
|
||||
@ -65,30 +88,48 @@ class NumberToLocalizedStringTransformerTest extends LocalizedTestCase
|
||||
|
||||
}
|
||||
|
||||
public function testReverseTransform()
|
||||
/**
|
||||
* @dataProvider provideTransformations
|
||||
*/
|
||||
public function testReverseTransform($to, $from, $locale)
|
||||
{
|
||||
\Locale::setDefault($locale);
|
||||
|
||||
$transformer = new NumberToLocalizedStringTransformer();
|
||||
|
||||
$this->assertEquals(1, $transformer->reverseTransform('1'));
|
||||
$this->assertEquals(1.5, $transformer->reverseTransform('1,5'));
|
||||
$this->assertEquals(1234.5, $transformer->reverseTransform('1234,5'));
|
||||
$this->assertEquals(12345.912, $transformer->reverseTransform('12345,912'));
|
||||
$this->assertEquals($to, $transformer->reverseTransform($from));
|
||||
}
|
||||
|
||||
public function testReverseTransformEmpty()
|
||||
/**
|
||||
* @dataProvider provideTransformationsWithGrouping
|
||||
*/
|
||||
public function testReverseTransformWithGrouping($to, $from, $locale)
|
||||
{
|
||||
$transformer = new NumberToLocalizedStringTransformer();
|
||||
\Locale::setDefault($locale);
|
||||
|
||||
$this->assertNull($transformer->reverseTransform(''));
|
||||
$transformer = new NumberToLocalizedStringTransformer(null, true);
|
||||
|
||||
$this->assertEquals($to, $transformer->reverseTransform($from));
|
||||
}
|
||||
|
||||
public function testReverseTransformWithGrouping()
|
||||
// https://github.com/symfony/symfony/issues/7609
|
||||
public function testReverseTransformWithGroupingAndFixedSpaces()
|
||||
{
|
||||
if (!extension_loaded('mbstring')) {
|
||||
$this->markTestSkipped('The "mbstring" extension is required for this test.');
|
||||
}
|
||||
|
||||
\Locale::setDefault('ru');
|
||||
|
||||
$transformer = new NumberToLocalizedStringTransformer(null, true);
|
||||
|
||||
$this->assertEquals(1234.5, $transformer->reverseTransform("1\xc2\xa0234,5"));
|
||||
}
|
||||
|
||||
public function testReverseTransformWithGroupingButWithoutGroupSeparator()
|
||||
{
|
||||
$transformer = new NumberToLocalizedStringTransformer(null, true);
|
||||
|
||||
// completely valid format
|
||||
$this->assertEquals(1234.5, $transformer->reverseTransform('1.234,5'));
|
||||
$this->assertEquals(12345.912, $transformer->reverseTransform('12.345,912'));
|
||||
// omit group separator
|
||||
$this->assertEquals(1234.5, $transformer->reverseTransform('1234,5'));
|
||||
$this->assertEquals(12345.912, $transformer->reverseTransform('12345,912'));
|
||||
@ -299,6 +340,7 @@ class NumberToLocalizedStringTransformerTest extends LocalizedTestCase
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
|
||||
* @expectedExceptionMessage The number contains unrecognized characters: "foo3"
|
||||
*/
|
||||
public function testReverseTransformDisallowsCenteredExtraCharacters()
|
||||
{
|
||||
@ -309,6 +351,41 @@ class NumberToLocalizedStringTransformerTest extends LocalizedTestCase
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
|
||||
* @expectedExceptionMessage The number contains unrecognized characters: "foo8"
|
||||
*/
|
||||
public function testReverseTransformDisallowsCenteredExtraCharactersMultibyte()
|
||||
{
|
||||
if (!extension_loaded('mbstring')) {
|
||||
$this->markTestSkipped('The "mbstring" extension is required for this test.');
|
||||
}
|
||||
|
||||
\Locale::setDefault('ru');
|
||||
|
||||
$transformer = new NumberToLocalizedStringTransformer(null, true);
|
||||
|
||||
$transformer->reverseTransform("12\xc2\xa0345,67foo8");
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
|
||||
* @expectedExceptionMessage The number contains unrecognized characters: "foo8"
|
||||
*/
|
||||
public function testReverseTransformIgnoresTrailingSpacesInExceptionMessage()
|
||||
{
|
||||
if (!extension_loaded('mbstring')) {
|
||||
$this->markTestSkipped('The "mbstring" extension is required for this test.');
|
||||
}
|
||||
|
||||
\Locale::setDefault('ru');
|
||||
|
||||
$transformer = new NumberToLocalizedStringTransformer(null, true);
|
||||
|
||||
$transformer->reverseTransform("12\xc2\xa0345,67foo8 \xc2\xa0\t");
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
|
||||
* @expectedExceptionMessage The number contains unrecognized characters: "foo"
|
||||
*/
|
||||
public function testReverseTransformDisallowsTrailingExtraCharacters()
|
||||
{
|
||||
@ -316,4 +393,21 @@ class NumberToLocalizedStringTransformerTest extends LocalizedTestCase
|
||||
|
||||
$transformer->reverseTransform('123foo');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
|
||||
* @expectedExceptionMessage The number contains unrecognized characters: "foo"
|
||||
*/
|
||||
public function testReverseTransformDisallowsTrailingExtraCharactersMultibyte()
|
||||
{
|
||||
if (!extension_loaded('mbstring')) {
|
||||
$this->markTestSkipped('The "mbstring" extension is required for this test.');
|
||||
}
|
||||
|
||||
\Locale::setDefault('ru');
|
||||
|
||||
$transformer = new NumberToLocalizedStringTransformer(null, true);
|
||||
|
||||
$transformer->reverseTransform("12\xc2\xa0345,678foo");
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user