diff --git a/src/Doctrine/Functions/SiValueSort.php b/src/Doctrine/Functions/SiValueSort.php index 3d0a7cc8..1bba1b9f 100644 --- a/src/Doctrine/Functions/SiValueSort.php +++ b/src/Doctrine/Functions/SiValueSort.php @@ -82,7 +82,10 @@ class SiValueSort extends FunctionNode assert($this->field !== null, 'Field is not set'); $platform = $sqlWalker->getConnection()->getDatabasePlatform(); - $fieldSql = $this->field->dispatch($sqlWalker); + $rawField = $this->field->dispatch($sqlWalker); + + // Normalize comma decimal separator to dot for SQL platforms (European locale support) + $fieldSql = "REPLACE({$rawField}, ',', '.')"; if ($platform instanceof PostgreSQLPlatform) { return $this->getPostgreSQLSql($fieldSql); @@ -92,6 +95,9 @@ class SiValueSort extends FunctionNode return $this->getMySQLSql($fieldSql); } + // SQLite: comma normalization is handled in the PHP callback + $fieldSql = $rawField; + if ($platform instanceof SQLitePlatform) { return "SI_VALUE({$fieldSql})"; } @@ -168,6 +174,9 @@ class SiValueSort extends FunctionNode return null; } + // Normalize comma decimal separator to dot (European locale support) + $value = str_replace(',', '.', $value); + // Match a number at the very start (allowing leading whitespace), optionally followed by an SI prefix if (!preg_match('/^\s*(\d+\.?\d*)\s*([pnuµmkKMGT])?/u', $value, $matches)) { return null; diff --git a/tests/Doctrine/Functions/SiValueSortTest.php b/tests/Doctrine/Functions/SiValueSortTest.php index 4c13ff69..dbdd9d28 100644 --- a/tests/Doctrine/Functions/SiValueSortTest.php +++ b/tests/Doctrine/Functions/SiValueSortTest.php @@ -37,7 +37,7 @@ final class SiValueSortTest extends AbstractDoctrineFunctionTestCase $sql = $function->getSql($this->createSqlWalker(new PostgreSQLPlatform())); $this->assertStringContainsString('CASE', $sql); - $this->assertStringContainsString('substring(part_name', $sql); + $this->assertStringContainsString("REPLACE(part_name, ',', '.')", $sql); $this->assertStringContainsString('1e-12', $sql); $this->assertStringContainsString('1e-9', $sql); $this->assertStringContainsString('1e-6', $sql); @@ -56,7 +56,7 @@ final class SiValueSortTest extends AbstractDoctrineFunctionTestCase $sql = $function->getSql($this->createSqlWalker(new MySQLPlatform())); $this->assertStringContainsString('CASE', $sql); - $this->assertStringContainsString('REGEXP_SUBSTR(part_name', $sql); + $this->assertStringContainsString("REPLACE(part_name, ',', '.')", $sql); $this->assertStringContainsString('1e-12', $sql); $this->assertStringContainsString('1e6', $sql); } @@ -106,11 +106,16 @@ final class SiValueSortTest extends AbstractDoctrineFunctionTestCase yield 'plain_integer' => ['100', 100.0]; yield 'plain_decimal' => ['4.7', 4.7]; - // Decimal values with prefix + // Decimal values with prefix (dot separator) yield 'decimal_nano' => ['4.7nF', 4.7e-9]; yield 'decimal_micro' => ['0.1uF', 0.1e-6]; yield 'decimal_kilo' => ['2.2k', 2.2e3]; + // Comma decimal separator (European locale) + yield 'comma_kilo' => ['4,7k', 4.7e3]; + yield 'comma_micro' => ['2,2uF', 2.2e-6]; + yield 'comma_kilo_space' => ['1,2 kΩ', 1.2e3]; + // Number NOT at the start — should return NULL yield 'prefixed_name' => ['CAP-100nF', null]; yield 'name_with_number' => ['R 4.7k 1%', null];