Repository navigation
Bugfix Issue 1415 buildCfields EWarning
Bugfix — Issue #1415: print.inc.php — E_WARNING Undefined variable $buildCfields on every report render with unexecuted TCs on a build
Generating a Test Plan Execution report on a build
(printDocument.php?type=testreport_onbuild → DOC_TEST_PLAN_EXECUTION_ON_BUILD)
raises one E_WARNING "Undefined variable $buildCfields" per linked Test Case
that has NO execution row on the selected build. Each warning is logged as an
event (log_level=2, source 'GUI - Test Project ID : 1') in the events table,
polluting the Event Viewer used for CI integration checks.
Reproduced at HEAD (fresh-import CI box, PHP 8.x, MySQL), both on the legacy apikey path and the logged-in session path:
E_WARNING\nUndefined variable $buildCfields - in .../lib/functions/print.inc.php - Line 1595
Verified 2026-09-11 on fixture data (plan with 3 TCs, 2 builds, an execution on build 2 for 1 TC only): exactly 2 new events per render (one per unexecuted-on- build-2 TC). Document output is unaffected because the undefined variable short-circuits its own guard.

Chain (each hop backed by file:line):
-
lib/functions/print.inc.php:922—renderTestCaseForPrinting(&$db,&$node,&$options,$env,$context,$indentLevel)never declares$buildCfields; a grep of the function confirms the single bare reference is line 1595. -
print.inc.php:1067-1071— build custom fields are fetched onto the static tree object:$st->buildCfields[$tbuild_id] = $st->build_mgr->html_table_of_custom_field_values(...), gated on thebuild_cfieldsprint option and only when$exec_infois not null. -
print.inc.php:1594-1602— for a TC with no execution on the selected build (is_null($exec_info)) the build-name block runs its build-CF row; its outer guard!is_null($buildCfields)(line 1595) reads the undefined variable → PHP8 E_WARNING → event row. The row body already used the real source,$st->buildCfields[$build_id]. - Git history pinpoints the regression source:
-
25619cd009(2016) usedstatic $buildCfields;populated per build id inside the same function. -
90c461a54("#0008556 DB Access Error", 2019) refactored the storage to$st->buildCfields, migrating the write, the row body andbuildTestExecResults()— but forgot the guard on the then-old line 1563. From that commit on,$buildCfieldsis a leftover name: the variable is undefined, and the whole CF row is dead code.
-
Why it breaks now: PHP 8.x surfaces the 2019 refactor leftover as an
E_WARNING on every affected render. Not a modernization regression; the legacy
printDocument.php path reproduces it identically.
Blast radius: grep buildCfields in lib/functions/print.inc.php →
7 hits; only the guard under review used the bare variable; the other 6
already use $st->buildCfields (lines 1068, 1069, 1595, 1596, 1599, 1629)
plus an unrelated $things->buildCfields (2355). No other file references it.
Single-line blast radius.
Committed on branch fix/issue-1415, commit e9fa9f0e9:
if(is_null($exec_info)) {
if(isset($st->buildCfields[$build_id]) &&
$st->buildCfields[$build_id] != '') {
$code .= '<tr><td width="' . $cfg['firstColWidth'] .
'" valign="top"></td>' . '<td colspan="' . $tsp . '">' .
$st->buildCfields[$build_id] . "</td></tr>\n";
}
}The stale !is_null($buildCfields) clause is deleted. The remaining
isset($st->buildCfields[$build_id]) provides the same "CF data already
fetched for this build" semantics the original static-null check was meant to
express, against the real data source. The row renders its build-CF table when
data exists — the behaviour the 2019 refactor intended but had accidentally
dead-branched.
Why this method: the guard should read exactly what the row body reads.
isset() is null-safe and covers "initialised" — an extra is_null($st->buildCfields)
adds nothing.
Rejected alternatives: (a) $buildCfields = null; initializer — silences
the warning but keeps the CF row permanently dead, losing intended output;
(b) switching the whole guard to $st->buildCfields with an added null check —
redundant given isset().
-
lib/functions/print.inc.php— line 1595: removed the undefined!is_null($buildCfields)clause from the build-CF guard (-2/+1). -
tmp/TLU_Test_Cases.md— regression suite "Regression — Issue #1415", 7/7 PASS. -
tmp/fixtures_1415.php— fixture (1 project, plan with 3 linked TCs on platform 1, 2 builds, execution on build 2 for the 3rd TC only).
All checks on branch fix/issue-1415, PHP 8.x, MySQL fresh-import schema:
- Pre-fix control (file reverted to HEAD): session render of the affected URL
→ HTTP 200 + 2 new
E_WARNING ... Line 1595events. - Post-fix R1 (build_id=2, allOptionsOn=1): HTTP 200, 0 new events.
- Post-fix R2 (build_id=1, no executions at all): HTTP 200, 0 new events.
- Post-fix R3 (build_id=2, print options off): HTTP 200, 0 new events.
- Post-fix R4 (anonymous/apikey path): HTTP 200, 0
buildCfieldsevents. - Post-fix R5 (positive path): a build custom field seeded
(
cf_build_1415, valueBUILDCF-MARKER-VALUE) renders its row in the document exactly once for the executed TC viabuildTestExecResults()— the restoredisset()branch is now live for no-execution TCs when the static has been populated by an earlier executed TC in the same render. - Post-fix R6 (restored branch proof): with the executed TC (tcversion 10)
reordered to render FIRST,
BUILDCF-MARKER-VALUEappears 3x in the HTML — once per TC under its "Build: Build1415-2" line, i.e. the line-1595 row now renders for the two no-execution TCs (isset()true from the earlier executed TC). Pre-fix those rows were impossible (guard always false:is_null(undefined)→true⇒!is_null(...)→false). -
php -l lib/functions/print.inc.phpclean. - Events table after all fixed-path renders: 0 rows matching
%buildCfields%.
Regression suite: tmp/TLU_Test_Cases.md — "Regression — Issue #1415", 7/7 PASS.
While testing, the anonymous/apikey direct access to printDocument.php also
emits 3 E_WARNING "Undefined array key basehref" events
(printDocument.php:175/254, print.inc.php:700) because $_SESSION['basehref']
is unset without a session. Pre-existing (reproduced identically against the
pre-fix file), filed separately as a bug issue.
Address: Fixes #1415 (verified + pushed on fix/issue-1415).