4.5 KiB
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 (/search)
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 textyear— exact yearorientation— artistic orientationap_program— AP programfinality— finality typeformat— formatkeyword— tag/keywordlanguage— language
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 namesor[]— orientationsfi[]— finalitieskw[]— 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)andDatabase::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_publicpre-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