Issue 427 Baselines L1L2 NoBaseline EWarning Fix - sebiboga/testlink-upgraded GitHub Wiki
Issue 427 β Baselines L1 & L2 report: null $rsu loop guard (no-baseline E_WARNING)
Issue: https://github.com/sebiboga/testlink-upgraded/issues/427 Related: #424 (earlier mitigation on this file), #639 (L18N notices in this screen's XLS export β separate bug)
Symptom
Opening Reports and Metrics β Baselines Level 1 & Level 2 Test Suites for any
test plan that has never had a baseline saved wrote an E_WARNING into the
events table on every render:
E_WARNING
foreach() argument must be of type array|object, null given - in lib/results/baselinel1l2.php - Line 95
The original issue body reported a worse variant β a fatal
Cannot use object of type stdClass as array at compiled-template line 140
($gui->statistics[$platId]) β plus a second defect where
$gui->statistics = array() inside the platform loop reset the accumulator
so only the last platform survived. Both of those were already mitigated by run
#424 (initialization hoisted above the loop), which is why post-#424 renders
returned HTTP 200. What remained was the unguarded loop over a null row map.
Approach
Root cause chain:
lib/functions/database.class.php:981βfetchRowsIntoMap4l()starts with$items = nulland only materializes the array inside its row loop; an empty result set returns null (:1004).lib/results/baselinel1l2.php:80assigns that null to$rsuwhenever the plan has zero rows inbaseline_l1l2_contextΓbaseline_l1l2_details.lib/results/baselinel1l2.php:95iterates$rsuunconditionally β PHP 8 E_WARNING, logged per render.
Fix (minimal, single call site):
$rsu = $db->fetchRowsIntoMap4l($sql,$keyCols,true);
// fetchRowsIntoMap4l() returns NULL when the plan has no saved baseline
// yet; iterating null raised "E_WARNING foreach() argument must be of
// type array|object, null given" on every no-baseline render. (#427)
if( is_null($rsu) ) {
$rsu = array();
}
Alternatives rejected:
- Changing
database.class.phpreturn contract (null β array) β ~10 call sites share that fetcher; a contract change could ripple into unrelated reports. - Wrapping the
foreachinis_array()instead β equivalent behavior but the normalization reads cleaner next to the hoisted init from #424.
Commit: 6504fc15b (fix(results): guard baselinel1l2 loop against null $rsu β¦, branch fix/issue-427).
Verification (regression matrix, run 2026-08-23)
Fixtures: php tmp/fixtures_427.php β project RPT427 / plan Plan427A (id 6,
no platforms, no baseline); php tmp/fixtures_427b.php β project RPT427B /
plans Plan427B (id 10, platforms P-ONE + P-TWO, baselines on both) and
Plan427C (id 11, platform P-ONE only, baseline). Baseline rows carry passed=7 /
not_run=3 of total 10 per topβchild pair.
| Case | Request | Result |
|---|---|---|
| R1 no baseline | baselinel1l2.php?tplan_id=6&tproject_id=1&format=0 |
HTTP 200 header-only report; 0 new Error/Warning events (pre-fix produced E_WARNING events id 3) |
| R2 two platforms | tplan_id=10&β¦&format=0 |
HTTP 200; BOTH Results on Platform: P-ONE and P-TWO metric tables render with 70%/30% percentages β accumulator intact across loop iterations |
| R3 single platform | tplan_id=11&β¦&format=0 |
HTTP 200; single P-ONE section |
| R4 XLS export | tplan_id=6&β¦&format=1&spreadsheet=1 |
HTTP 200 valid .xls download; no fatal on the touched path |
Event Viewer after the suite: zero new Error/Warning rows. The export path did
surface two pre-existing L18N-level (log_level 32) notices
(priority_level, not_run not localized for en_GB) β logged separately as #639,
deliberately not fixed in this scope.
Full suite: Suite 427 in tmp/TLU_Test_Cases.md (5/5 PASS).
