From 0dcf099a7cbc4e3a22cde945a161fa243eb34b45 Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Mon, 13 Mar 2023 16:23:54 +0700 Subject: [PATCH] Search with accent did not return existing result #4638 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a search was done in a localized field it did not always return results even though they existed in DB. This is because localized field use JSON to store data in DB and default behavior of Doctrine is to escape unicode characters. That means a "é" would end up as "\u00e9". If the search was only "é" that would still correctly matches, but if the search had a prefix (or suffix) such as "sé", then it would incorrectly not match. To fix this, we override Doctrine behavior and always store unescaped unicode characters. This makes the search straightforward and easier to work with raw data in DB. --- src/DBAL/Types/LocalizedType.php | 8 ++++++-- tests/DBAL/Types/LocalizedTypeTest.php | 11 +++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) 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'); + } }