mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-09-25 09:53:08 +02:00
99 lines
3.4 KiB
Markdown
99 lines
3.4 KiB
Markdown
# 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
|
||
|
||
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.
|
||
|
||
---
|
||
|
||
## 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
|