Files
xamxam/docs/search.md
T
Pontoporeia a31e4ab307 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.
2026-09-18 16:26:36 +02:00

4.5 KiB
Raw Blame History

Search & Répertoire — Documentation

Two public browsing surfaces, both handled by app/src/Controllers/SearchController.php and routed by app/src/Dispatcher.php:

Route Handler Purpose
/search, /search.php handleSearch() Full-text query + classic single filters
/repertoire, /repertoire.php handleRepertoire() Browseable directory with multi-select filters

Both only ever expose published theses (is_published = 1).


handleSearch() reads from $_GET and renders app/templates/public/search.php with the results fragment (app/templates/partials/search-results.php).

Searchable text fields (via Database::searchTheses()):

  • Title, subtitle, synopsis, author names, supervisor names, tags/keywords.

Single-value filters (collectSearchParams()):

  • query — free text
  • year — exact year
  • orientation — artistic orientation
  • ap_program — AP program
  • finality — finality type
  • format — format
  • keyword — tag/keyword

Results are paginated (limit = 20 default); the search bar (app/templates/partials/search-bar.php) submits a GET form to /search.


HandleRepertoire (/repertoire)

handleRepertoire() reads multi-select filter arrays from $_GET and renders app/templates/public/repertoire.php, which uses the shared results partial and app/templates/partials/repertoire-index.php.

Multi-select filters (collectFilterParams(), each an array, _GET keys):

  • fy[] — years (validated to 1900–2100)
  • ap[] — AP program names
  • or[] — orientations
  • fi[] — finalities
  • kw[] — keywords/tags

Each value is trimmed, length-capped (≤ 100), de-duplicated, and passed through as sanitised strings — no direct user input reaches SQL.

There is also an HTMX student preview popover at /repertoire/student-preview (handleStudentPreview() → student-preview.php).


Rate limiting

Search is rate-limited via app/src/RateLimit.php. See the nginx config (nginx/xamxam.conf) for the matching server-side limits.


Database access

  • Full-text + single filters: Database::searchTheses(array $params, $limit, $offset) and Database::countSearchResults(array $params).
  • Keyword/tag autocomplete: Database::searchTags(string $query).
  • Supervisor autocomplete: Database::searchSupervisors($query, $role).
  • Language autocomplete: Database::searchLanguages(string $query).

Queries operate on v_theses_public; keyword matching joins the thesis_tags / tags tables (keywords are stored as lowercase-normalised tags, not a keywords/thesis_keywords set — see database.md).

All queries use PDO prepared statements and escape %/_ for LIKE (Database::escapeLikeString) to prevent wildcard injection.

Accent-insensitive matching

Text searches on the public search bar, the student-preview popover, and the admin list search are all diacritic-insensitive: Théophile and Theophile, sévère and severe return the same results.

This is implemented via a SQLite user-defined function accfold() (app/src/AccentFolding.php, registered in Database::registerSqliteFunctions()), which strips precomposed accented Latin characters to their ASCII base (é → e, ç → c, …). Search conditions compare the folded column against the folded term (accfold(column) LIKE accfold(:term)), so both sides are normalised the same way. The function is NULL-safe and registered on the production and test connections alike; the public path uses searchTheses()/countSearchResults(), the student popover getThesesByAuthorName(), and the admin list getThesesList()/getThesesListCount().

Note: intl/Normalizer and iconv are not available on the runtime, so folding uses a hand-maintained transliteration map (Western Latin-1 + Latin Extended-A).


Performance notes

  • Critical text/filter columns and the junction tables are indexed (idx_theses_pub_year, idx_theses_*, idx_thesis_tags_*, …).
  • v_theses_public pre-computes the joins for the common read path.
  • The repertoire filters operate on indexed lookup columns.

Future enhancements (not yet implemented)

The historical search.md listed potential automplete/faceted-search/export ideas. Status:

  • Auto-complete for tags exists at the form level (searchTags)
  • Faceted counts, saved searches, result export, and advanced boolean operators are not implemented