Skip to content

refactor(characters): consolidate downloadPdf onto DocuDeskPdfRenderer, closing gate-49 - #267

Merged
rubenvdlinde merged 2 commits into
developmentfrom
fix/consolidate-pdf-renderer
Aug 5, 2026
Merged

refactor(characters): consolidate downloadPdf onto DocuDeskPdfRenderer, closing gate-49#267
rubenvdlinde merged 2 commits into
developmentfrom
fix/consolidate-pdf-renderer

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

What

CharactersController failed hydra gate-49 (controller-exception-translation). This closes it by first removing responsibility from the controller, then adding the exception import the gate wants.

Why the obvious fix was rejected

Adding use OCP\AppFramework\Db\DoesNotExistException; on its own is a net regression, and an FQCN is no escape because MissingImport is enabled in this repo's ruleset. Measured, not assumed (PHP 8.4.22 / PHPMD 2.15.0):

shipped PHPMD findings CouplingBetweenObjects
development 0 12
import alone 1 13

The actual fix

DocuDeskPdfRenderer already existed, and its own docblock already claimed both the character-sheet and the event run-sheet export as callers — but downloadPdf() never used it and re-implemented the entire pipeline inline (dependency check, UUID validation, template lookup, render, error logging).

Routing downloadPdf() through the renderer — exactly as EventsController::downloadRunsheet() already does — drops IAppManager, ContainerInterface and LoggerInterface from the controller. That buys back the coupling budget the exception import needs.

Before / after

before after
shipped PHPMD findings 0 0
CouplingBetweenObjects 12 11 (down)
gate-49 FAIL (2 methods) PASS
unit tests 153 / 541 173 / 577

Both downloadPdf() and requirementReport() were flagged; both are fixed. Of the 63 gate verdicts, exactly one changed (gate-49 FAIL→PASS); the other 5 failures are pre-existing and untouched.

Behaviour preservation

The existing downloadPdf tests were kept driving a real DocuDeskPdfRenderer built from the same IAppManager/ContainerInterface/Logger mocks the controller used to hold — not a mock of the renderer. They therefore still exercise the identical end-to-end pipeline and act as a behaviour-preservation check rather than an assertion about the new internal shape.

Adds the first tests for DocuDeskPdfRenderer, which had none despite already serving EventsController, and pins the details this refactor could have silently changed: the template body, render context and page options handed to DocuDesk, the derived download filename, and template-id lower-casing.

Fail-proof

A passing test is evidence about the test until it has been shown it can fail. Each mutation applied to the renderer, then reverted:

mutation tests killed
isDocuDeskAvailable()true 3 (incl. controller 424)
normaliseTemplateId() → passthrough 8 (incl. controller 400)
render error → '' instead of null 2 (incl. controller 500)

The PHPMD rig itself was positive-controlled before the first measurement with a deliberate 3-violation probe, which it reported exactly.

Reported honestly: the two new DoesNotExistException → 404 tests pass with or without the specific catch clause, because the pre-existing catch (\Exception) already caught it. They pin the 404 translation behaviour but do not discriminate the gate-49 fix — gate-49 itself is the verifier for that.

Not done

  • psalm cannot run locallypsalm.xml references a stub at vendor/nextcloud/ocp/OCP.bak/… that does not exist after a fresh composer install. Verified pre-existing: it fails identically on the pristine tree. Not touched, because editing the stub config to make the check pass would weaken it.

No @SuppressWarnings, baseline, threshold change, .skip, waiver, continue-on-error or weakened assertion was added. larpingapp still has no phpmd.baseline.xml.

…r, closing gate-49

CharactersController failed hydra gate-49 (controller-exception-translation)
on both downloadPdf() and requirementReport(): each calls
RegisterObjectFetcher::getObject() but caught only \Exception, so an
OpenRegister DoesNotExistException was never translated explicitly.

The obvious fix -- importing DoesNotExistException -- is a net regression on
its own. Measured on PHP 8.4.22 / PHPMD 2.15.0:

  import alone:  CouplingBetweenObjects 12 -> 13, shipped findings 0 -> 1

DocuDeskPdfRenderer already existed and its docblock already claimed both the
character-sheet and the event run-sheet export as callers -- but downloadPdf()
never actually used it and re-implemented the whole pipeline inline. Routing
downloadPdf() through the renderer (as EventsController::downloadRunsheet
already does) drops IAppManager, ContainerInterface and LoggerInterface from
the controller, which buys back the budget the exception import needs.

  before:  CBO 12, shipped PHPMD findings 0, gate-49 FAIL (2 methods)
  after:   CBO 11, shipped PHPMD findings 0, gate-49 PASS

No behaviour change. The existing downloadPdf tests were kept driving a REAL
DocuDeskPdfRenderer built from the same IAppManager/Container/Logger mocks the
controller used to hold, so they still exercise the identical end-to-end
pipeline and act as a behaviour-preservation check rather than an assertion
about the new internal shape.

Tests: 153/541 -> 173/577, all passing. Adds the first tests for
DocuDeskPdfRenderer, which had none despite already serving EventsController,
and pins the details this refactor could have silently changed: the template
body, render context and page options handed to DocuDesk, the derived
download filename, and template-id lower-casing.

Fail-proof (mutation testing, each reverted):
  isDocuDeskAvailable -> true            kills 3 tests (incl. controller 424)
  normaliseTemplateId -> passthrough     kills 8 tests (incl. controller 400)
  render error -> '' instead of null     kills 2 tests (incl. controller 500)

No suppressions, baselines, thresholds or waivers were added or changed.
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/larpingapp @ 441ca17

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-specs
test-l10n
composer ✅ 101/101
npm ✅ 537/537
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-05 18:04 UTC

Download the full PDF report from the workflow artifacts.

… this change touches

gate-28 (license-triangle) is diff-scoped, so editing CharactersController
pulled a pre-existing header drift into scope: the file declared AGPL-3.0
while composer.json declares EUPL-1.2. Fixed properly rather than waived, on
the two files this change touches plus the new test.

DashboardController, DeepLinkRegistrationListener and LarpingAppAdmin carry
the same pre-existing drift but are outside this diff and are already covered
by chore/eupl-license-normalisation-2026-08-05; left alone to avoid conflicting
with that branch.
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/larpingapp @ c2a2c34

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-specs
test-l10n
composer ✅ 101/101
npm ✅ 537/537
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-05 18:47 UTC

Download the full PDF report from the workflow artifacts.

@rubenvdlinde
rubenvdlinde merged commit c218318 into development Aug 5, 2026
33 of 36 checks passed
@rubenvdlinde
rubenvdlinde deleted the fix/consolidate-pdf-renderer branch August 5, 2026 19:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant