Skip to content

Commit 0dcf099

Browse files
committed
Search with accent did not return existing result #4638
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.
1 parent f5c1ee5 commit 0dcf099

File tree

2 files changed

+17
-2
lines changed

2 files changed

+17
-2
lines changed

src/DBAL/Types/LocalizedType.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Doctrine\DBAL\Platforms\AbstractPlatform;
88
use Doctrine\DBAL\Types\ConversionException;
99
use Doctrine\DBAL\Types\JsonType;
10+
use JsonException;
1011

1112
/**
1213
* Type specialized to store localized data as JSON.
@@ -53,7 +54,10 @@ public function convertToDatabaseValue(mixed $value, AbstractPlatform $platform)
5354
return '';
5455
}
5556

56-
// @phpstan-ignore-next-line
57-
return parent::convertToDatabaseValue($value, $platform);
57+
try {
58+
return json_encode($value, JSON_THROW_ON_ERROR | JSON_PRESERVE_ZERO_FRACTION | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
59+
} catch (JsonException $e) {
60+
throw ConversionException::conversionFailedSerialization($value, 'json', $e->getMessage(), $e);
61+
}
5862
}
5963
}

tests/DBAL/Types/LocalizedTypeTest.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,15 @@ public function testConvertToPHPValueWillThrowIfNotJsonArray(): void
5151
$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'");
5252
$this->type->convertToPHPValue('"foo"', $this->platform);
5353
}
54+
55+
public function testMustAlwaysStoreUnescaped(): void
56+
{
57+
$original = ['fr' => 'aéa/a💕a'];
58+
59+
$actualDB = $this->type->convertToDatabaseValue($original, $this->platform);
60+
self::assertSame('{"fr":"aéa/a💕a"}', $actualDB, 'unicode and slashes should not be escaped');
61+
62+
$actualPHP = $this->type->convertToPHPValue($actualDB, $this->platform);
63+
self::assertSame($original, $actualPHP, 'can be re-converted back to the exact same original');
64+
}
5465
}

0 commit comments

Comments
 (0)