Move all data-fetching and request logic out of the 285-line search page
into src/SearchController.php:
- SearchController::create() — static factory; builds RateLimit + Database
dependencies, sends HTTP 429 (and exits) if rate limit is exceeded,
runs probabilistic cleanup, returns ready instance
- SearchController::handle() — sanitises GET params (query/year/orientation/
ap_program/keyword), runs all DB queries (searchTheses, countSearchResults,
getAvailableYears, getAllOrientations, getAllAPPrograms, getUsedTags,
getPublishedAuthors), builds alphabetical author→id map, assembles
OG/meta tags, returns a flat array of view variables
- Rate-limit 429 HTML response moved into private sendRateLimitResponse()
public/search.php is now a 6-line dispatcher:
require SearchController; extract(SearchController::create()->handle());
followed by the unchanged view template (162 lines total, was 285).
The view template is byte-for-byte equivalent: same HTML, same variable
names, same pagination partial include.