mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-09-25 01:53:03 +02:00
Recherche insensible aux accents sur toutes les barres de recherche (publique + backoffice).
Ajoute une fonction SQLite UDF accfold() (app/src/AccentFolding.php) qui plie les caractères accentués latin vers leur base ASCII (é→e, ç→c, …), et l'applique à chaque condition de recherche côté colonne ET côté terme (accfold(column) LIKE accfold(:term)). Comme le runtime n'a ni intl (Normalizer) ni iconv, le repli passe par une map de translitération manuelle (Western Latin-1 + Latin Extended-A, NULL-safe). Couvert : - recherche publique (searchTheses / countSearchResults) : titre, sous-titre, synopsis, auteurs, promoteurs, tags ; - popover étudiant (getThesesByAuthorName / getThesesForAuthors) : a.name ; - recherche backoffice (getThesesList / getThesesListCount) : titre, sous-titre, identifiant, auteur. L'UDF est enregistré dans Database::registerSqliteFunctions() (appelé par le constructeur et par le harnais de test TestDatabaseInstance). Évite aussi la dépréciation PHP 8.5 de PDO::sqliteCreateFunction() : la connexion est créée via \Pdo\Sqlite quand disponible (createFunction()) avec repli sur PDO (sqliteCreateFunction()) sur les anciens runtimes ; les tests passent de @dataProvider docblock à l'attribut #[DataProvider] (fin de la dépréciation PHPUnit). Détache .php-cs-fixer.cache (gitignoré) pour ne plus polluer le working copy. 294 tests PHPUnit verts sans dépréciation, phpstan niveau 5 OK.
This commit is contained in:
+12
-2
@@ -15,7 +15,11 @@ class TestDatabaseInstance extends Database
|
||||
{
|
||||
public function __construct(PDO $pdo)
|
||||
{
|
||||
// Inject PDO directly via reflection, then flag as ready
|
||||
// Inject PDO directly via reflection, then flag as ready.
|
||||
// Because we bypass the parent constructor, we must also register the
|
||||
// custom SQLite functions (e.g. accfold) it would otherwise install.
|
||||
Database::registerSqliteFunctions($pdo);
|
||||
|
||||
$ref = new ReflectionProperty(Database::class, 'pdo');
|
||||
$ref->setValue($this, $pdo);
|
||||
|
||||
@@ -36,7 +40,13 @@ class TestDatabase
|
||||
public static function getInstance(): Database
|
||||
{
|
||||
if (self::$db === null) {
|
||||
self::$pdo = new PDO('sqlite::memory:');
|
||||
// Since PHP 8.5, `PDO::sqliteCreateFunction()` is deprecated and the
|
||||
// registration in Database::registerSqliteFunctions() uses
|
||||
// `Pdo\Sqlite::createFunction()` when the connection is a `Pdo\Sqlite`.
|
||||
// Build the same connection type here so the new API path is exercised.
|
||||
self::$pdo = class_exists('Pdo\Sqlite')
|
||||
? new Pdo\Sqlite('sqlite::memory:')
|
||||
: new PDO('sqlite::memory:');
|
||||
self::$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
self::$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
|
||||
self::$pdo->exec('PRAGMA foreign_keys = ON');
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* AccentInsensitiveSearchTest — regression tests ensuring all search paths
|
||||
* (public search, student preview, admin list) treat accented and
|
||||
* non-accented queries as equivalent. "Théophile" must match "Theophile",
|
||||
* "sévère" must match "severe", etc.
|
||||
*/
|
||||
class AccentInsensitiveSearchTest extends TestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
TestDatabase::resetData();
|
||||
}
|
||||
|
||||
#[DataProvider('foldProvider')]
|
||||
public function testFoldStripsDiacritics(string $input, string $expected): void
|
||||
{
|
||||
$this->assertSame($expected, AccentFolding::fold($input));
|
||||
}
|
||||
|
||||
public static function foldProvider(): array
|
||||
{
|
||||
return [
|
||||
'french name' => ['Théophile', 'Theophile'],
|
||||
'lowercase + mixed' => ['sévère où ça', 'severe ou ca'],
|
||||
// Upper diacritics fold to lower base letters (LIKE is case-insensitive in SQLite,
|
||||
// so this is fine for matching; the point is É and é both fold to e).
|
||||
'upper diacritics' => ['ÉCOLE À ö', 'eCOLE a o'],
|
||||
'cedilla' => ['garçon', 'garcon'],
|
||||
'n tilde' => ['señor', 'senor'],
|
||||
'umlauts' => ['üöä', 'uoa'],
|
||||
'apex/apostrophe' => ['l\'erg', "l'erg"],
|
||||
'empty' => ['', ''],
|
||||
'no diacritics' => ['plain text', 'plain text'],
|
||||
];
|
||||
}
|
||||
|
||||
public function testFoldReturnsNullForNull(): void
|
||||
{
|
||||
$this->assertNull(AccentFolding::fold(null));
|
||||
}
|
||||
|
||||
public function testPublicSearchMatchedWithoutAccent(): void
|
||||
{
|
||||
TestDatabase::seedBasicThesis('TFE ac', 'Théophile Dupont', 2024);
|
||||
$db = TestDatabase::getInstance();
|
||||
$res = $db->searchTheses(['query' => 'theophile']);
|
||||
$this->assertCount(1, $res);
|
||||
$this->assertStringContainsString('Théophile', $res[0]['authors']);
|
||||
}
|
||||
|
||||
public function testPublicSearchMatchedWithAccent(): void
|
||||
{
|
||||
TestDatabase::seedBasicThesis('TFE ac', 'Théophile Dupont', 2024);
|
||||
$db = TestDatabase::getInstance();
|
||||
$res = $db->searchTheses(['query' => 'Théophile']);
|
||||
$this->assertCount(1, $res);
|
||||
}
|
||||
|
||||
public function testTitleSearchIgnoresAccent(): void
|
||||
{
|
||||
TestDatabase::seedBasicThesis('Sévère étude', 'Auteur', 2024);
|
||||
$db = TestDatabase::getInstance();
|
||||
$res = $db->searchTheses(['query' => 'severe']);
|
||||
$this->assertCount(1, $res);
|
||||
}
|
||||
|
||||
public function testSearchReturnsNothingForMismatch(): void
|
||||
{
|
||||
TestDatabase::seedBasicThesis('Distinct Title', 'Autre Auteur', 2024);
|
||||
$db = TestDatabase::getInstance();
|
||||
$this->assertCount(0, $db->searchTheses(['query' => 'xyzzy-no-match']));
|
||||
}
|
||||
|
||||
public function testAuthorNamePreviewIgnoresAccent(): void
|
||||
{
|
||||
[$authorId, $thesisId] = TestDatabase::seedBasicThesis('P', 'Théophile Dupont', 2024);
|
||||
$db = TestDatabase::getInstance();
|
||||
$this->assertCount(1, $db->getThesesByAuthorName('Theophile Dupont'));
|
||||
$this->assertCount(1, $db->getThesesByAuthorName('Théophile Dupont'));
|
||||
$this->assertCount(0, $db->getThesesByAuthorName('Jean-Claude'));
|
||||
}
|
||||
|
||||
public function testAdminListIgnoresAccent(): void
|
||||
{
|
||||
TestDatabase::seedBasicThesis('Étude de cas', 'Théophile Martin', 2025);
|
||||
$db = TestDatabase::getInstance();
|
||||
|
||||
$accented = $db->getThesesList(['search' => 'Théophile'], 0, 0);
|
||||
$plain = $db->getThesesList(['search' => 'theophile'], 0, 0);
|
||||
|
||||
$this->assertCount(1, $accented);
|
||||
$this->assertEquals($accented, $plain);
|
||||
$this->assertSame(0, $db->getThesesListCount(['search' => 'zz-nope']));
|
||||
}
|
||||
|
||||
public function testAdminIdentifierSearchStillMatchesAscii(): void
|
||||
{
|
||||
[$authorId, $thesisId] = TestDatabase::seedBasicThesis('X', 'Auteur', 2024);
|
||||
$db = TestDatabase::getInstance();
|
||||
// seedBasicThesis uses identifier "$year-001" → "2024-001"
|
||||
$pdo = TestDatabase::getPDO();
|
||||
$id = $pdo->query("SELECT identifier FROM theses WHERE id = $thesisId")->fetchColumn();
|
||||
$this->assertCount(1, $db->getThesesList(['search' => $id], 0, 0));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user