Search Requirement Specifications - sebiboga/testlink-upgraded GitHub Wiki
Path: ASIDE menu > Requirements > Search Requirement Specifications
URL: gui/templates/requirements/searchReqSpec.html?tproject_id=<id>&tplan_id=<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.
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 itsno_records_foundstate without any PHP-8TypeError. See Bugfix Issue #1735.

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.
| 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.

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 popupgui/templates/requirements/reqSpecView.html?id=…(wasreqSpecView.php?req_spec_id=…, Refs #755); -
Revisions — one link per matching revision (
rev. N, newest first), each openingreqSpecViewRevision.php?item_id=<revision_id>in a popup (still legacy — next piece of #755).
Header line shows the match count ("Matches: N").

- no matches → red warning box + centered empty-state panel ("No requirement specifications match the given criteria.");
- too many matches → legacy
too_wide_search_criteriawarning instead of rows.
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.

- Menu entry rendered only for users with
mgt_view_reqon the project. - Both BFF routes re-check
mgt_view_reqserver-side → HTTP 403 + error toast when missing (verified with a no-rights user). - Search is always scoped to the session/current test project.
- BFF mirrors
reqSpecSearch.phpSQL 1:1 (joins onreq_specs/req_specs_revisions/nodes_hierarchy, cumulative grouping by spec id, path viatree_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).
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.
Legacy closed every result set with the italic "how to read this list" hint
plus a "Generated by TestLink on <date>" stamp, both rendered only when the
search produced no warning
(gui/templates/dashio/requirements/reqSpecSearchResults.tpl:22-33):
<p class="italic">{lang_get s='info_search_req_spec'}</p>
{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-searchnow returnsgenerated_on(already localized:tlStrftime($tsFormat, time()), format taken fromconfig_get('locales_timestamp_format')[$_SESSION['locale']]with adefault_languagefallback) andgenerated_on_iso(tooltip). -
Screen renders them in a dedicated
#footerGeneratedblock after everyrenderResults(); the block is hidden for theno_records_foundandtoo_wide_search_criteriawarnings, exactly like the legacy{if !isset($gui->warning_msg)}guard.doSearch()hides it andresetForm()clears it, so a stamp never outlives its result set. -
#footerInfokeepsMatches: N. -
i18n: new
reqspecsearch.infoSearchkey in all 10 bundles (legacy$TLS_info_search_req_spectexts,\n-separated paragraphs rendered as<br>, escaped); the label reuses the already translatedcommon.generatedBy.

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).