Skip to content

Commit

Permalink
Search with accent did not return existing result #4638
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
PowerKiKi committed Mar 13, 2023
1 parent f5c1ee5 commit 0dcf099
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 2 deletions.
8 changes: 6 additions & 2 deletions src/DBAL/Types/LocalizedType.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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);
}
}
}
11 changes: 11 additions & 0 deletions tests/DBAL/Types/LocalizedTypeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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');
}
}

0 comments on commit 0dcf099

Please sign in to comment.