Skip to content

feat: Migrate to Vue Router and refactor views to @conduction/nextcloud-vue - #1

Merged
rubenvdlinde merged 19 commits into
mainfrom
feature/documentation
Mar 3, 2026
Merged

feat: Migrate to Vue Router and refactor views to @conduction/nextcloud-vue#1
rubenvdlinde merged 19 commits into
mainfrom
feature/documentation

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

Summary

  • Replace manual currentView/currentRoute navigation with Vue Router (src/router/)
  • App.vue now renders <router-view /> and mounts CnIndexSidebar globally
  • Refactor CaseList and TaskList to use CnIndexPage with schema-driven columns and built-in CRUD dialogs
  • Update procest_register.json schema bindings
  • Bump composer dependencies

Test plan

  • Navigate between dashboard, cases, tasks, and settings — all routes resolve correctly
  • Create, edit, and delete cases from CaseList
  • Create, edit, and delete tasks from TaskList
  • CnIndexSidebar opens and filters results correctly
  • MyWork and CaseDetail views still load without errors

🤖 Generated with Claude Code

rubenvdlinde and others added 19 commits February 26, 2026 07:55
Replace existing license (Apache-2.0/AGPL) with EUPL-1.2 across all
metadata files: LICENSE, appinfo/info.xml, composer.json, package.json.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…orkflow

Add Conduction coding standard with custom sniffs, PHPMD mess detection,
ESLint with Nextcloud config, and stylelint. Add GitHub Actions workflow
for PR quality checks.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add project architecture docs, feature specs, and OpenSpec change
tracking for structured development workflow.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Apply Conduction PHPCS standard. Add deep link registration listener,
register configuration, and admin settings infrastructure.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add dashboard widgets, My Work view, case create dialog, case detail
components, task management views, and admin settings with case type
configuration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Only allow PRs from 'development' or 'hotfix/*' branches to merge into
main. Other source branches will be blocked by a required status check.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Enforce branching strategy: main only from beta, beta only from
development, development only from feature/*. Hotfix/* bypasses all
restrictions. Add beta to quality check triggers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document the promotion-based branching model (feature→development→beta→main),
hotfix policy, required quality checks, and local development workflow
with a mermaid flow diagram.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds NcAppSettingsDialog-based user settings accessible from sidebar
Configuration menu. Consolidates UserPreferencesController into
SettingsController. Backend uses OCP\IConfig for per-user storage.
Updates register schema JSON and repair step.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New modal dialog for creating tasks from list view. Dashboard KPI card
hover fixes. Case and task list views updated with consistent filtering.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…rary

AdminRoot uses CnSettingsSection for Case Type Management section.
Settings wraps form in CnSettingsSection with doc-url and loading state.
Webpack dedup aliases use $ suffix for exact-match.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…webpack alias

Makes the shared library work in both monorepo dev (local source alias)
and CI/production builds (npm package from git). The alias only activates
when ../nextcloud-vue/src exists.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replaces github:ConductionNL/nextcloud-vue#main with ^0.1.0-beta.1
from npm registry. Faster installs, no git clone + build step.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Nextcloud App Store schema does not accept EUPL-1.2 as a valid
licence value, causing all release uploads to fail with HTTP 400.
Revert to 'agpl' which is in the accepted set.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add vimeo/psalm ^5.26 + psalm.xml config
- Add phpstan/phpstan ^1.10 + phpstan.neon config
- Add nextcloud/coding-standard, phpcsstandards/phpcsextra
- Add roave/security-advisories, edgedesign/phpqa
- Add psalm, phpstan, phpmetrics:violations, phpcs:output, phpqa scripts
- Fix phpmetrics:violations flag to --violations-xml (matching OpenRegister)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…e coverage

Replaces the one-liner README with a comprehensive document covering:
- Logo and CI badges header
- Screenshots table (dashboard, cases, admin)
- Detailed feature sections organized by category
- Mermaid architecture diagram
- Data model table with CMMN 1.1 and ZGW API mappings
- Directory structure
- Requirements, installation, and development guide
- Tech stack and standards/compliance

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tcloud-vue

Replaces manual currentView/currentRoute navigation with vue-router.
App.vue now renders <router-view /> and mounts CnIndexSidebar globally.
CaseList and TaskList are refactored to use CnIndexPage with schema-
driven columns and built-in CRUD dialogs. Adds src/router/ for route
definitions. Updates procest_register.json schema and bumps dependencies.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@rubenvdlinde
rubenvdlinde merged commit e032eee into main Mar 3, 2026
1 of 3 checks passed
rubenvdlinde added a commit that referenced this pull request Mar 22, 2026
…rements)

Evidence-backed proposals from 39,600 tenders across 8 EU countries:
1. workflow-engine-enhancement (534 tenders) — foundational, prerequisites for 2-4
2. vth-workflow-configuration (436 tenders) — VTH domain config, depends on #1
3. bezwaar-beroep-workflow (280 tenders) — AWB-compliant, depends on #1
4. besluitvorming-workflow (126 tenders) — decision process, depends on #1
5. signalering-widgets (160 tenders) — dashboard alerts
6. doorlooptijd-dashboard (350 tenders) — SLA analytics
7. deelzaak-support (245 tenders) — sub-case hierarchy
8. gis-integration (300 tenders) — map views, PDOK, WMS/WFS
rubenvdlinde added a commit that referenced this pull request Aug 11, 2026
)

`DsoIntakeService` carried two implementations of DSO intake. The live
webhook path (`processAanvraag`, POST /api/vth/dso/intake) did the
extract → build → save → save-properties inline, while an extracted
`map()` + `createCase()` pair sat next to it with zero callers — an
abandoned "make intake testable" refactor.

`createCase()` was not merely unreachable, it had never run. It called
OpenRegister's ObjectService positionally:

    saveObject($register, $caseSchema, $caseData)

against the real signature

    saveObject(array|ObjectEntity $object, ?array $extend = [], $register = null, $schema = null, ...)

so the schema slug landed in `?array $extend` and the register slug in
`array|ObjectEntity $object` — a TypeError on the first call. The same
bug was in its case-property loop.

This wires the orphan instead of deleting it:

- `processAanvraag()` now delegates to `map()` + `createCase()`, so there
  is ONE implementation of the intake write rather than two.
- `createCase()` passes register/schema by NAME, fixing the latent
  TypeError, and reuses the existing `storeCaseProperties()` helper
  (which already had the argument order right) for the property rows.
- `createCase()` adopts the live path's log line, so the message the
  webhook has always emitted is preserved.

Characterization tests were written FIRST, against the pre-refactor code,
and pin the observable behaviour of the live path: the exact saveObject
call sequence including which parameter each named argument binds to, the
case-property rows written vs skipped, and the byte shape of the JSON the
Omgevingsloket receives back. They passed before the refactor and pass
after it, unedited.

The ObjectService test double declares OpenRegister's real parameter
order, so the argument-order assertions are not vacuous: reverting to the
positional call makes 12 of the 15 tests fail with
"saveObject(): Argument #1 ($object) must be of type array, string given".

Verification (hydra-gates @ ConductionNL/.github b8c7ead, 66 gates):
- gate-57 orphaned-write-capability: 16 → 15; the only removed finding is
  DsoIntakeService::createCase.
- gate-25 contract-coverage: 126 → 126, findings log byte-identical.
- Failing-gate ID set identical before and after — no new gate fails.
- composer phpstan: no errors.
- composer phpcs: 1 error + 501 warnings in 219 files, identical to
  origin/development; the changed file carries the same 2 warnings.
- vendor/bin/phpunit: 1761 tests green (1746 baseline + 15 new), 5 skipped.

Behaviour note: on a MALFORMED payload with OpenRegister unavailable, the
mapping now runs before the config guards, so such a request surfaces the
mapping error rather than "OpenRegister is not available". Both are a 500
from the webhook and neither message is part of the response contract.
rubenvdlinde added a commit that referenced this pull request Aug 15, 2026
…ferent class"

The reconcile pass removed VALID arguments. PHPUnit, after it:

    Error: DsoObjectRepository::__construct(): Argument #1 ($settingsService) not passed
    Error: ZgwRulesBase::__construct(): Argument #1 ($logger) not passed
    Error: Too few arguments to ProcestCaseReader::__construct(), 0 passed

It was written to fix ONE real problem — two classes sharing a file stem, where
`new ChecklistService()` was given three arguments belonging to
lib/Service/Inspection/ChecklistService.php. That problem is real and is fixed
by hand in the next commit.

The pass itself judged every construction in the file, and where its constructor
parse came back empty it treated every named argument as unknown and deleted it.
A tool that removes code needs to be certain, not merely unable to confirm;
reverting is cheaper than making it certain, since exactly one call site
actually needed changing.
rubenvdlinde added a commit that referenced this pull request Aug 15, 2026
…#847)

* refactor(deps): inject OpenRegister instead of looking it up (ADR-083)

2 file(s) reached OpenRegister through $this->container->get(...) on an
UNCONDITIONAL path — no availability check, no degrading catch. The
dependency was announced nowhere: not in the constructor, not in the use
block, not in any type. It appeared mid-method, as a string.

Now constructor-injected and typed, so the dependency is visible to a
reader and to tooling. Behaviour is unchanged: the same object, from the
same container, resolved at construction instead of at first use.

ContainerInterface is dropped only where nothing else used it.

Deliberately NOT converted, because they are correct as written (ADR-083
rule 1's exception): lookups behind isInstalled()/getInstalledApps(), and
lookups whose catch degrades rather than rethrows.

Verified per file: php -l clean, and gate-66's lookup check reports zero
remaining findings for each file changed.

gate-66 for this app: 3 -> 1.

* style: put the injected parameter on its own line

The transformer appended the new promoted parameter AFTER the
whitespace-only line preceding the closing paren, producing

    private readonly ObjectService $objectService,) {

php -l accepts that; phpcs does not, and it reads badly. Fixed here and in
the transformer, which now backs up over trailing whitespace before
inserting when the constructor has no defaulted parameters to sit in front
of.

No behavioural change — parameter list is identical.

* refactor(deps): type-hint OpenRegister's published contract (ADR-084)

Five services take OCA\OpenRegister\Contract\ObjectServiceInterface instead of
the concrete class, bound in the composition root, with hydra-gates bumped to
v1.8.0 so composer installs the interface into vendor/.

This is what makes the ADR-083 conversion mockable. A leaf app cannot load a
class from another Nextcloud app, so a typed constructor parameter had no
satisfiable double:

    TypeError: __construct(): Argument #N ($objectService) must be of type
    OCA\OpenRegister\Service\ObjectService, class@anonymous given

The 199 files that name ObjectService only as a CONTAINER KEY are untouched.
Those are availability-guarded lookups — the ADR-083 rule-1 exception — and the
string must go on naming the concrete service, because that is the key the
alias resolves TO. Rewriting it would have made the container look up something
nobody registered.

Two of these five files were nearly missed. The first transformer masked string
literals with a regex, and in DsoCaseService the comment `// King's Day.` opened
a string that did not close until `date('N')` 240 lines later — so every type
position between them looked like it was inside a string and the file was
silently skipped. A skipped file is indistinguishable from a clean one, which is
why it took a count to notice: 3 converted where 5 were due. The transformer now
takes its comment and string ranges from PHP's own token_get_all(), and reports
every file it declines to convert together with the reason.

* fix(adr-084): complete the conversion the first transformer under-did

The first pass through this app used a transformer with three defects, each of
which failed SILENTLY -- a skipped file is indistinguishable from a clean one.

1. It masked string literals with a REGEX. An apostrophe in a comment
   (`// King's Day.`) opened a string that did not close for 240 lines, so
   every type position between them looked quoted and the file was skipped.
   Now the comment and string ranges come from PHP's own token_get_all().

2. It compared PHP's BYTE offsets against Python's CHARACTER indices. One file
   differed by 94 -- em dashes in prose comments -- so spans after the first
   non-ASCII byte were misaligned and a docblock was judged "not in a comment".
   Everything is handled as bytes now.

3. It missed short-form RETURN types (`): ?ObjectService`), which neither the
   parameter nor the fully-qualified pattern matched.

And it dropped the concrete import even where `ObjectService::class` or
`instanceof ObjectService` still needed it. That one is not merely incomplete,
it is silent damage: `::class` does not require the class to exist, so the
lookup would have resolved to this app's own namespace.

An invariant check now enforces the rule -- a file may import the contract, or
both, but never the contract alone while still naming bare ObjectService -- and
reports 0 for every app in this rollout.

* test: construct the two services with the contract they now require

ADR-083 added a fifth constructor parameter and the tests still passed four:

    ArgumentCountError: Too few arguments to DsoCaseService::__construct(),
    4 passed and exactly 5 expected

Both sites use named arguments, so each is one line: an ObjectServiceInterface
mock. That clears 6 of the 8 PHPUnit errors on this branch.

NOT fixed here, deliberately.
testCreateZaakFromVergunningaanvraagCallsObjectService builds its double from a
LOCAL interface declared in this test file, DsoCaseObjectServiceStub, whose own
docblock describes exactly the problem ADR-084 solves -- a \stdClass mock
generates positional-only signatures and dies on "Unknown named parameter", so
somebody hand-rolled a typed interface to get named arguments working. It is an
eleventh double, and being an interface rather than a class it was missed by the
fleet count of ten.

Swapping it for the contract is not mechanical: it stubs find() to return an
ARRAY, while the contract returns ?ObjectEntityInterface. That is the same shape
as openbuild's stub failure, but the fix there was to make the stub satisfy the
contract; here the test is asserting on a raw array it never had to justify. It
needs a decision about what the test should actually assert, not a rushed
signature change.

* fix: saveObject() returns an entity, and two methods were returning it as array

The last PHPUnit error on this branch was not a test problem. It was the test
faithfully modelling a production defect.

`createZaakFromVergunningaanvraag(): array` did

    $created = $objectService->saveObject(...);
    return $created;

and `ObjectServiceInterface::saveObject()` returns an ObjectEntityInterface.
That worked only while the service was reached through an untyped container
lookup, which returned whatever it returned and told nobody. The test's local
stub returned raw arrays because that is what production expected.

Fixed on the production side, using the shape this app already had: a
saveObjectAsArray() helper next to findObjectAsArray(), same array-or-
jsonSerialize() normalisation, applied at the two sites that RETURN the result.
The third (syncPermitApplicationStatus) discards it and is unchanged.

The test now mocks the contract and returns what the contract promises —
entities whose jsonSerialize() carries the payload — and rebuilds the service
with that double, because the container path setUp() configured is dead now
that the dependency is injected.

DsoCaseObjectServiceStub is deleted. It was an ELEVENTH hand-rolled double, and
being an interface rather than a class it was missed by the fleet count of ten.
Its own docblock stated the problem ADR-084 exists to solve: "a \stdClass-based
mock generates positional-only signatures and fails at call time with Unknown
named parameter; this typed interface lets PHPUnit generate a mock whose method
signatures accept the named arguments". Someone hand-rolled a contract to make
mocking work. Now there is a published one.

* fix: the contract lives in Contract\, not Service\

phpstan caught a defect in the rollout transformer:

    PHPDoc tag @var for property $objectService with type
    OCA\OpenRegister\Service\ObjectServiceInterface is not subtype of native
    type OCA\OpenRegister\Contract\ObjectServiceInterface

The docblock rewrite matched `@var \OCA\OpenRegister\Service\ObjectService` and
appended `Interface` to the CLASS name while leaving the NAMESPACE alone, so the
declared type named a class that does not exist. The native type next to it was
correct, which is why only phpstan noticed — PHP itself never reads the docblock,
and the tests pass either way.

That is the fifth silent failure from this transformer, and the same shape as
the others: it produced plausible output that no runtime check disagreed with.

* ci: adopt development's Code Quality workflow — the branch had the pre-fix one

These branches were cut from ADR-083 branches predating the 2026-08-14
correction, so they carry an older code-quality.yml whose push trigger has no
refactor/** — which is this branch's prefix. development's version says why that
matters:

    An ALLOW-LIST of branch prefixes is a gate with a hole in it, and the hole
    is SILENT: a branch matching nothing gets no CI at all, and its last visible
    status is whatever it inherited — indistinguishable, on every dashboard,
    from a branch that passed.

Observed here: softwarecatalog#519 settled at FOUR checks (CodeQL and Analyze
only) and read as green, having previously reported 43. shillinq#556 did the
same at three, which is shillinq#557.

Takes merge-hygiene.yml with it, the companion added in the same change, which
runs the fast structural checks on ** so an unlisted prefix is not completely
unguarded.

This restores coverage via the PUSH path. It does not explain why the
pull_request runs stopped, which is tracked separately.

* test: seed the Samenwerkverzoek doubles from the contract, not a local stub

procest's PHPUnit went 8 errors -> 3 after the arity fix, and all three were the
same thing: "Zaak not found", "Samenwerkverzoek not found". A bare
createMock(ObjectServiceInterface::class) returns null from find(), so the
service correctly concluded the object did not exist.

The seeding was there — it just went to the wrong place. The tests configured a
SamenwerkObjectServiceStub mock and handed it over through the CONTAINER, and
the container path is dead now that the dependency is injected. So the service
was built with setUp()'s empty double while a fully-seeded one sat unused.

Two changes per test: mock the contract, and rebuild the service with that
double instead of relying on the container.

find() and saveObject() now return ENTITIES via a small entity() helper, because
that is what the contract promises and what the service normalises with
jsonSerialize(). The old stub returned bare arrays — which the untyped container
lookup allowed, and which is the same mis-shaped double this ADR keeps turning
up.

* test: complete the ADR-083 constructor changes and make the stubs satisfy the contract

Three distinct pre-existing defects, all of which only became visible once the
tests could actually construct their subjects.

1. ARITY, completely this time. The first pass added `objectService` only,
   because that is the parameter ADR-084 was about. ADR-083 added others in the
   same commit — softwarecatalog's ContactpersonenController gained THREE
   (objectService, magicMapper, organisationService) — so a call could be fixed
   for one and still be short by two. Every required parameter is now supplied,
   by NAME so it fills the right slot regardless of the existing arguments.

2. IMPORTS for the types those arguments name. `createMock(MagicMapper::class)`
   without a `use` resolves the short name against the TEST's own namespace, and
   `::class` does not require the class to exist — so it silently mocks a class
   nobody declared. Same trap as the container-key strings in lib/.

3. The ObjectEntity STUB now implements ObjectEntityInterface. Once
   ObjectServiceInterface is mocked its return types are enforced:

       Method find may not return value of type MockObject_ObjectEntity, its
       declared return type is "?OCA\OpenRegister\Contract\ObjectEntityInterface"

   A hand-rolled double that does not declare the interface cannot be handed
   back. This is ADR-084's argument arriving in the tests: ten apps had such a
   double, and none of them was checked against anything until now.

softwarecatalog also gains a MagicMapper stub, because ADR-083 injected
OpenRegister's MagicMapper into a controller and this app has no way to load it.
That stub is debt of exactly the kind ADR-084 removed for ObjectService — noted
in the file so it stays visible rather than becoming furniture.

php -l on every touched file, reverted on failure.

* refactor: drop the dead catch ADR-083 left behind

phpstan, on this branch:

    Dead catch - Throwable is never thrown in the try block.

getObjectService() used to resolve the service from the container, which could
fail, so it wrapped the call and rethrew a RuntimeException. ADR-083 made the
dependency injected, and the body became `return $this->objectService;` — a
property read, which throws nothing. The catch survived the conversion and was
unreachable.

Removing it is not a loss of safety: absence is now a CONSTRUCTION failure on
the route that needed the data, which is precisely what ADR-083 rule 1 asks for,
rather than a RuntimeException raised deep inside a call.

* fix(tests): remove constructor arguments that belong to a different class

The arity fixer keyed constructors by FILE STEM, and two classes with the same
stem in different namespaces collide. procest has

    lib/Service/ChecklistService.php             no constructor arguments
    lib/Service/Inspection/ChecklistService.php  three

so a correct `new ChecklistService()` was given three arguments belonging to the
other class:

    Error: Unknown named parameter $settingsService

Constructions are now resolved through the FILE'S OWN `use` imports to a
fully-qualified name before their arguments are judged.

The reconcile pass was itself wrong on its first run, in a way worth recording:
its parameter parser only accepted types beginning with a capital, so
`string $appName` on every Nextcloud controller was invisible and a valid
`appName:` argument looked like one the constructor did not have. It removed 33
files' worth of arguments in procest; with scalar types accepted it removes 8.
The tell was reading a diff that deleted `appName: 'procest'` — a line no
plausible fix would touch.

php -l on every touched file, reverted on failure.

* chore(phpmd): record why DsoCaseService is one collaborator over

ADR-083 replaced a lazy container lookup with a typed ObjectServiceInterface
dependency — the point of the ADR, since the dependency becomes visible to
readers and to tooling. That took the class to 13 collaborators, one over
phpmd's threshold.

The container cannot simply go: IGroupManager is still resolved through it.
Swapping one for the other would leave the count unchanged.

Suppressed with the reason attached rather than silently, and consistent with
this app's own convention — 29 classes here already carry it.

* fix: repair references to the local $objectService ADR-083 deleted

phpmd, on this branch:

    UndefinedVariable   $objectService

ADR-083 replaced

    $objectService = $this->container->get('OCA\OpenRegister\Service\ObjectService');

with an injected property and rewrote most usages to $this->objectService — but
not all. What remained read a local that no longer exists. In PHP that is not a
parse error and not a test failure unless the line executes; it is null at
runtime, and the call it feeds gets null instead of the service.

Rewritten only where the enclosing function has no assignment to that local AND
does not take it as a PARAMETER — several helpers legitimately receive it, e.g.
CreditLimitGuard::sumOutstandingCents(object $objectService, ...), and those are
untouched.

php -l on every touched file, reverted on failure.

* Revert "fix(tests): remove constructor arguments that belong to a different class"

The reconcile pass removed VALID arguments. PHPUnit, after it:

    Error: DsoObjectRepository::__construct(): Argument #1 ($settingsService) not passed
    Error: ZgwRulesBase::__construct(): Argument #1 ($logger) not passed
    Error: Too few arguments to ProcestCaseReader::__construct(), 0 passed

It was written to fix ONE real problem — two classes sharing a file stem, where
`new ChecklistService()` was given three arguments belonging to
lib/Service/Inspection/ChecklistService.php. That problem is real and is fixed
by hand in the next commit.

The pass itself judged every construction in the file, and where its constructor
parse came back empty it treated every named argument as unknown and deleted it.
A tool that removes code needs to be certain, not merely unable to confirm;
reverting is cheaper than making it certain, since exactly one call site
actually needed changing.

* fix(tests): ChecklistService takes no constructor arguments

OCA\Procest\Service\ChecklistService has an empty constructor. The three
arguments passed here belong to OCA\Procest\Service\Inspection\ChecklistService,
a different class with the same FILE NAME — which is what an earlier fixer keyed
constructors by, and how they arrived:

    Error: Unknown named parameter $settingsService

This is the one call site that genuinely needed changing; the sweep written to
find it removed valid arguments elsewhere and has been reverted.

* fix(tests): drop constructor arguments belonging to a same-named class

Several classes here share a FILE NAME with another in a different namespace —
lib/Service/ChecklistService.php and lib/Service/Inspection/ChecklistService.php,
BelplanRoutingService, HearingService and others. The arity fixer keyed
constructors by that file name, so some constructions received arguments from
the wrong class:

    Error: Unknown named parameter $settingsService

Classes are now resolved through the file's own `use` imports, and the pass
refuses to act unless it is certain: a constructor that exists but parses to
nothing is treated as a PARSE FAILURE and skipped, never as "takes no
arguments".

It also reads only DEPTH-0 named arguments. A nested construction has its own
constructor:

    new ProcestToolProvider(
        caseReader: new ProcestCaseReader(
            settingsService: $settingsService,   <-- the INNER call's parameter
            logger: $logger,

Judging those against the outer constructor is what made the first attempt
delete valid arguments; that attempt was reverted, and this is its replacement.

* fix(tests): restore inherited constructor args, and expect saveObject's real order

Two remaining PHPUnit causes in this app.

1. 21 errors: ArgumentCountError on ZgwRulesBase::__construct().
   ZgwZrcRulesService has NO constructor of its own — it INHERITS
   ZgwRulesBase(logger, settingsService, fieldValidator). An earlier sweep read
   "no __construct in this file" as "takes no arguments" and dropped the two
   inherited ones. Both mocks were already built two lines above; they had
   simply stopped being passed.

2. 2 TypeErrors: the doubles declared

       function (string $r, string $s, array $obj)

   which is the OLD positional saveObject($register, $schema, $object).
   ObjectServiceInterface::saveObject() takes $object FIRST, and the caller uses
   named arguments, so the double receives them in the contract's order. The
   with() expectation had the same assumption and asserted on the third
   argument.

   This is the contract doing its job: a signature nobody could see is now one
   the doubles have to agree with.
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