Files
xamxam/docs/search.md
T

120 lines
4.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 text
- `year` — exact year
- `orientation` — artistic orientation
- `ap_program` — AP program
- `finality` — finality type
- `format` — format
- `keyword` — tag/keyword
- `language` — 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 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](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