# Search Requirement Specifications — Modernized Screen **Path:** ASIDE menu > Requirements > *Search Requirement Specifications* **URL:** `gui/templates/requirements/searchReqSpec.html?tproject_id=&tplan_id=` **BFF API:** `api/requirements/index.php` routes `GET /reqspec-context` and `GET /reqspec-search` (session-based auth, JSON I/O) **Prerequisite:** `mgt_view_req` right on the current test project (same rule as legacy menu visibility); the entry is hidden otherwise and both routes return HTTP 403. **Replaces:** legacy form `lib/requirements/reqSpecSearchForm.php` + results grid from `lib/requirements/reqSpecSearch.php` (ExtJS table). **Update (#1825):** both legacy controllers are now **retired session-guarded shims** (302 to the modern screen, 405 for a write verb, 405 JSON for an XHR) and the criteria page itself is modern too — see [Search Requirement Specifications — Criteria Form](Search-Requirement-Specifications-Form.md). This screen honours `?auto_search=1` (run the search on arrival) and offers a **Criteria form** button that hands the criteria on screen back to that page. > **Bug fix (#1735):** the retired legacy controller used to answer **HTTP 500 / 0 bytes** > (`count($itemSet)` on an uninitialised variable). The retirement removed the defect; the > modern BFF serves the search and its `no_records_found` state without any PHP-8 > `TypeError`. See > [Bugfix Issue #1735](Bugfix-Issue-1735-reqSpecSearch-count-null-500.md). ![Search form](search-reqspec-form.png) --- ## What it does Searches **requirement specifications of the CURRENT test project only**, combining all filled criteria with a logical **AND** (`LIKE '%value%'` semantics on text fields) — exactly like TestLink 1.9.20. Like the legacy screen, the search runs against **`req_specs_revisions`** (doc id, scope, type, log message are matched per REVISION), so a spec shows up once per matching revision group with all its revision links. Notices shown above the form: * all criteria are combined with AND; * search is restricted to the selected test project. ## Search criteria | Criterion | Behavior | |-----------|----------| | Doc ID | `LIKE '%value%'` on `req_specs_revisions.doc_id`; offered only when the project has req specs containing requirements (`getOptionReqSpec(GET_NOT_EMPTY_REQSPEC)`, legacy rule) | | Title | `LIKE` on spec name (`nodes_hierarchy.name`) | | Type | exact match on revision type; domain localized server-side (`req_spec_cfg.type_labels`): Section / User Req Spec / System Req Spec + "Any" | | Scope | `LIKE` on `req_specs_revisions.scope` | | Log message | `LIKE` on `req_specs_revisions.log_message` | | Custom field + value | design-time custom fields linked to **requirement_spec**; values joined on the revision node id (`cfield_design_values.node_id = RSPECREV.id`), `LIKE` semantics | Result cap: if more than `req_cfg.search.max_qty_for_display` (200) specs match, results are not displayed and the legacy warning "Too many results" is returned instead. ## Results ![Search results](search-reqspec-results.png) DataTable with columns: * **Path** — full tree path of the spec (empty for root-level specs); * **Requirement Specification** — edit icon + `DOCID:Title`; opens the modern viewer popup `gui/templates/requirements/reqSpecView.html?id=…` (was `reqSpecView.php?req_spec_id=…`, Refs #755); * **Revisions** — one link per matching revision (`rev. N`, newest first), each opening `reqSpecViewRevision.php?item_id=` in a popup (still legacy — next piece of #755). Header line shows the match count ("Matches: N"). ## Empty state / warnings ![No results](search-reqspec-noresults.png) * no matches → red warning box + centered empty-state panel ("No requirement specifications match the given criteria."); * too many matches → legacy `too_wide_search_criteria` warning instead of rows. ## i18n All labels, placeholders and messages use the client-side `TLi18n` module with the `reqspecsearch.*` key namespace, present in **all 10 locale bundles** (en, ro, de, es, fr, it, ja, pt, ru, zh). The type domain is localized server-side like the legacy form. ![Romanian locale](search-reqspec-ro.png) ## Permissions * Menu entry rendered only for users with `mgt_view_req` on the project. * Both BFF routes re-check `mgt_view_req` server-side → HTTP 403 + error toast when missing (verified with a no-rights user). * Search is always scoped to the session/current test project. ## Implementation notes * BFF mirrors `reqSpecSearch.php` SQL 1:1 (joins on `req_specs` / `req_specs_revisions` / `nodes_hierarchy`, cumulative grouping by spec id, path via `tree_manager->get_full_path_verbose(path_as_string)`). * Deep-link prefill: every criterion can be seeded via URL params (`doc_id`, `name`, `reqSpecType`, `scope`, `log_message`, `custom_field_id`, `custom_field_value`). ## Test coverage Suite 43 in `tmp/TLU_Test_Cases.md` (15 cases) covers: criteria matrix, revision-level matching, AND combinations, LIKE partials, reset, deep links, locale switching, permission paths and Event Viewer cleanliness. ## Generated-on results footer (Issue #1081) Legacy closed every result set with the italic "how to read this list" hint plus a **"Generated by TestLink on ``"** stamp, both rendered only when the search produced **no** warning (`gui/templates/dashio/requirements/reqSpecSearchResults.tpl:22-33`): ```smarty

{lang_get s='info_search_req_spec'}

{lang_get s='generated_by_TestLink_on'} {$smarty.now|date_format:$gsmarty_timestamp_format} ``` The stamp used `$gsmarty_timestamp_format`, i.e. `$tlCfg->locales_timestamp_format[$session locale]` (`lib/functions/tlsmarty.inc.php:304`) — the **logged-in user's** language format, not the browser locale. The modern screen had dropped the whole block (only the match count remained). * **BFF** `GET /reqspec-search` now returns `generated_on` (already localized: `tlStrftime($tsFormat, time())`, format taken from `config_get('locales_timestamp_format')[$_SESSION['locale']]` with a `default_language` fallback) and `generated_on_iso` (tooltip). * **Screen** renders them in a dedicated `#footerGenerated` block after every `renderResults()`; the block is **hidden** for the `no_records_found` and `too_wide_search_criteria` warnings, exactly like the legacy `{if !isset($gui->warning_msg)}` guard. `doSearch()` hides it and `resetForm()` clears it, so a stamp never outlives its result set. * `#footerInfo` keeps `Matches: N`. * **i18n:** new `reqspecsearch.infoSearch` key in all 10 bundles (legacy `$TLS_info_search_req_spec` texts, `\n`-separated paragraphs rendered as `
`, escaped); the label reuses the already translated `common.generatedBy`. ![generated-on footer](issue-1081-searchreqspec-generatedon.png) Test suite: *Task — Issue #1081* in `tmp/TLU_Test_Cases.md` (8 cases, all PASS: BFF payload, normal search, no-records, too-wide 205 > cap 200, Reset, German locale, stamp refresh, console/Event Viewer clean).