mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-09-25 09:53:08 +02:00
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.
152 lines
5.1 KiB
PHP
152 lines
5.1 KiB
PHP
<?php
|
|
|
|
/**
|
|
* TestDatabase — helper for integration tests that need a real SQLite database.
|
|
*
|
|
* Creates an in-memory SQLite database, loads the full schema + seed data,
|
|
* and provides a Database instance connected to it. Teardown discards the DB.
|
|
*/
|
|
|
|
/**
|
|
* Thin Database subclass that accepts a pre-built PDO connection.
|
|
* Bypasses the normal path-based constructor.
|
|
*/
|
|
class TestDatabaseInstance extends Database
|
|
{
|
|
public function __construct(PDO $pdo)
|
|
{
|
|
// 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);
|
|
|
|
$pathRef = new ReflectionProperty(Database::class, 'dbPath');
|
|
$pathRef->setValue($this, ':memory:');
|
|
}
|
|
}
|
|
|
|
class TestDatabase
|
|
{
|
|
private static ?PDO $pdo = null;
|
|
private static ?Database $db = null;
|
|
|
|
/**
|
|
* Get or create the shared test Database instance.
|
|
* Uses an in-memory SQLite DB so tests are fast and isolated.
|
|
*/
|
|
public static function getInstance(): Database
|
|
{
|
|
if (self::$db === null) {
|
|
// 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');
|
|
self::$pdo->exec('PRAGMA journal_mode = MEMORY');
|
|
|
|
// Load schema
|
|
$schema = file_get_contents(APP_ROOT . '/storage/schema.sql');
|
|
if ($schema === false) {
|
|
throw new RuntimeException('Failed to read schema.sql');
|
|
}
|
|
self::$pdo->exec($schema);
|
|
|
|
// Create a Database wrapper injecting our PDO
|
|
self::$db = new TestDatabaseInstance(self::$pdo);
|
|
}
|
|
|
|
return self::$db;
|
|
}
|
|
|
|
/**
|
|
* Get the raw PDO connection (for queries that bypass the Database class).
|
|
*/
|
|
public static function getPDO(): PDO
|
|
{
|
|
// Ensure the DB is booted
|
|
self::getInstance();
|
|
return self::$pdo;
|
|
}
|
|
|
|
/**
|
|
* Reset all test data between tests.
|
|
* Preserves seed data (orientations, access types, etc.) but removes
|
|
* any theses, authors, tags, share links etc. created during a test.
|
|
*/
|
|
public static function resetData(): void
|
|
{
|
|
$pdo = self::getPDO();
|
|
// Order matters due to FK constraints
|
|
$tables = [
|
|
'one_time_tokens',
|
|
'file_access_audit',
|
|
'file_access_sessions',
|
|
'file_access_tokens',
|
|
'file_access_requests',
|
|
'thesis_files',
|
|
'thesis_tags',
|
|
'thesis_formats',
|
|
'thesis_languages',
|
|
'thesis_supervisors',
|
|
'thesis_authors',
|
|
'theses',
|
|
'share_links',
|
|
'tags',
|
|
'authors',
|
|
'supervisors',
|
|
'admin_audit_log',
|
|
'audit_log',
|
|
];
|
|
foreach ($tables as $table) {
|
|
$pdo->exec("DELETE FROM $table");
|
|
}
|
|
// Re-seed tags (some tests rely on tags existing)
|
|
try {
|
|
$pdo->exec('DELETE FROM tags WHERE deleted_at IS NOT NULL');
|
|
} catch (Exception $e) {
|
|
// tags table already empty
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Seed some basic test data: an author, a thesis.
|
|
* Returns [authorId, thesisId].
|
|
*
|
|
* @return array{0: int, 1: int}
|
|
*/
|
|
public static function seedBasicThesis(string $title = 'Test Thesis', string $authorName = 'Test Author', int $year = 2024): array
|
|
{
|
|
$pdo = self::getPDO();
|
|
|
|
// Insert author
|
|
$pdo->prepare('INSERT INTO authors (name) VALUES (?)')->execute([$authorName]);
|
|
$authorId = (int)$pdo->lastInsertId();
|
|
|
|
// Insert thesis
|
|
$pdo->prepare(
|
|
"INSERT INTO theses (title, year, identifier, is_published, objet) VALUES (?, ?, ?, 1, 'tfe')"
|
|
)->execute([$title, $year, "$year-001"]);
|
|
|
|
$thesisId = (int)$pdo->lastInsertId();
|
|
|
|
// Link author
|
|
$pdo->prepare('INSERT INTO thesis_authors (thesis_id, author_id) VALUES (?, ?)')
|
|
->execute([$thesisId, $authorId]);
|
|
|
|
// Insert a cover file
|
|
$pdo->prepare(
|
|
"INSERT INTO thesis_files (thesis_id, file_type, file_path, file_name, file_size, mime_type) VALUES (?, 'cover', ?, ?, 0, 'image/jpeg')"
|
|
)->execute([$thesisId, "documents/$year-001/cover.jpg", 'cover.jpg']);
|
|
|
|
return [$authorId, $thesisId];
|
|
}
|
|
}
|