Reviewed Rector batch (3 files) + a manual decomposition of massEdit on top.
Rector batch (reviewed against suite + PHPStan):
- FIX (recurring Rector bug): the boolean inversion again dropped the parens on
an assignment-in-condition in massEdit (array_search category DEL) — restored.
- massEdit: many correct empty-if/else -> guard inversions (verified).
- strlen(x) > 0 -> x !== '' in saveStreamOptions, TMDbService::buildUrl and
ResellerTableRenderer (behaviour-preserving).
massEdit decomposition (166 -> 96 lines, nesting ~10 -> 7), test-first:
- computeCategoryChange() — ADD union / DEL remove / SET replace (pure)
- planBouquetChanges() — SET/ADD/DEL bouquet attach/detach plan (pure)
- planServerTreeForStream()— per-stream streams_servers reconcile (update in
place / batch-insert buffer / delete marking)
- raiseTimeLimits() — the set_time_limit + ini_set block, shared with
massDelete (de-duplicated)
Tests: RadioServiceTest gains computeCategoryChange (5) + planBouquetChanges (3);
new RadioServiceMassEditTest characterizes massEdit end to end (invalid input,
and the server-tree ADD path) — it has no verifyPostTable/exit and
StreamProcess::updateStreams is a no-op with caching off, so the whole method
runs against the SQLite harness. That test guarded the server_tree extraction.
PHPStan level 5 clean; suite 721 tests / 0 errors.