diff --git a/src/DBAL/Types/LocalizedType.php b/src/DBAL/Types/LocalizedType.php index c3d66a5..8e9834e 100644 --- a/src/DBAL/Types/LocalizedType.php +++ b/src/DBAL/Types/LocalizedType.php @@ -7,6 +7,7 @@ use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Types\ConversionException; use Doctrine\DBAL\Types\JsonType; +use JsonException; /** * Type specialized to store localized data as JSON. @@ -53,7 +54,10 @@ public function convertToDatabaseValue(mixed $value, AbstractPlatform $platform) return ''; } - // @phpstan-ignore-next-line - return parent::convertToDatabaseValue($value, $platform); + try { + return json_encode($value, JSON_THROW_ON_ERROR | JSON_PRESERVE_ZERO_FRACTION | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); + } catch (JsonException $e) { + throw ConversionException::conversionFailedSerialization($value, 'json', $e->getMessage(), $e); + } } } diff --git a/tests/DBAL/Types/LocalizedTypeTest.php b/tests/DBAL/Types/LocalizedTypeTest.php index a6c3b0b..6b39c6f 100644 --- a/tests/DBAL/Types/LocalizedTypeTest.php +++ b/tests/DBAL/Types/LocalizedTypeTest.php @@ -51,4 +51,15 @@ public function testConvertToPHPValueWillThrowIfNotJsonArray(): void $this->expectExceptionMessage("Could not convert database value to 'json' as an error was triggered by the unserialization: 'value in DB is not a JSON encoded associative array'"); $this->type->convertToPHPValue('"foo"', $this->platform); } + + public function testMustAlwaysStoreUnescaped(): void + { + $original = ['fr' => 'aéa/a💕a']; + + $actualDB = $this->type->convertToDatabaseValue($original, $this->platform); + self::assertSame('{"fr":"aéa/a💕a"}', $actualDB, 'unicode and slashes should not be escaped'); + + $actualPHP = $this->type->convertToPHPValue($actualDB, $this->platform); + self::assertSame($original, $actualPHP, 'can be re-converted back to the exact same original'); + } }