From c64365b91f808c12f262659ef08b2ccbc120f8d7 Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Tue, 12 May 2026 09:46:02 +0200 Subject: [PATCH 01/13] chore(phpcs): auto-fix 602 PHPCS violations in lib/ via phpcbf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `composer phpcs:fix` (PHPCBF) auto-corrects 602 sniff violations across 75 files in `lib/` — alignment, trailing whitespace, missing `//end` comments, brace placement, etc. Pure mechanical reformat; no logic changes. This shrinks procest's pre-existing PHPCS baseline from ~829 errors to 227. The remaining 227 are NOT auto-fixable and need manual work — a separate focused pass: - ~132 × "All arguments in calls to internal code must use named arguments" - ~43 × "Inline IF statements are not allowed" (ternary → if/else) - ~52 × missing `@return` / parameter PHPDoc tags + a few misc The procest "PHP Quality (phpcs)" CI gate fails on any error, so it stays red until the remaining 227 are cleared too — but this is the right first step (the 602 auto-fixes would otherwise have to be re-done by hand). Recommend merging this before the other open procest PRs (#410-#420) so they rebase onto the reformatted lib/ rather than conflicting with a later sweep. --- lib/BackgroundJob/AdviceDeadlineJob.php | 3 +- lib/Controller/AdviceController.php | 1 - lib/Controller/CaseSharingController.php | 1 - lib/Controller/LhsController.php | 4 +- .../ParaferingAuditExportController.php | 26 +++---- lib/Controller/PublicShareController.php | 2 +- lib/Controller/RoutingController.php | 12 +-- lib/Controller/StatusTransitionController.php | 19 +++-- lib/Controller/WmsWfsController.php | 11 +-- .../WorkflowDefinitionController.php | 9 --- lib/Event/ParafeerTransitionEvent.php | 2 +- lib/Listener/BeroepEscalationListener.php | 12 +-- .../BezwaarAdviceRequestedListener.php | 8 +- lib/Listener/BezwaarDecisionListener.php | 6 +- .../BezwaarHearingScheduledListener.php | 8 +- lib/Listener/BezwaarLifecycleListener.php | 16 ++-- .../ChecklistRunImmutabilityListener.php | 5 +- lib/Listener/ParaferingAuditListener.php | 6 +- lib/Listener/RoleMutationListener.php | 7 +- lib/Repair/MigrateWorkflowDefinitions.php | 64 +++++++-------- lib/Repair/SeedBezwaarWorkflowDefinition.php | 26 +++---- lib/Repair/SeedVthWorkflowTemplates.php | 36 +++------ lib/Service/Actions/ActionRegistry.php | 16 +++- lib/Service/Actions/ActionResult.php | 2 + lib/Service/Actions/CallWebhookHandler.php | 20 +++-- lib/Service/Actions/CreateDocumentHandler.php | 8 +- lib/Service/Actions/HandlesTemplates.php | 7 +- lib/Service/Actions/MergeTemplateHandler.php | 4 +- lib/Service/Actions/NotifyRoleHandler.php | 8 +- .../Actions/ScheduleReminderHandler.php | 6 +- lib/Service/Actions/SendEmailHandler.php | 6 +- lib/Service/AdviceService.php | 4 +- .../Bezwaar/AdvisoryCommitteeService.php | 48 +++++------- lib/Service/Bezwaar/BeroepService.php | 53 ++++++------- lib/Service/Bezwaar/DecisionService.php | 6 +- lib/Service/Bezwaar/HearingService.php | 77 ++++++++----------- lib/Service/CaseSharingService.php | 10 +-- lib/Service/Inspection/ChecklistService.php | 50 ++++++------ lib/Service/LocationService.php | 72 ++++++++--------- lib/Service/ParafeerActieService.php | 4 +- lib/Service/ParafeerRouteService.php | 6 +- lib/Service/Parafering/AuditTrailService.php | 12 ++- lib/Service/Pdok/PdokBagService.php | 6 +- lib/Service/Pdok/PdokLocatieserverService.php | 11 ++- lib/Service/RoleResolverService.php | 42 +++++----- .../Routing/RoutingStrategyInterface.php | 5 +- .../Routing/Strategy/HierarchicalStrategy.php | 4 +- .../Routing/Strategy/LeastLoadedStrategy.php | 4 +- .../Routing/Strategy/OrSetStrategy.php | 4 +- .../Routing/Strategy/RoundRobinStrategy.php | 4 +- .../Routing/Strategy/SingleRoleStrategy.php | 13 ++-- lib/Service/Routing/StrategyRegistry.php | 1 + lib/Service/StatusTransitionService.php | 73 ++++++++++++------ lib/Service/StepConfigValidator.php | 28 ++++--- .../Transitions/ActionHandlerInterface.php | 1 - .../Transitions/ActionHandlerRegistry.php | 4 +- lib/Service/Transitions/ActionResult.php | 1 - lib/Service/Transitions/ChecklistGuard.php | 4 +- .../Transitions/CreateSubCaseHandler.php | 7 +- lib/Service/Transitions/CreateTaskHandler.php | 3 +- .../Transitions/GuardEvaluatorInterface.php | 1 - lib/Service/Transitions/GuardRegistry.php | 9 ++- lib/Service/Transitions/GuardResult.php | 1 - lib/Service/Transitions/NotifyHandler.php | 1 - .../Transitions/RequiredDocumentGuard.php | 2 +- .../Transitions/RequiredFieldGuard.php | 1 - lib/Service/Transitions/RoleGuard.php | 3 +- lib/Service/Transitions/SendEmailHandler.php | 3 +- lib/Service/Transitions/SetFieldHandler.php | 3 +- .../Transitions/SideEffectDispatcher.php | 5 +- lib/Service/Transitions/WebhookHandler.php | 3 +- lib/Service/Vth/LhsRecommendationService.php | 4 +- lib/Service/WmsWfsService.php | 16 +--- lib/Service/WorkflowDefinitionService.php | 53 ++++--------- lib/Service/WorkflowTemplateLoader.php | 8 ++ 75 files changed, 496 insertions(+), 535 deletions(-) diff --git a/lib/BackgroundJob/AdviceDeadlineJob.php b/lib/BackgroundJob/AdviceDeadlineJob.php index f8ee8154..e8af486d 100644 --- a/lib/BackgroundJob/AdviceDeadlineJob.php +++ b/lib/BackgroundJob/AdviceDeadlineJob.php @@ -39,7 +39,6 @@ */ class AdviceDeadlineJob extends TimedJob { - /** * Constructor. * @@ -124,6 +123,6 @@ protected function run($argument): void ], ); } - } + }//end foreach }//end run() }//end class diff --git a/lib/Controller/AdviceController.php b/lib/Controller/AdviceController.php index 39f216f7..405e36ea 100644 --- a/lib/Controller/AdviceController.php +++ b/lib/Controller/AdviceController.php @@ -39,7 +39,6 @@ */ class AdviceController extends Controller { - /** * Constructor. * diff --git a/lib/Controller/CaseSharingController.php b/lib/Controller/CaseSharingController.php index 3725dcf9..b2ac4a78 100644 --- a/lib/Controller/CaseSharingController.php +++ b/lib/Controller/CaseSharingController.php @@ -201,5 +201,4 @@ public function handleTransfer(string $transferId): JSONResponse return new JSONResponse(['success' => true, 'transfer' => $result]); }//end handleTransfer() - }//end class diff --git a/lib/Controller/LhsController.php b/lib/Controller/LhsController.php index 372958fe..03301ce2 100644 --- a/lib/Controller/LhsController.php +++ b/lib/Controller/LhsController.php @@ -137,7 +137,7 @@ public function recommend(): JSONResponse ['error' => 'LHS-aanbeveling mislukt'], Http::STATUS_INTERNAL_SERVER_ERROR, ); - } + }//end try return new JSONResponse($recommendation); }//end recommend() @@ -206,7 +206,7 @@ public function override(): JSONResponse ['error' => 'LHS-override mislukt'], Http::STATUS_INTERNAL_SERVER_ERROR, ); - } + }//end try return new JSONResponse($updated); }//end override() diff --git a/lib/Controller/ParaferingAuditExportController.php b/lib/Controller/ParaferingAuditExportController.php index ca9af6c4..5f64ff3c 100644 --- a/lib/Controller/ParaferingAuditExportController.php +++ b/lib/Controller/ParaferingAuditExportController.php @@ -52,13 +52,13 @@ class ParaferingAuditExportController extends Controller /** * Constructor. * - * @param string $appName Nextcloud app id - * @param IRequest $request Incoming request - * @param IUserSession $userSession Current user session - * @param IGroupManager $groupManager Group manager (for RBAC check) - * @param AuditTrailService $auditTrailService The audit-trail service - * @param SettingsService $settingsService Procest settings bridge - * @param LoggerInterface $logger PSR-3 logger + * @param string $appName Nextcloud app id + * @param IRequest $request Incoming request + * @param IUserSession $userSession Current user session + * @param IGroupManager $groupManager Group manager (for RBAC check) + * @param AuditTrailService $auditTrailService The audit-trail service + * @param SettingsService $settingsService Procest settings bridge + * @param LoggerInterface $logger PSR-3 logger */ public function __construct( string $appName, @@ -81,7 +81,7 @@ public function __construct( * @return JSONResponse */ #[NoAdminRequired] - public function export(string $id, string $format = 'json'): JSONResponse + public function export(string $id, string $format='json'): JSONResponse { try { $user = $this->userSession->getUser(); @@ -92,8 +92,8 @@ public function export(string $id, string $format = 'json'): JSONResponse ); } - $uid = $user->getUID(); - $allowed = false; + $uid = $user->getUID(); + $allowed = false; foreach (self::ALLOWED_GROUPS as $group) { if ($this->groupManager->isInGroup($uid, $group) === true) { $allowed = true; @@ -182,13 +182,13 @@ private function resolveVoorstelOnderwerp(string $voorstelId): ?string $array = []; if (is_array($voorstel) === true) { $array = $voorstel; - } elseif (is_object($voorstel) === true) { + } else if (is_object($voorstel) === true) { if (method_exists($voorstel, 'jsonSerialize') === true) { $serialized = $voorstel->jsonSerialize(); if (is_array($serialized) === true) { $array = $serialized; } - } elseif (method_exists($voorstel, 'toArray') === true) { + } else if (method_exists($voorstel, 'toArray') === true) { $arr = $voorstel->toArray(); if (is_array($arr) === true) { $array = $arr; @@ -204,6 +204,6 @@ private function resolveVoorstelOnderwerp(string $voorstelId): ?string ); return null; - } + }//end try }//end resolveVoorstelOnderwerp() }//end class diff --git a/lib/Controller/PublicShareController.php b/lib/Controller/PublicShareController.php index d4ae9086..372d0e94 100644 --- a/lib/Controller/PublicShareController.php +++ b/lib/Controller/PublicShareController.php @@ -267,7 +267,7 @@ public function uploadDocument(string $token): JSONResponse ); } - $share = $validation['share']; + $share = $validation['share']; $permissionLevel = ($share['permissionLevel'] ?? 'bekijken'); if ($permissionLevel !== 'bijdragen' && $permissionLevel !== 'contribute') { diff --git a/lib/Controller/RoutingController.php b/lib/Controller/RoutingController.php index ee6fac13..2df10bc8 100644 --- a/lib/Controller/RoutingController.php +++ b/lib/Controller/RoutingController.php @@ -116,9 +116,9 @@ public function reroute(string $id): JSONResponse ); } - $register = $this->settingsService->getConfigValue('register'); - $caseSchema = $this->settingsService->getConfigValue('case_schema'); - $workflowSlug = $this->settingsService->getConfigValue('workflow_template_schema'); + $register = $this->settingsService->getConfigValue('register'); + $caseSchema = $this->settingsService->getConfigValue('case_schema'); + $workflowSlug = $this->settingsService->getConfigValue('workflow_template_schema'); $case = $this->toArray(value: $objectService->findObject($register, $caseSchema, $id)); @@ -136,8 +136,8 @@ public function reroute(string $id): JSONResponse continue; } - $assignees = $this->resolver->resolve($rule, $case); - $affected[] = [ + $assignees = $this->resolver->resolve($rule, $case); + $affected[] = [ 'stepId' => (string) ($step['id'] ?? ''), 'order' => (int) ($step['order'] ?? 0), 'assignees' => $assignees, @@ -158,7 +158,7 @@ public function reroute(string $id): JSONResponse ['error' => 'Herberekening mislukt'], Http::STATUS_INTERNAL_SERVER_ERROR, ); - } + }//end try }//end reroute() /** diff --git a/lib/Controller/StatusTransitionController.php b/lib/Controller/StatusTransitionController.php index b25c47a0..0940846c 100644 --- a/lib/Controller/StatusTransitionController.php +++ b/lib/Controller/StatusTransitionController.php @@ -50,7 +50,6 @@ */ class StatusTransitionController extends Controller { - /** * Constructor. * @@ -107,9 +106,9 @@ public function available(string $caseId): JSONResponse */ public function execute(string $caseId): JSONResponse { - $body = $this->readJsonBody(); - $transitionId = (string) ($body['transitionId'] ?? ''); - $comment = isset($body['comment']) === true ? (string) $body['comment'] : null; + $body = $this->readJsonBody(); + $transitionId = (string) ($body['transitionId'] ?? ''); + $comment = isset($body['comment']) === true ? (string) $body['comment'] : null; if ($transitionId === '') { return new JSONResponse( @@ -131,12 +130,13 @@ public function execute(string $caseId): JSONResponse Http::STATUS_CONFLICT, ); } catch (RuntimeException $e) { - $code = $e->getMessage(); - $status = match ($code) { + $code = $e->getMessage(); + $status = match ($code) { 'case_not_found', 'transition_not_found' => Http::STATUS_NOT_FOUND, 'forbidden_admin_only' => Http::STATUS_FORBIDDEN, default => Http::STATUS_BAD_REQUEST, }; + $this->logger->info('StatusTransitionController: execute rejected', ['code' => $code]); return new JSONResponse(['error' => 'Could not execute transition'], $status); } catch (\Throwable $e) { @@ -148,7 +148,7 @@ public function execute(string $caseId): JSONResponse ['error' => 'Could not execute transition'], Http::STATUS_INTERNAL_SERVER_ERROR, ); - } + }//end try }//end execute() /** @@ -195,6 +195,7 @@ public function freeform(string $caseId): JSONResponse 'case_not_found', 'case_type_not_found' => Http::STATUS_NOT_FOUND, default => Http::STATUS_BAD_REQUEST, }; + $this->logger->info('StatusTransitionController: freeform rejected', ['code' => $code]); return new JSONResponse(['error' => 'Could not execute free-form transition'], $status); } catch (\Throwable $e) { @@ -206,7 +207,7 @@ public function freeform(string $caseId): JSONResponse ['error' => 'Could not execute free-form transition'], Http::STATUS_INTERNAL_SERVER_ERROR, ); - } + }//end try }//end freeform() /** @@ -246,10 +247,12 @@ private function readJsonBody(): array if ($content === '' || $content === false) { return []; } + $decoded = json_decode($content, true); if (is_array($decoded) === true) { return $decoded; } + return []; }//end readJsonBody() }//end class diff --git a/lib/Controller/WmsWfsController.php b/lib/Controller/WmsWfsController.php index e86dee2b..29e125bf 100644 --- a/lib/Controller/WmsWfsController.php +++ b/lib/Controller/WmsWfsController.php @@ -38,14 +38,12 @@ */ class WmsWfsController extends Controller { - - /** * Constructor for WmsWfsController. * - * @param string $appName The application name - * @param IRequest $request The request object - * @param WmsWfsService $wmsWfsService The WMS/WFS service + * @param string $appName The application name + * @param IRequest $request The request object + * @param WmsWfsService $wmsWfsService The WMS/WFS service * * @return void */ @@ -57,7 +55,6 @@ public function __construct( parent::__construct(appName: $appName, request: $request); }//end __construct() - /** * Proxy a request to a configured wmsLayer's upstream endpoint. * @@ -121,6 +118,4 @@ public function proxy(): JSONResponse ); } }//end proxy() - - }//end class diff --git a/lib/Controller/WorkflowDefinitionController.php b/lib/Controller/WorkflowDefinitionController.php index 6008f539..bfe6628a 100644 --- a/lib/Controller/WorkflowDefinitionController.php +++ b/lib/Controller/WorkflowDefinitionController.php @@ -39,8 +39,6 @@ */ class WorkflowDefinitionController extends Controller { - - /** * Constructor. * @@ -54,7 +52,6 @@ public function __construct( parent::__construct(appName: Application::APP_ID, request: $request); }//end __construct() - /** * Publish a draft definition. * @@ -79,7 +76,6 @@ public function publish(string $id): JSONResponse return new JSONResponse(['success' => true, 'definition' => $result]); }//end publish() - /** * Deprecate a published definition. * @@ -103,7 +99,6 @@ public function deprecate(string $id): JSONResponse return new JSONResponse(['success' => true, 'definition' => $result]); }//end deprecate() - /** * Clone an existing definition into a new draft. * @@ -124,7 +119,6 @@ public function cloneDefinition(string $id): JSONResponse return new JSONResponse(['success' => true, 'definition' => $result]); }//end cloneDefinition() - /** * Read-only consumer endpoint — returns the active definition for a * caseType. Used by other apps when they need to consult the @@ -147,7 +141,6 @@ public function active(string $caseTypeId): JSONResponse return new JSONResponse(['success' => true, 'definition' => $definition]); }//end active() - /** * Read-only consumer endpoint — returns the definition pinned to a * specific case via case.workflowTemplate + case.workflowVersion. @@ -168,6 +161,4 @@ public function forCase(string $caseId): JSONResponse return new JSONResponse(['success' => true, 'definition' => $definition]); }//end forCase() - - }//end class diff --git a/lib/Event/ParafeerTransitionEvent.php b/lib/Event/ParafeerTransitionEvent.php index 1b2dd0c2..8804879c 100644 --- a/lib/Event/ParafeerTransitionEvent.php +++ b/lib/Event/ParafeerTransitionEvent.php @@ -52,7 +52,7 @@ public function __construct( private readonly ?string $step, private readonly string $actor, private readonly string $actorRole, - private readonly ?string $reason = null, + private readonly ?string $reason=null, ) { parent::__construct(); }//end __construct() diff --git a/lib/Listener/BeroepEscalationListener.php b/lib/Listener/BeroepEscalationListener.php index 213c5e05..12f08869 100644 --- a/lib/Listener/BeroepEscalationListener.php +++ b/lib/Listener/BeroepEscalationListener.php @@ -170,7 +170,7 @@ public function handle(Event $event): void 'Procest beroep: dwingendStatus derivation swallowed ' .'exception: '.$e->getMessage(), ); - } + }//end try }//end handle() /** @@ -195,8 +195,7 @@ public function handle(Event $event): void private function shouldFlagDwingend(array $beroep, array $bezwaar): bool { $bezwaarStatus = (string) ($bezwaar['status'] ?? ''); - if (in_array($bezwaarStatus, self::TERMINAL_BEZWAAR_STATUSES, true) - === false + if (in_array($bezwaarStatus, self::TERMINAL_BEZWAAR_STATUSES, true) === false ) { return false; } @@ -235,8 +234,7 @@ private function withinFilingWindow(array $beroep): bool $deadline = (string) ($beroep['filingDeadline'] ?? ''); if ($deadline !== '') { try { - return (new DateTimeImmutable($filing)) - <= (new DateTimeImmutable($deadline)); + return (new DateTimeImmutable($filing)) <= (new DateTimeImmutable($deadline)); } catch (Throwable $e) { return true; } @@ -267,9 +265,7 @@ private function isBeroepSchema(array $object): bool } $candidate = (string) ( - $object['@self']['schema'] - ?? ($object['@self']['schemaSlug'] - ?? ($object['schema'] ?? ($object['_schemaSlug'] ?? ''))) + $object['@self']['schema'] ?? ($object['@self']['schemaSlug'] ?? ($object['schema'] ?? ($object['_schemaSlug'] ?? ''))) ); return $candidate !== '' && ( diff --git a/lib/Listener/BezwaarAdviceRequestedListener.php b/lib/Listener/BezwaarAdviceRequestedListener.php index 69cc36d8..9801d649 100644 --- a/lib/Listener/BezwaarAdviceRequestedListener.php +++ b/lib/Listener/BezwaarAdviceRequestedListener.php @@ -104,8 +104,7 @@ public function handle(Event $event): void } $bezwaarId = (string) ( - $object['@self']['id'] - ?? ($object['id'] ?? ($object['uuid'] ?? '')) + $object['@self']['id'] ?? ($object['id'] ?? ($object['uuid'] ?? '')) ); if ($bezwaarId === '') { return; @@ -119,7 +118,7 @@ public function handle(Event $event): void 'Procest BAC: advice-requested listener swallowed ' .'exception: '.$e->getMessage(), ); - } + }//end try }//end handle() /** @@ -139,8 +138,7 @@ private function isBezwaarSchema(array $object): bool } $candidate = (string) ( - $object['@self']['schema'] - ?? ($object['schema'] ?? '') + $object['@self']['schema'] ?? ($object['schema'] ?? '') ); return $candidate !== '' && ( diff --git a/lib/Listener/BezwaarDecisionListener.php b/lib/Listener/BezwaarDecisionListener.php index 04980561..11639ad1 100644 --- a/lib/Listener/BezwaarDecisionListener.php +++ b/lib/Listener/BezwaarDecisionListener.php @@ -108,7 +108,7 @@ public function handle(Event $event): void 'Procest bezwaar-decision: guard derivation swallowed ' .'exception: '.$e->getMessage() ); - } + }//end try }//end handle() /** @@ -257,9 +257,7 @@ private function isBezwaarSchema(array $object): bool } $candidate = (string) ( - $object['@self']['schema'] - ?? ($object['@self']['schemaSlug'] - ?? ($object['schema'] ?? ($object['_schemaSlug'] ?? ''))) + $object['@self']['schema'] ?? ($object['@self']['schemaSlug'] ?? ($object['schema'] ?? ($object['_schemaSlug'] ?? ''))) ); return $candidate !== '' && ( diff --git a/lib/Listener/BezwaarHearingScheduledListener.php b/lib/Listener/BezwaarHearingScheduledListener.php index 6b8e86e9..6b87989a 100644 --- a/lib/Listener/BezwaarHearingScheduledListener.php +++ b/lib/Listener/BezwaarHearingScheduledListener.php @@ -101,8 +101,7 @@ public function handle(Event $event): void } $bezwaarId = (string) ( - $object['@self']['id'] - ?? ($object['id'] ?? ($object['uuid'] ?? '')) + $object['@self']['id'] ?? ($object['id'] ?? ($object['uuid'] ?? '')) ); if ($bezwaarId === '') { return; @@ -114,7 +113,7 @@ public function handle(Event $event): void 'Procest hearing: scheduled listener swallowed exception: ' .$e->getMessage(), ); - } + }//end try }//end handle() /** @@ -134,8 +133,7 @@ private function isBezwaarSchema(array $object): bool } $candidate = (string) ( - $object['@self']['schema'] - ?? ($object['schema'] ?? '') + $object['@self']['schema'] ?? ($object['schema'] ?? '') ); return $candidate !== '' && ( diff --git a/lib/Listener/BezwaarLifecycleListener.php b/lib/Listener/BezwaarLifecycleListener.php index cb42f2e5..5ddcdcd1 100644 --- a/lib/Listener/BezwaarLifecycleListener.php +++ b/lib/Listener/BezwaarLifecycleListener.php @@ -64,7 +64,6 @@ class BezwaarLifecycleListener implements IEventListener 'decision', ]; - /** * Constructor. * @@ -77,7 +76,6 @@ public function __construct( ) { }//end __construct() - /** * Handle an OR object event. * @@ -113,16 +111,15 @@ public function handle(Event $event): void $this->logger->debug( 'Procest bezwaar-lifecycle: observed '.$schemaSlug.' '.$event::class, [ - 'app' => Application::APP_ID, - 'schema' => $schemaSlug, - 'objectId' => (string) ($payload['id'] ?? ''), - 'caseId' => (string) ($payload['case'] ?? ''), - 'status' => (string) ($payload['status'] ?? ''), + 'app' => Application::APP_ID, + 'schema' => $schemaSlug, + 'objectId' => (string) ($payload['id'] ?? ''), + 'caseId' => (string) ($payload['case'] ?? ''), + 'status' => (string) ($payload['status'] ?? ''), ] ); }//end handle() - /** * Extract the OR object array from an event. * @@ -150,7 +147,6 @@ private function extractObject(Event $event): ?array return null; }//end extractObject() - /** * Resolve the schema slug for an OR object payload. * @@ -166,6 +162,7 @@ private function resolveSchemaSlug(array $payload): string if (isset($self['schemaSlug']) === true) { return (string) $self['schemaSlug']; } + if (isset($self['schema']) === true && is_string($self['schema']) === true) { return $self['schema']; } @@ -181,5 +178,4 @@ private function resolveSchemaSlug(array $payload): string return ''; }//end resolveSchemaSlug() - }//end class diff --git a/lib/Listener/ChecklistRunImmutabilityListener.php b/lib/Listener/ChecklistRunImmutabilityListener.php index c123f251..e82c8f1c 100644 --- a/lib/Listener/ChecklistRunImmutabilityListener.php +++ b/lib/Listener/ChecklistRunImmutabilityListener.php @@ -119,7 +119,7 @@ public function handle(Event $event): void $this->logger->debug( 'Procest: checklist immutability listener swallowed exception: '.$e->getMessage(), ); - } + }//end try }//end handle() /** @@ -137,8 +137,7 @@ private function isChecklistRunSchema(array $object): bool } $candidate = (string) ( - $object['@self']['schema'] - ?? ($object['schema'] ?? '') + $object['@self']['schema'] ?? ($object['schema'] ?? '') ); return $candidate !== '' && ( diff --git a/lib/Listener/ParaferingAuditListener.php b/lib/Listener/ParaferingAuditListener.php index f03b43ed..dd18d40f 100644 --- a/lib/Listener/ParaferingAuditListener.php +++ b/lib/Listener/ParaferingAuditListener.php @@ -125,13 +125,13 @@ private function fetchContentSnapshot(string $voorstelId): array $array = []; if (is_array($voorstel) === true) { $array = $voorstel; - } elseif (is_object($voorstel) === true) { + } else if (is_object($voorstel) === true) { if (method_exists($voorstel, 'jsonSerialize') === true) { $serialized = $voorstel->jsonSerialize(); if (is_array($serialized) === true) { $array = $serialized; } - } elseif (method_exists($voorstel, 'toArray') === true) { + } else if (method_exists($voorstel, 'toArray') === true) { $arr = $voorstel->toArray(); if (is_array($arr) === true) { $array = $arr; @@ -152,6 +152,6 @@ private function fetchContentSnapshot(string $voorstelId): array ); return []; - } + }//end try }//end fetchContentSnapshot() }//end class diff --git a/lib/Listener/RoleMutationListener.php b/lib/Listener/RoleMutationListener.php index 2bdf7a71..d384bbf0 100644 --- a/lib/Listener/RoleMutationListener.php +++ b/lib/Listener/RoleMutationListener.php @@ -103,7 +103,7 @@ public function handle(Event $event): void $this->logger->debug( 'Procest: role mutation listener swallowed exception: '.$e->getMessage(), ); - } + }//end try }//end handle() /** @@ -121,8 +121,7 @@ private function isRoleSchema(array $object): bool } $candidate = (string) ( - $object['@self']['schema'] - ?? ($object['schema'] ?? '') + $object['@self']['schema'] ?? ($object['schema'] ?? '') ); return $candidate !== '' && ( @@ -165,7 +164,7 @@ private function extractObject(Event $event): ?array } } } - } + }//end foreach return null; }//end extractObject() diff --git a/lib/Repair/MigrateWorkflowDefinitions.php b/lib/Repair/MigrateWorkflowDefinitions.php index 62ada6c3..191e5647 100644 --- a/lib/Repair/MigrateWorkflowDefinitions.php +++ b/lib/Repair/MigrateWorkflowDefinitions.php @@ -39,8 +39,6 @@ */ class MigrateWorkflowDefinitions implements IRepairStep { - - /** * Constructor. * @@ -55,7 +53,6 @@ public function __construct( ) { }//end __construct() - /** * Get the name of this repair step. * @@ -66,7 +63,6 @@ public function getName(): string return 'Backfill workflowTemplate definitions for existing caseTypes'; }//end getName() - /** * Run the backfill. * @@ -87,11 +83,11 @@ public function run(IOutput $output): void return; } - $register = $this->settingsService->getConfigValue('register'); - $caseTypeSchema = $this->settingsService->getConfigValue('case_type_schema'); - $statusSchema = $this->settingsService->getConfigValue('status_type_schema'); - $templateSchema = $this->settingsService->getConfigValue('workflow_template_schema'); - $caseSchema = $this->settingsService->getConfigValue('case_schema'); + $register = $this->settingsService->getConfigValue('register'); + $caseTypeSchema = $this->settingsService->getConfigValue('case_type_schema'); + $statusSchema = $this->settingsService->getConfigValue('status_type_schema'); + $templateSchema = $this->settingsService->getConfigValue('workflow_template_schema'); + $caseSchema = $this->settingsService->getConfigValue('case_schema'); if ($register === '' || $caseTypeSchema === '' @@ -198,7 +194,7 @@ public function run(IOutput $output): void $newId, ); } - } + }//end if $migrated++; }//end foreach @@ -208,16 +204,15 @@ public function run(IOutput $output): void ); }//end run() - /** * Build a workflowTemplate payload from a caseType's statusType * records. * - * @param string $caseTypeId The caseType UUID - * @param array $caseType Normalized caseType row - * @param object $objectService Resolved OR ObjectService - * @param string $register The register id - * @param string $statusSchema The statusType schema id + * @param string $caseTypeId The caseType UUID + * @param array $caseType Normalized caseType row + * @param object $objectService Resolved OR ObjectService + * @param string $register The register id + * @param string $statusSchema The statusType schema id * * @return array|null */ @@ -274,14 +269,14 @@ static function (array $a, array $b): int { } $steps[] = [ - 'id' => $this->uuid(), - 'title' => (string) ($status['name'] ?? 'Stap'), - 'description' => (string) ($status['description'] ?? ''), - 'status' => (string) ($status['id'] ?? ''), - 'order' => (int) ($status['order'] ?? 0), - 'assigneeRole' => '', - 'isRequired' => false, - 'checklist' => [], + 'id' => $this->uuid(), + 'title' => (string) ($status['name'] ?? 'Stap'), + 'description' => (string) ($status['description'] ?? ''), + 'status' => (string) ($status['id'] ?? ''), + 'order' => (int) ($status['order'] ?? 0), + 'assigneeRole' => '', + 'isRequired' => false, + 'checklist' => [], 'automaticActions' => [], ]; } @@ -293,13 +288,13 @@ static function (array $a, array $b): int { $to = $statuses[($i + 1)]; $transitions[] = [ - 'id' => $this->uuid(), - 'fromStatus' => (string) ($from['id'] ?? ''), - 'toStatus' => (string) ($to['id'] ?? ''), - 'label' => (string) ($to['name'] ?? 'Door'), - 'guards' => [], + 'id' => $this->uuid(), + 'fromStatus' => (string) ($from['id'] ?? ''), + 'toStatus' => (string) ($to['id'] ?? ''), + 'label' => (string) ($to['name'] ?? 'Door'), + 'guards' => [], 'automaticActions' => [], - 'allowedRoles' => [], + 'allowedRoles' => [], ]; } @@ -310,7 +305,7 @@ static function (array $a, array $b): int { return [ 'title' => $title.' — basis', - 'description' => 'Backfilled from implicit statusType ordering.', + 'description' => 'Backfilled from implicit statusType ordering.', 'caseType' => $caseTypeId, 'version' => 1, 'isActive' => true, @@ -322,7 +317,6 @@ static function (array $a, array $b): int { ]; }//end buildTemplateFor() - /** * Pin every open case of a caseType to workflowVersion 1 and bind it * to the new workflowTemplate. @@ -394,10 +388,9 @@ private function pinOpenCases( ['app' => Application::APP_ID, 'exception' => $e->getMessage()] ); } - } + }//end foreach }//end pinOpenCases() - /** * Coerce an OpenRegister result row to an associative array. * @@ -421,7 +414,6 @@ private function normalize(mixed $row): ?array return null; }//end normalize() - /** * Generate a UUID v4 for embedded step / transition identifiers. * @@ -440,6 +432,4 @@ private function uuid(): string .substr($hex, 16, 4).'-' .substr($hex, 20, 12); }//end uuid() - - }//end class diff --git a/lib/Repair/SeedBezwaarWorkflowDefinition.php b/lib/Repair/SeedBezwaarWorkflowDefinition.php index bc6a43ca..4192d6fc 100644 --- a/lib/Repair/SeedBezwaarWorkflowDefinition.php +++ b/lib/Repair/SeedBezwaarWorkflowDefinition.php @@ -54,7 +54,6 @@ class SeedBezwaarWorkflowDefinition implements IRepairStep 'Ingetrokken' => 'Intrekking vergt AWB-motivering (6:21)', ]; - /** * Constructor. * @@ -69,7 +68,6 @@ public function __construct( ) { }//end __construct() - /** * Get the name of this repair step. * @@ -80,7 +78,6 @@ public function getName(): string return 'Seed canonical bezwaar workflow definition (AWB-compliant state machine)'; }//end getName() - /** * Run the repair step. * @@ -101,10 +98,10 @@ public function run(IOutput $output): void return; } - $register = $this->settingsService->getConfigValue('register'); - $caseTypeSchema = $this->settingsService->getConfigValue('case_type_schema'); - $statusSchema = $this->settingsService->getConfigValue('status_type_schema'); - $templateSchema = $this->settingsService->getConfigValue('workflow_template_schema'); + $register = $this->settingsService->getConfigValue('register'); + $caseTypeSchema = $this->settingsService->getConfigValue('case_type_schema'); + $statusSchema = $this->settingsService->getConfigValue('status_type_schema'); + $templateSchema = $this->settingsService->getConfigValue('workflow_template_schema'); if ($register === '' || $caseTypeSchema === '' @@ -183,6 +180,7 @@ public function run(IOutput $output): void if ($row === null) { continue; } + $name = (string) ($row['name'] ?? ''); $id = (string) ($row['id'] ?? ''); if ($name !== '' && $id !== '') { @@ -215,7 +213,7 @@ public function run(IOutput $output): void $template = [ 'title' => 'Bezwaar — AWB-compliant workflow', - 'description' => 'Canonical bezwaar lifecycle state machine: Ontvangen → Afgehandeld with terminal Niet-ontvankelijk/Ingetrokken. Transitions wired through the status-transition-engine; deadlines computed declaratively on the bezwaar schema (x-openregister-calculations, ADR-022).', + 'description' => 'Canonical bezwaar lifecycle state machine: Ontvangen → Afgehandeld with terminal Niet-ontvankelijk/Ingetrokken. Transitions wired through the status-transition-engine; deadlines computed declaratively on the bezwaar schema (x-openregister-calculations, ADR-022).', 'caseType' => $caseTypeId, 'version' => 1, 'isActive' => true, @@ -263,7 +261,6 @@ public function run(IOutput $output): void $output->info('Seeded canonical bezwaar workflow definition.'); }//end run() - /** * Build step records from statusType rows. * @@ -277,7 +274,7 @@ private function buildSteps(array $statusByName, array $ordered): array $steps = []; $order = 1; foreach ($ordered as $name) { - $row = $statusByName[$name]; + $row = $statusByName[$name]; $steps[] = [ 'id' => $this->uuid(), 'title' => $name, @@ -291,10 +288,10 @@ private function buildSteps(array $statusByName, array $ordered): array ]; $order++; } + return $steps; }//end buildSteps() - /** * Build the bezwaar state-machine transition matrix. * @@ -345,12 +342,11 @@ private function buildTransitions(array $statusByName): array 'automaticActions' => [], 'allowedRoles' => [], ]; - } + }//end foreach return $transitions; }//end buildTransitions() - /** * Normalize an OR object into a flat array. * @@ -363,14 +359,15 @@ private function normalize(mixed $object): ?array if (is_array($object) === true) { return $object; } + if (is_object($object) === true && method_exists($object, 'jsonSerialize') === true) { $serialized = $object->jsonSerialize(); return is_array($serialized) ? $serialized : null; } + return null; }//end normalize() - /** * Generate a v4 UUID. * @@ -383,5 +380,4 @@ private function uuid(): string $data[8] = chr((ord($data[8]) & 0x3F) | 0x80); return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4)); }//end uuid() - }//end class diff --git a/lib/Repair/SeedVthWorkflowTemplates.php b/lib/Repair/SeedVthWorkflowTemplates.php index 8c654280..b5f76977 100644 --- a/lib/Repair/SeedVthWorkflowTemplates.php +++ b/lib/Repair/SeedVthWorkflowTemplates.php @@ -61,7 +61,6 @@ class SeedVthWorkflowTemplates implements IRepairStep */ private const NS_UUID = '6ba7b811-9dad-11d1-80b4-00c04fd430c8'; - /** * Constructor for SeedVthWorkflowTemplates. * @@ -78,7 +77,6 @@ public function __construct( ) { }//end __construct() - /** * Get the name of this repair step. * @@ -89,7 +87,6 @@ public function getName(): string return 'Seed VTH (Vergunningen, Toezicht, Handhaving) workflow templates for Procest'; }//end getName() - /** * Run the repair step. * @@ -131,7 +128,7 @@ public function run(IOutput $output): void foreach ($files as $file) { try { - $result = $this->processCatalogFile(file: $file, output: $output); + $result = $this->processCatalogFile(file: $file, output: $output); $summary[$result] = ($summary[$result] ?? 0) + 1; } catch (\Throwable $e) { $summary['failed']++; @@ -159,7 +156,6 @@ public function run(IOutput $output): void ); }//end run() - /** * Process a single catalog file. * @@ -335,7 +331,6 @@ private function processCatalogFile(string $file, IOutput $output): string return 'seeded'; }//end processCatalogFile() - /** * Resolve a caseType by its slug — uses the `identifier` field on the * caseType schema (the canonical slug-like field across procest seed @@ -387,12 +382,11 @@ private function resolveCaseTypeId(string $slug): string if ($id !== '') { return $id; } - } + }//end foreach return ''; }//end resolveCaseTypeId() - /** * Check whether a workflowTemplate with the given title is already * present for the given caseType. Used for idempotency. @@ -438,12 +432,11 @@ private function isAlreadySeeded(string $caseTypeId, string $title): bool ] ); return false; - } + }//end try return $this->extractFirstId(rows: $rows) !== ''; }//end isAlreadySeeded() - /** * Build a status name → UUID map for the statusTypes belonging to a * given caseType. @@ -499,14 +492,14 @@ private function buildStatusMap(string $caseTypeId): array return $map; }//end buildStatusMap() - /** * Resolve the steps[] block against the status name → UUID map. * Returns null when any status name does not resolve. * - * @param string $slug The template slug (for UUID5 ids) + * @param string $slug The template slug (for UUID5 ids) * @param array> $rawSteps Steps from the catalog file - * @param array $statusMap Name → UUID map + * @param array $statusMap Name → UUID + * map * * @return array>|null Resolved steps, or null */ @@ -523,7 +516,7 @@ private function resolveSteps(string $slug, array $rawSteps, array $statusMap): return null; } - $stepSlug = (string) ($step['slug'] ?? ''); + $stepSlug = (string) ($step['slug'] ?? ''); $resolved[] = [ 'id' => $this->deterministicId(template: $slug, child: 'step-'.$stepSlug), 'slug' => $stepSlug, @@ -541,15 +534,15 @@ private function resolveSteps(string $slug, array $rawSteps, array $statusMap): return $resolved; }//end resolveSteps() - /** * Resolve the transitions[] block against the status name → UUID map. * Accepts "*" as a wildcard for fromStatus (any status). Returns null * when any non-wildcard status name does not resolve. * - * @param string $slug The template slug (for UUID5 ids) + * @param string $slug The template slug (for UUID5 ids) * @param array> $rawTransitions Transitions from the catalog file - * @param array $statusMap Name → UUID map + * @param array $statusMap Name → UUID + * map * * @return array>|null Resolved transitions, or null */ @@ -570,14 +563,14 @@ private function resolveTransitions(string $slug, array $rawTransitions, array $ if ($fromName === '*') { $fromId = '*'; - } elseif ($fromName === '' || isset($statusMap[$fromName]) === false) { + } else if ($fromName === '' || isset($statusMap[$fromName]) === false) { return null; } else { $fromId = $statusMap[$fromName]; } $transitionSlug = (string) ($transition['slug'] ?? ''); - $resolved[] = [ + $resolved[] = [ 'id' => $this->deterministicId(template: $slug, child: 'transition-'.$transitionSlug), 'slug' => $transitionSlug, 'label' => (string) ($transition['label'] ?? ''), @@ -595,7 +588,6 @@ private function resolveTransitions(string $slug, array $rawTransitions, array $ return $resolved; }//end resolveTransitions() - /** * Generate a deterministic UUID5 from a template slug + child slug. * Re-running the repair step therefore produces stable step / transition @@ -622,7 +614,6 @@ private function deterministicId(string $template, string $child): string ); }//end deterministicId() - /** * Extract the first row id from an OpenRegister result set. * @@ -656,7 +647,6 @@ private function extractFirstId(mixed $rows): string return ''; }//end extractFirstId() - /** * Coerce an OpenRegister result row to an associative array. * @@ -683,6 +673,4 @@ private function normalizeRow(mixed $row): ?array return null; }//end normalizeRow() - - }//end class diff --git a/lib/Service/Actions/ActionRegistry.php b/lib/Service/Actions/ActionRegistry.php index d652510f..b4b94b58 100644 --- a/lib/Service/Actions/ActionRegistry.php +++ b/lib/Service/Actions/ActionRegistry.php @@ -50,6 +50,7 @@ */ class ActionRegistry { + /** * In-process cache keyed by "{tenantId}::{slug}". * @@ -115,6 +116,7 @@ public function resolve(string $tenantId, string $slug): ?array if ($cached === false) { return null; } + return $cached; } @@ -188,6 +190,7 @@ public function resolve(string $tenantId, string $slug): ?array $action['config'] = $decoded; } } + if (isset($action['config']) === false || is_array($action['config']) === false) { $action['config'] = []; } @@ -227,11 +230,14 @@ public function listForTenant(string $tenantId, ?string $typeFilter=null): array if ((string) ($action['tenantId'] ?? '') !== $tenantId) { continue; } + if ($typeFilter !== null && (string) ($action['type'] ?? '') !== $typeFilter) { continue; } + $out[] = $action; } + return $out; }//end listForTenant() @@ -275,11 +281,12 @@ public function getHandler(string $type): ?ActionHandlerInterface ); continue; } + if ($handler instanceof ActionHandlerInterface) { $this->handlerIndex[$handler->type()] = $handler; } } - } + }//end if return ($this->handlerIndex[$type] ?? null); }//end getHandler() @@ -303,7 +310,7 @@ private function findAction(string $slug): ?array 'register', '' ); - $schema = $this->appConfig->getValueString( + $schema = $this->appConfig->getValueString( Application::APP_ID, 'automatic_action_schema', '' @@ -330,6 +337,7 @@ private function findAction(string $slug): ?array if (is_object($first) === true && method_exists($first, 'jsonSerialize') === true) { $first = $first->jsonSerialize(); } + return (array) $first; }//end findAction() @@ -350,7 +358,7 @@ private function fetchAll(): array 'register', '' ); - $schema = $this->appConfig->getValueString( + $schema = $this->appConfig->getValueString( Application::APP_ID, 'automatic_action_schema', '' @@ -374,8 +382,10 @@ private function fetchAll(): array if (is_object($entry) === true && method_exists($entry, 'jsonSerialize') === true) { $entry = $entry->jsonSerialize(); } + $out[] = (array) $entry; } + return $out; }//end fetchAll() diff --git a/lib/Service/Actions/ActionResult.php b/lib/Service/Actions/ActionResult.php index a6327166..d802045a 100644 --- a/lib/Service/Actions/ActionResult.php +++ b/lib/Service/Actions/ActionResult.php @@ -91,9 +91,11 @@ public function toArray(): array if ($this->error !== null) { $out['error'] = $this->error; } + if ($this->data !== []) { $out['data'] = $this->data; } + return $out; }//end toArray() }//end class diff --git a/lib/Service/Actions/CallWebhookHandler.php b/lib/Service/Actions/CallWebhookHandler.php index 245adc0d..c67a1637 100644 --- a/lib/Service/Actions/CallWebhookHandler.php +++ b/lib/Service/Actions/CallWebhookHandler.php @@ -70,10 +70,8 @@ public function handle(array $actionConfig, array $case, array $transitionContex try { $url = $this->resolveUrl($actionConfig, $transitionContext); $payloadTemplate = (string) ($actionConfig['payloadTemplate'] ?? ''); - $payload = $payloadTemplate === '' - ? json_encode(['case' => $case], JSON_THROW_ON_ERROR) - : $this->renderTemplate($payloadTemplate, $case); - $timeoutSec = (int) ($actionConfig['timeoutSec'] ?? self::DEFAULT_TIMEOUT_SEC); + $payload = $payloadTemplate === '' ? json_encode(['case' => $case], JSON_THROW_ON_ERROR) : $this->renderTemplate($payloadTemplate, $case); + $timeoutSec = (int) ($actionConfig['timeoutSec'] ?? self::DEFAULT_TIMEOUT_SEC); $preview = [ 'url' => $url, @@ -111,12 +109,13 @@ public function handle(array $actionConfig, array $case, array $transitionContex ] ); return ActionResult::failure($errorCode, $preview); - } + }//end try $statusCode = (int) $response->getStatusCode(); if ($statusCode >= 500) { return ActionResult::failure('webhook_http_5xx', $preview); } + if ($statusCode >= 400) { return ActionResult::failure('webhook_http_4xx', $preview); } @@ -133,7 +132,7 @@ public function handle(array $actionConfig, array $case, array $transitionContex ] ); return ActionResult::failure('webhook_dispatch_failed'); - } + }//end try }//end handle() /** @@ -153,17 +152,20 @@ private function resolveUrl(array $config, array $context): string // Tenant secret store lookup will land with the secret-store // change; meanwhile we honour an inline `urlSlug` => `url` map // on the action config itself for early adoption. - $slug = (string) $config['urlSlug']; + $slug = (string) $config['urlSlug']; $tenant = (string) ($context['tenantId'] ?? ''); - $map = (array) ($config['urlMap'] ?? []); + $map = (array) ($config['urlMap'] ?? []); if (isset($map[$tenant][$slug]) === true) { return (string) $map[$tenant][$slug]; } + if (isset($map[$slug]) === true) { return (string) $map[$slug]; } + // Fall through — `url` may still be set for legacy inline configs. } + return (string) ($config['url'] ?? ''); }//end resolveUrl() @@ -180,9 +182,11 @@ private function classifyHttpException(\Throwable $e): string if (str_contains($message, 'timeout') === true || str_contains($message, 'timed out') === true) { return 'webhook_timeout'; } + if (str_contains($message, 'could not resolve host') === true || str_contains($message, 'name resolution') === true) { return 'webhook_dns_failure'; } + return 'webhook_network_error'; }//end classifyHttpException() }//end class diff --git a/lib/Service/Actions/CreateDocumentHandler.php b/lib/Service/Actions/CreateDocumentHandler.php index 060b47da..c24539eb 100644 --- a/lib/Service/Actions/CreateDocumentHandler.php +++ b/lib/Service/Actions/CreateDocumentHandler.php @@ -66,12 +66,12 @@ public function type(): string public function handle(array $actionConfig, array $case, array $transitionContext): ActionResult { try { - $templateSlug = (string) ($actionConfig['templateSlug'] ?? ''); - $outputName = $this->renderTemplate( + $templateSlug = (string) ($actionConfig['templateSlug'] ?? ''); + $outputName = $this->renderTemplate( (string) ($actionConfig['outputName'] ?? 'document.pdf'), $case ); - $mergeFields = (array) ($actionConfig['mergeFields'] ?? []); + $mergeFields = (array) ($actionConfig['mergeFields'] ?? []); $renderedFields = []; foreach ($mergeFields as $key => $tpl) { $renderedFields[(string) $key] = $this->renderTemplate((string) $tpl, $case); @@ -122,7 +122,7 @@ public function handle(array $actionConfig, array $case, array $transitionContex ] ); return ActionResult::failure('document_create_failed'); - } + }//end try }//end handle() /** diff --git a/lib/Service/Actions/HandlesTemplates.php b/lib/Service/Actions/HandlesTemplates.php index 787ec993..27a99d93 100644 --- a/lib/Service/Actions/HandlesTemplates.php +++ b/lib/Service/Actions/HandlesTemplates.php @@ -57,18 +57,21 @@ protected function renderTemplate(string $template, array $case): string return (string) preg_replace_callback( '/\{\{\s*([a-zA-Z0-9_.]+)\s*\}\}/', static function (array $match) use ($context): string { - $path = explode('.', $match[1]); + $path = explode('.', $match[1]); $cursor = $context; foreach ($path as $segment) { if (is_array($cursor) === true && array_key_exists($segment, $cursor) === true) { $cursor = $cursor[$segment]; continue; } + return ''; } + if (is_scalar($cursor) === true) { return (string) $cursor; } + return ''; }, $template @@ -105,9 +108,11 @@ protected function resolveRecipient(string $recipientRef, array $case): string if (is_array($value) === true) { return (string) ($value['email'] ?? ''); } + if (is_scalar($value) === true) { return (string) $value; } + return ''; }//end resolveRecipient() }//end trait diff --git a/lib/Service/Actions/MergeTemplateHandler.php b/lib/Service/Actions/MergeTemplateHandler.php index 9b4ba83f..cb3f760a 100644 --- a/lib/Service/Actions/MergeTemplateHandler.php +++ b/lib/Service/Actions/MergeTemplateHandler.php @@ -97,7 +97,7 @@ public function handle(array $actionConfig, array $case, array $transitionContex 'register', '' ); - $schema = $this->appConfig->getValueString( + $schema = $this->appConfig->getValueString( Application::APP_ID, 'case_schema', '' @@ -125,7 +125,7 @@ public function handle(array $actionConfig, array $case, array $transitionContex ] ); return ActionResult::failure('merge_template_failed'); - } + }//end try }//end handle() /** diff --git a/lib/Service/Actions/NotifyRoleHandler.php b/lib/Service/Actions/NotifyRoleHandler.php index abc2dd7d..a412d3b0 100644 --- a/lib/Service/Actions/NotifyRoleHandler.php +++ b/lib/Service/Actions/NotifyRoleHandler.php @@ -73,7 +73,7 @@ public function handle(array $actionConfig, array $case, array $transitionContex ); $recipients = $this->resolveRoleMembers($roleSlug, $case); - $preview = [ + $preview = [ 'roleSlug' => $roleSlug, 'recipients' => $recipients, 'message' => $message, @@ -110,7 +110,7 @@ public function handle(array $actionConfig, array $case, array $transitionContex ] ); return ActionResult::failure('notify_role_failed'); - } + }//end try }//end handle() /** @@ -135,6 +135,7 @@ private function resolveRoleMembers(string $roleSlug, array $case): array if (is_string($single) === true && $single !== '') { return [$single]; } + if (is_array($single) === true) { $id = (string) ($single['id'] ?? ($single['userId'] ?? '')); if ($id !== '') { @@ -143,7 +144,7 @@ private function resolveRoleMembers(string $roleSlug, array $case): array } $multiKey = $roleSlug.'Members'; - $multi = ($case[$multiKey] ?? null); + $multi = ($case[$multiKey] ?? null); if (is_array($multi) === true) { $out = []; foreach ($multi as $member) { @@ -156,6 +157,7 @@ private function resolveRoleMembers(string $roleSlug, array $case): array } } } + return $out; } diff --git a/lib/Service/Actions/ScheduleReminderHandler.php b/lib/Service/Actions/ScheduleReminderHandler.php index 3cb4e2f9..2ea7a656 100644 --- a/lib/Service/Actions/ScheduleReminderHandler.php +++ b/lib/Service/Actions/ScheduleReminderHandler.php @@ -85,7 +85,7 @@ public function handle(array $actionConfig, array $case, array $transitionContex $case ); - $fireAt = $this->computeFireTime($offsetIso); + $fireAt = $this->computeFireTime($offsetIso); $preview = [ 'offsetIso8601' => $offsetIso, 'fireAtIso' => $fireAt === null ? null : $fireAt->format(\DateTimeInterface::ATOM), @@ -121,7 +121,7 @@ public function handle(array $actionConfig, array $case, array $transitionContex ] ); return ActionResult::failure('schedule_reminder_failed'); - } + }//end try }//end handle() /** @@ -136,11 +136,13 @@ private function computeFireTime(string $offsetIso): ?\DateTimeImmutable if ($offsetIso === '') { return null; } + try { $interval = new \DateInterval($offsetIso); } catch (\Throwable $e) { return null; } + return (new \DateTimeImmutable('now'))->add($interval); }//end computeFireTime() }//end class diff --git a/lib/Service/Actions/SendEmailHandler.php b/lib/Service/Actions/SendEmailHandler.php index 66d9b6dd..7d20e05b 100644 --- a/lib/Service/Actions/SendEmailHandler.php +++ b/lib/Service/Actions/SendEmailHandler.php @@ -68,11 +68,11 @@ public function type(): string public function handle(array $actionConfig, array $case, array $transitionContext): ActionResult { try { - $subject = $this->renderTemplate( + $subject = $this->renderTemplate( (string) ($actionConfig['subjectTemplate'] ?? ''), $case ); - $body = $this->renderTemplate( + $body = $this->renderTemplate( (string) ($actionConfig['bodyTemplate'] ?? ''), $case ); @@ -115,7 +115,7 @@ public function handle(array $actionConfig, array $case, array $transitionContex ] ); return ActionResult::failure('email_dispatch_failed'); - } + }//end try }//end handle() /** diff --git a/lib/Service/AdviceService.php b/lib/Service/AdviceService.php index 34a99351..e839ede1 100644 --- a/lib/Service/AdviceService.php +++ b/lib/Service/AdviceService.php @@ -84,7 +84,7 @@ public function __construct( * * @throws \RuntimeException When OpenRegister unavailable / invalid status */ - public function transitionStatus(string $adviceId, string $to, array $payload = []): array + public function transitionStatus(string $adviceId, string $to, array $payload=[]): array { if (in_array($to, self::VALID_STATUSES, true) === false) { throw new \RuntimeException('Invalid advice status'); @@ -413,7 +413,7 @@ private function sendUserNotification( string $userId, string $subject, string $objectId, - string $message = '', + string $message='', ): void { try { $notification = $this->notificationManager->createNotification(); diff --git a/lib/Service/Bezwaar/AdvisoryCommitteeService.php b/lib/Service/Bezwaar/AdvisoryCommitteeService.php index 434e9d5a..2fed08dc 100644 --- a/lib/Service/Bezwaar/AdvisoryCommitteeService.php +++ b/lib/Service/Bezwaar/AdvisoryCommitteeService.php @@ -70,9 +70,9 @@ class AdvisoryCommitteeService * in-deliberation per Awb Art. 7:13(7). */ private const ALLOWED_TRANSITIONS = [ - 'assigned' => ['in-deliberation'], - 'in-deliberation' => ['advice-issued', 'niet-ontvankelijk'], - 'advice-issued' => [], + 'assigned' => ['in-deliberation'], + 'in-deliberation' => ['advice-issued', 'niet-ontvankelijk'], + 'advice-issued' => [], 'niet-ontvankelijk' => [], ]; @@ -126,15 +126,15 @@ public function __construct( public function assignToCommittee( string $bezwaarId, string $commissieId, - array $payload = [] + array $payload=[] ): array { $objectService = $this->settingsService->getObjectService(); if ($objectService === null) { throw new RuntimeException('OpenRegister is not available'); } - $register = $this->settingsService->getConfigValue(key: 'register'); - $requestSchema = $this->settingsService->getConfigValue( + $register = $this->settingsService->getConfigValue(key: 'register'); + $requestSchema = $this->settingsService->getConfigValue( key: 'bac_advice_request_schema' ); $committeeSchema = $this->settingsService->getConfigValue( @@ -222,7 +222,7 @@ public function assignToCommittee( public function transitionAdviceStatus( string $requestId, string $newStatus, - array $payload = [] + array $payload=[] ): array { if (in_array($newStatus, self::VALID_STATUSES, true) === false) { throw new RuntimeException('Invalid BAC advice status'); @@ -247,7 +247,7 @@ public function transitionAdviceStatus( throw new RuntimeException('Advice request not found'); } - $from = (string) ($current['status'] ?? 'assigned'); + $from = (string) ($current['status'] ?? 'assigned'); $allowed = self::ALLOWED_TRANSITIONS[$from] ?? []; if (in_array($newStatus, $allowed, true) === false) { @@ -300,8 +300,8 @@ public function transitionAdviceStatus( 'Panel member conflict (Awb Art. 7:13 lid 3): ' .$independence['reason'] ); - } - } + }//end if + }//end if // Guard: in-deliberation → advice-issued requires the structured // advice content (REQ-BAC-4). @@ -321,19 +321,17 @@ public function transitionAdviceStatus( $userId = $this->resolveUserId(); // Compose the update. - $update = $payload; + $update = $payload; $update['status'] = $newStatus; if ($newStatus === 'advice-issued' || $newStatus === 'niet-ontvankelijk') { $update['adviceIssuedAt'] = (new \DateTimeImmutable()) ->format(\DateTimeInterface::ATOM); - $auditEvent = 'advice-signed-by-chair'; - $auditPayload = [ + $auditEvent = 'advice-signed-by-chair'; + $auditPayload = [ 'chair' => $userId, - 'signatureEvidence' => $update['signatureEvidence'] - ?? ($current['signatureEvidence'] ?? null), - 'conclusion' => $update['conclusion'] - ?? ($current['conclusion'] ?? null), + 'signatureEvidence' => $update['signatureEvidence'] ?? ($current['signatureEvidence'] ?? null), + 'conclusion' => $update['conclusion'] ?? ($current['conclusion'] ?? null), ]; $update['auditTrail'] = $this->appendAudit( existing: (array) ($current['auditTrail'] ?? []), @@ -436,8 +434,8 @@ public function recordCouncilDeviation( existing: (array) ($current['auditTrail'] ?? []), event: 'council-deviation-recorded', payload: [ - 'besluit' => $besluitId, - 'motivatie' => $motivatieRef, + 'besluit' => $besluitId, + 'motivatie' => $motivatieRef, ], ); @@ -452,7 +450,7 @@ public function recordCouncilDeviation( 'Procest BAC: failed to record council deviation: ' .$e->getMessage() ); - } + }//end try }//end recordCouncilDeviation() /** @@ -524,9 +522,7 @@ private function checkPanelIndependence( $objectionSchema, ['case' => $caseId] ); - $objection = (is_array($objections) && $objections !== []) - ? $objections[0] - : null; + $objection = (is_array($objections) && $objections !== []) ? $objections[0] : null; if (is_array($objection) === false) { return ['ok' => true, 'member' => null, 'reason' => null]; } @@ -546,9 +542,7 @@ private function checkPanelIndependence( } $steller = (string) ( - $decision['@self']['owner'] - ?? ($decision['createdBy'] - ?? ($decision['steller'] ?? '')) + $decision['@self']['owner'] ?? ($decision['createdBy'] ?? ($decision['steller'] ?? '')) ); if ($steller === '') { return ['ok' => true, 'member' => null, 'reason' => null]; @@ -569,7 +563,7 @@ private function checkPanelIndependence( 'Procest BAC: independence check error: '.$e->getMessage() ); // Fail-open here is intentional: do not block on infra issues. - } + }//end try return ['ok' => true, 'member' => null, 'reason' => null]; }//end checkPanelIndependence() diff --git a/lib/Service/Bezwaar/BeroepService.php b/lib/Service/Bezwaar/BeroepService.php index 454a6ab9..27a82a00 100644 --- a/lib/Service/Bezwaar/BeroepService.php +++ b/lib/Service/Bezwaar/BeroepService.php @@ -134,22 +134,23 @@ public function __construct( * record. The OpenRegister audit trail captures actor + change diff * automatically; this method writes no bespoke audit entries. * - * @param string $caseId UUID of the procest case - * wrapping the beroep - * @param string $sourceBezwaarId UUID of the bezwaar - * lifecycle record being - * escalated + * @param string $caseId UUID of the procest case + * wrapping the beroep + * @param string $sourceBezwaarId UUID of the bezwaar + * lifecycle record + * being escalated * @param string $contestedDecisionId UUID of the * appealDecision being * contested - * @param string $filingDate ISO date the - * beroepschrift was filed - * at the court - * @param array $payload Optional extra fields - * (courtReference, - * competentCourt, - * responsibleChamber, - * voorzieningRequested) + * @param string $filingDate ISO date the + * beroepschrift + * was filed at + * the court + * @param array $payload Optional extra fields + * (courtReference, + * competentCourt, + * responsibleChamber, + * voorzieningRequested) * * @return array The created beroep record * @@ -162,14 +163,14 @@ public function register( string $sourceBezwaarId, string $contestedDecisionId, string $filingDate, - array $payload = [] + array $payload=[] ): array { $objectService = $this->settingsService->getObjectService(); if ($objectService === null) { throw new RuntimeException('OpenRegister is not available'); } - $register = $this->settingsService->getConfigValue(key: 'register'); + $register = $this->settingsService->getConfigValue(key: 'register'); $beroepSchema = $this->settingsService->getConfigValue( key: 'beroep_schema' ); @@ -203,7 +204,7 @@ public function register( $record = array_merge( [ - 'responsibleChamber' => 'enkelvoudig', + 'responsibleChamber' => 'enkelvoudig', 'voorzieningRequested' => false, ], $payload, @@ -234,8 +235,8 @@ public function register( * curates it via existing dossier tooling; this method records the * linkage with a computed deadline of requestedAt + P4W. * - * @param string $beroepId UUID of the beroep - * @param string $requestedAt ISO date the rechtbank issued the request + * @param string $beroepId UUID of the beroep + * @param string $requestedAt ISO date the rechtbank issued the request * @param string|null $dossierBundle Optional NC file ID / dossier ref * * @return array The updated beroep record @@ -246,7 +247,7 @@ public function register( public function addFileInspectionRequest( string $beroepId, string $requestedAt, - ?string $dossierBundle = null + ?string $dossierBundle=null ): array { $objectService = $this->settingsService->getObjectService(); if ($objectService === null) { @@ -280,7 +281,7 @@ public function addFileInspectionRequest( $entry['dossierBundle'] = $dossierBundle; } - $requests = (array) ($current['fileInspectionRequests'] ?? []); + $requests = (array) ($current['fileInspectionRequests'] ?? []); $requests[] = $entry; try { @@ -323,7 +324,7 @@ public function recordJudgment( string $beroepId, string $outcome, string $judgmentDate, - ?string $judgmentDocument = null + ?string $judgmentDocument=null ): array { if (in_array($outcome, self::VALID_OUTCOMES, true) === false) { throw new RuntimeException('Invalid judgment outcome'); @@ -405,8 +406,8 @@ public function executeCascade(string $beroepId, string $action): array throw new RuntimeException('OpenRegister is not available'); } - $register = $this->settingsService->getConfigValue(key: 'register'); - $beroepSchema = $this->settingsService->getConfigValue( + $register = $this->settingsService->getConfigValue(key: 'register'); + $beroepSchema = $this->settingsService->getConfigValue( key: 'beroep_schema' ); $bezwaarSchema = $this->settingsService->getConfigValue( @@ -457,9 +458,9 @@ public function executeCascade(string $beroepId, string $action): array ); } } - } - } - } + }//end if + }//end if + }//end if if ($action === 'new_primary_decision') { // The follow-up primary-decision case is opened via the diff --git a/lib/Service/Bezwaar/DecisionService.php b/lib/Service/Bezwaar/DecisionService.php index 637d934f..4bf0eaa9 100644 --- a/lib/Service/Bezwaar/DecisionService.php +++ b/lib/Service/Bezwaar/DecisionService.php @@ -287,7 +287,7 @@ public function publish(string $decisionId): array $totalAmount = $this->computeProceskostenTotal(decision: $current); if ($totalAmount !== null) { $proceskosten = (array) ($current['proceskostenvergoeding'] ?? []); - $proceskosten['totalAmount'] = $totalAmount; + $proceskosten['totalAmount'] = $totalAmount; $patch['proceskostenvergoeding'] = $proceskosten; } @@ -414,8 +414,8 @@ private function assertPublishable(array $decision): void // set and the decision deviates. $advisory = (string) ($decision['advisoryOpinion'] ?? ''); if ($advisory !== '') { - $follows = (bool) ($decision['followsAdvice'] ?? true); - $reason = (string) ($decision['deviationRationale'] ?? ''); + $follows = (bool) ($decision['followsAdvice'] ?? true); + $reason = (string) ($decision['deviationRationale'] ?? ''); if ($follows === false && $reason === '') { throw new RuntimeException( 'deviationRationale is required when followsAdvice is ' diff --git a/lib/Service/Bezwaar/HearingService.php b/lib/Service/Bezwaar/HearingService.php index b3a5b60f..5daec988 100644 --- a/lib/Service/Bezwaar/HearingService.php +++ b/lib/Service/Bezwaar/HearingService.php @@ -78,14 +78,14 @@ class HearingService * hearingSession (REQ-BH-8). Values are the canonical tags every * downstream consumer (beroep export, accessibility report) reads. */ - public const TAG_SCHEDULED = 'awb-art-7:2'; - public const TAG_INVITATION_SENT = 'awb-art-7:2'; - public const TAG_WAIVER = 'awb-art-7:3'; - public const TAG_INSPECTION = 'awb-art-7:4'; + public const TAG_SCHEDULED = 'awb-art-7:2'; + public const TAG_INVITATION_SENT = 'awb-art-7:2'; + public const TAG_WAIVER = 'awb-art-7:3'; + public const TAG_INSPECTION = 'awb-art-7:4'; public const TAG_CONFIDENTIAL_WITHELD = 'awb-art-7:6'; - public const TAG_VERSLAG = 'awb-art-7:7'; - public const TAG_BAC_REFERRAL = 'awb-art-7:13'; - public const TAG_RECORDING_CONSENT = 'avg-art-6'; + public const TAG_VERSLAG = 'awb-art-7:7'; + public const TAG_BAC_REFERRAL = 'awb-art-7:13'; + public const TAG_RECORDING_CONSENT = 'avg-art-6'; /** * Constructor. @@ -125,7 +125,7 @@ public function schedule( string $scheduledDate, string $chairpersonId, array $invitees, - array $payload = [] + array $payload=[] ): array { $objectService = $this->settingsService->getObjectService(); if ($objectService === null) { @@ -156,9 +156,7 @@ public function schedule( today: $now, ); - $available = isset($payload['inspectionAvailableFrom']) === true - ? $this->parseDate((string) $payload['inspectionAvailableFrom']) - : $now->setTime(0, 0, 0); + $available = isset($payload['inspectionAvailableFrom']) === true ? $this->parseDate((string) $payload['inspectionAvailableFrom']) : $now->setTime(0, 0, 0); if ($available > $deadline) { // Per design.md: inspectionAvailableFrom must be ≤ inspectionDeadline. @@ -167,9 +165,9 @@ public function schedule( $record = array_merge( [ - 'location' => null, + 'location' => null, 'videoCallUrl' => null, - 'members' => [], + 'members' => [], ], $payload, [ @@ -186,8 +184,7 @@ public function schedule( 'inspectionDeadline' => $deadline->format('Y-m-d'), 'status' => 'gepland', 'hearingWaived' => false, - 'recordingConsent' => $payload['recordingConsent'] - ?? 'not_requested', + 'recordingConsent' => $payload['recordingConsent'] ?? 'not_requested', ] ); @@ -196,8 +193,8 @@ public function schedule( event: 'hearing-scheduled', tag: self::TAG_SCHEDULED, payload: [ - 'case' => $caseId, - 'scheduledDate' => $record['scheduledDate'], + 'case' => $caseId, + 'scheduledDate' => $record['scheduledDate'], 'inspectionDeadline' => $record['inspectionDeadline'], ], ); @@ -229,7 +226,7 @@ public function schedule( public function waive( string $caseId, string $reason, - array $payload = [] + array $payload=[] ): array { $reason = trim($reason); if ($reason === '') { @@ -259,8 +256,7 @@ public function waive( [ 'case' => $caseId, 'scheduledDate' => $now->format(\DateTimeInterface::ATOM), - 'chairperson' => $payload['chairperson'] - ?? ($payload['chairpersonId'] ?? 'system'), + 'chairperson' => $payload['chairperson'] ?? ($payload['chairpersonId'] ?? 'system'), 'invitees' => $payload['invitees'] ?? [], 'inspectionAvailableFrom' => $now->format('Y-m-d'), 'inspectionDeadline' => $now->format('Y-m-d'), @@ -298,8 +294,8 @@ public function waive( * any correction SHALL carry a non-empty correctionReason that is * logged as an awb-art-7:7 audit entry. * - * @param string $sessionId UUID of the hearingSession - * @param array> $entries Attendance entries: each {invitee, present, arrivalTime?, correctionReason?} + * @param string $sessionId UUID of the hearingSession + * @param array> $entries Attendance entries: each {invitee, present, arrivalTime?, correctionReason?} * * @return array The updated hearingSession record * @@ -330,19 +326,17 @@ public function recordAttendance( throw new RuntimeException('Hearing session not found'); } - $now = new \DateTimeImmutable(); - $scheduledRaw = (string) ($current['scheduledDate'] ?? ''); - $scheduled = $scheduledRaw !== '' - ? $this->parseDateTime($scheduledRaw) - : $now; - $freezeAt = $scheduled->modify( + $now = new \DateTimeImmutable(); + $scheduledRaw = (string) ($current['scheduledDate'] ?? ''); + $scheduled = $scheduledRaw !== '' ? $this->parseDateTime($scheduledRaw) : $now; + $freezeAt = $scheduled->modify( '+'.self::ATTENDANCE_GRACE_HOURS.' hour' ); - $isFrozen = $now > $freezeAt; + $isFrozen = $now > $freezeAt; - $existing = (array) ($current['attendance'] ?? []); - $merged = $existing; - $audit = (array) ($current['auditTrail'] ?? []); + $existing = (array) ($current['attendance'] ?? []); + $merged = $existing; + $audit = (array) ($current['auditTrail'] ?? []); foreach ($entries as $entry) { if (is_array($entry) === false) { @@ -371,7 +365,7 @@ public function recordAttendance( } $merged[] = $entry; - } + }//end foreach $update = [ 'attendance' => $merged, @@ -428,12 +422,10 @@ public function addMinutes( } $summary = (string) ( - $payload['minutesSummary'] - ?? ($current['minutesSummary'] ?? '') + $payload['minutesSummary'] ?? ($current['minutesSummary'] ?? '') ); $document = (string) ( - $payload['minutesDocument'] - ?? ($current['minutesDocument'] ?? '') + $payload['minutesDocument'] ?? ($current['minutesDocument'] ?? '') ); if (trim($summary) === '' && trim($document) === '') { @@ -449,8 +441,7 @@ public function addMinutes( && (string) $payload['audioRecording'] !== '' ) { $consent = (string) ( - $payload['recordingConsent'] - ?? ($current['recordingConsent'] ?? 'not_requested') + $payload['recordingConsent'] ?? ($current['recordingConsent'] ?? 'not_requested') ); if ($consent !== 'granted') { $audit = $this->appendAudit( @@ -479,8 +470,8 @@ public function addMinutes( throw new RuntimeException( 'Bezwaarmaker heeft geen toestemming gegeven voor audio-opname' ); - } - } + }//end if + }//end if $update = [ 'minutesSummary' => $summary !== '' ? $summary : null, @@ -583,8 +574,8 @@ public function seedDefaultHearing(string $bezwaarId): ?array chairpersonId: 'system', invitees: [ [ - 'role' => 'bezwaarmaker', - 'channel' => 'email', + 'role' => 'bezwaarmaker', + 'channel' => 'email', 'accessibilityNeeds' => [], ], ], diff --git a/lib/Service/CaseSharingService.php b/lib/Service/CaseSharingService.php index cf5c1566..42301b72 100644 --- a/lib/Service/CaseSharingService.php +++ b/lib/Service/CaseSharingService.php @@ -505,11 +505,11 @@ public function storeExternalDocument(string $caseId, string $shareId, array $up ); return [ - 'caseId' => $caseId, - 'shareId' => $shareId, - 'name' => ($uploadedFile['name'] ?? 'unknown'), - 'size' => ($uploadedFile['size'] ?? 0), - 'uploadedAt' => (new \DateTime())->format('c'), + 'caseId' => $caseId, + 'shareId' => $shareId, + 'name' => ($uploadedFile['name'] ?? 'unknown'), + 'size' => ($uploadedFile['size'] ?? 0), + 'uploadedAt' => (new \DateTime())->format('c'), ]; }//end storeExternalDocument() }//end class diff --git a/lib/Service/Inspection/ChecklistService.php b/lib/Service/Inspection/ChecklistService.php index 568e6722..c9f9213d 100644 --- a/lib/Service/Inspection/ChecklistService.php +++ b/lib/Service/Inspection/ChecklistService.php @@ -51,7 +51,7 @@ * * @psalm-suppress UnusedClass * - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) — orchestrates ObjectService + IUserSession + follow-up dispatch + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) — orchestrates ObjectService + IUserSession + follow-up dispatch * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) — guarded by validateResponse branches per response type */ class ChecklistService @@ -94,8 +94,8 @@ class ChecklistService /** * Follow-up types matching the failureAction.type enum. */ - public const FOLLOWUP_HERINSPECTIE = 'herinspectie'; - public const FOLLOWUP_HANDHAVINGSTAAK = 'handhavingstaak'; + public const FOLLOWUP_HERINSPECTIE = 'herinspectie'; + public const FOLLOWUP_HANDHAVINGSTAAK = 'handhavingstaak'; public const FOLLOWUP_DOCUMENT_VERZOEK = 'documentVerzoek'; public const FOLLOWUP_GEEN = 'geen'; @@ -116,8 +116,8 @@ public function __construct( /** * Start a new run against a template, freezing the snapshot and inspector identity. * - * @param string $templateId Template UUID - * @param string $caseId Parent case UUID + * @param string $templateId Template UUID + * @param string $caseId Parent case UUID * @param string|null $inspectionId Optional parent mobiel-inspectie session id * * @return array The persisted run @@ -125,7 +125,7 @@ public function __construct( * @throws RuntimeException When configuration is missing, the template * cannot be loaded, or persistence fails. */ - public function createRun(string $templateId, string $caseId, ?string $inspectionId = null): array + public function createRun(string $templateId, string $caseId, ?string $inspectionId=null): array { [$objectService, $register] = $this->bootstrap(); $templateSchema = $this->requireConfig(key: 'inspection_checklist_template_schema'); @@ -281,13 +281,13 @@ public function aggregateResult(array $responses, array $snapshot): string continue; } - $itemId = (string) ($response['itemId'] ?? ''); - $item = $itemsByOrder[$itemId] ?? null; + $itemId = (string) ($response['itemId'] ?? ''); + $item = $itemsByOrder[$itemId] ?? null; $verdict = $this->classifyResponse(response: $response, item: $item); if ($verdict === 'fail') { $fails++; - } elseif ($verdict === 'skip') { + } else if ($verdict === 'skip') { $skipped++; } } @@ -398,9 +398,9 @@ public function dispatchFollowUps(array $run): array [$objectService, $register] = $this->bootstrap(); $taskSchema = (string) $this->settingsService->getConfigValue('task_schema'); - $created = []; - $runId = (string) ($run['id'] ?? ''); - $caseId = (string) ($run['case'] ?? ''); + $created = []; + $runId = (string) ($run['id'] ?? ''); + $caseId = (string) ($run['case'] ?? ''); $submittedAt = (string) ($run['submittedAt'] ?? (new DateTimeImmutable())->format(DateTimeInterface::ATOM)); foreach ($responses as $response) { @@ -426,7 +426,7 @@ public function dispatchFollowUps(array $run): array } $deadlineDays = (int) ($action['deadlineDays'] ?? 0); - $deadline = null; + $deadline = null; if ($deadlineDays > 0) { $deadline = (new DateTimeImmutable($submittedAt)) ->modify('+'.$deadlineDays.' days') @@ -434,11 +434,11 @@ public function dispatchFollowUps(array $run): array } $task = [ - 'case' => $caseId, - 'title' => $this->describeFollowUp(type: $actionType, item: $item), - 'description' => 'Follow-up automatically created from inspection checklist run', - 'sourceRun' => $runId, - 'sourceItem' => $itemId, + 'case' => $caseId, + 'title' => $this->describeFollowUp(type: $actionType, item: $item), + 'description' => 'Follow-up automatically created from inspection checklist run', + 'sourceRun' => $runId, + 'sourceItem' => $itemId, 'followUpType' => $actionType, ]; @@ -468,7 +468,7 @@ public function dispatchFollowUps(array $run): array } else { $created[] = $task; } - } + }//end foreach return $created; }//end dispatchFollowUps() @@ -613,13 +613,13 @@ private function classifyResponse(array $response, ?array $item): string private function resolvePrimaryFollowUp(array $responses, array $snapshot): ?string { $priority = [ - self::FOLLOWUP_HANDHAVINGSTAAK => 3, - self::FOLLOWUP_HERINSPECTIE => 2, + self::FOLLOWUP_HANDHAVINGSTAAK => 3, + self::FOLLOWUP_HERINSPECTIE => 2, self::FOLLOWUP_DOCUMENT_VERZOEK => 1, - self::FOLLOWUP_GEEN => 0, + self::FOLLOWUP_GEEN => 0, ]; - $items = $this->indexItemsBySnapshot(snapshot: $snapshot); + $items = $this->indexItemsBySnapshot(snapshot: $snapshot); $winner = null; $best = -1; @@ -649,7 +649,7 @@ private function resolvePrimaryFollowUp(array $responses, array $snapshot): ?str $best = $rank; $winner = $type; } - } + }//end foreach return $winner; }//end resolvePrimaryFollowUp() @@ -674,7 +674,7 @@ private function indexItemsBySnapshot(array $snapshot): array continue; } - $id = (string) ($item['id'] ?? ($item['order'] ?? (string) $idx)); + $id = (string) ($item['id'] ?? ($item['order'] ?? (string) $idx)); $out[$id] = $item; } }; diff --git a/lib/Service/LocationService.php b/lib/Service/LocationService.php index cfa14ec0..2b840090 100644 --- a/lib/Service/LocationService.php +++ b/lib/Service/LocationService.php @@ -117,13 +117,13 @@ public function validate(array $payload): array $errors[] = 'case.required'; } - $hasLatLng = ( + $hasLatLng = ( isset($payload['latitude']) === true && isset($payload['longitude']) === true && is_numeric($payload['latitude']) === true && is_numeric($payload['longitude']) === true ); - $hasBag = ( + $hasBag = ( isset($payload['nummeraanduidingId']) === true && (string) $payload['nummeraanduidingId'] !== '' ); @@ -133,35 +133,35 @@ public function validate(array $payload): array ); switch ($source) { - case 'bag': - if ($hasBag === false) { - $errors[] = 'nummeraanduidingId.required'; - } - break; - - case 'pdok-reverse': - if ($hasLatLng === false) { - $errors[] = 'latitude-longitude.required'; - } - break; - - case 'gps': - if ($hasLatLng === false) { - $errors[] = 'latitude-longitude.required'; - } - - if (isset($payload['accuracyRadius']) === false - || is_numeric($payload['accuracyRadius']) === false - ) { - $errors[] = 'accuracyRadius.required'; - } - break; - - case 'free': - if ($hasFormatted === false && $hasLatLng === false) { - $errors[] = 'formattedAddress-or-coordinates.required'; - } - break; + case 'bag': + if ($hasBag === false) { + $errors[] = 'nummeraanduidingId.required'; + } + break; + + case 'pdok-reverse': + if ($hasLatLng === false) { + $errors[] = 'latitude-longitude.required'; + } + break; + + case 'gps': + if ($hasLatLng === false) { + $errors[] = 'latitude-longitude.required'; + } + + if (isset($payload['accuracyRadius']) === false + || is_numeric($payload['accuracyRadius']) === false + ) { + $errors[] = 'accuracyRadius.required'; + } + break; + + case 'free': + if ($hasFormatted === false && $hasLatLng === false) { + $errors[] = 'formattedAddress-or-coordinates.required'; + } + break; }//end switch // Universal anchor rule: every location MUST have either a BAG @@ -237,10 +237,8 @@ public function reverseGeocode(float $latitude, float $longitude): ?array return null; } - $best = $docs[0]; - $distance = isset($best['afstand']) === true && is_numeric($best['afstand']) === true - ? (float) $best['afstand'] - : null; + $best = $docs[0]; + $distance = isset($best['afstand']) === true && is_numeric($best['afstand']) === true ? (float) $best['afstand'] : null; if ($distance !== null && $distance > (float) self::REVERSE_MAX_DISTANCE_M) { return null; @@ -256,9 +254,7 @@ public function reverseGeocode(float $latitude, float $longitude): ?array $nummeraanduidingId = (string) $best['id']; } - $formattedAddress = isset($best['weergavenaam']) === true - ? (string) $best['weergavenaam'] - : ''; + $formattedAddress = isset($best['weergavenaam']) === true ? (string) $best['weergavenaam'] : ''; if ($nummeraanduidingId === '' && $formattedAddress === '') { return null; diff --git a/lib/Service/ParafeerActieService.php b/lib/Service/ParafeerActieService.php index 4af3f3f4..81c76507 100644 --- a/lib/Service/ParafeerActieService.php +++ b/lib/Service/ParafeerActieService.php @@ -168,7 +168,7 @@ private function dispatchTransition( ?string $step, string $actor, string $actorRole, - ?string $reason = null, + ?string $reason=null, ): void { try { $this->eventDispatcher->dispatchTyped( @@ -190,7 +190,7 @@ private function dispatchTransition( 'exception' => $e->getMessage(), ], ); - } + }//end try }//end dispatchTransition() /** diff --git a/lib/Service/ParafeerRouteService.php b/lib/Service/ParafeerRouteService.php index 6475a75e..684a9483 100644 --- a/lib/Service/ParafeerRouteService.php +++ b/lib/Service/ParafeerRouteService.php @@ -115,7 +115,7 @@ private function dispatchTransition( ?string $step, string $actor, string $actorRole, - ?string $reason = null, + ?string $reason=null, ): void { try { $this->eventDispatcher->dispatchTyped( @@ -137,7 +137,7 @@ private function dispatchTransition( 'exception' => $e->getMessage(), ], ); - } + }//end try }//end dispatchTransition() /** @@ -518,7 +518,7 @@ private function advanceVoorstel( ); return $voorstel; - } + }//end if $voorstel['currentStep'] = $nextStep; $voorstel = $this->toArray(value: $objectService->saveObject($register, $voorstelSchema, $voorstel)); diff --git a/lib/Service/Parafering/AuditTrailService.php b/lib/Service/Parafering/AuditTrailService.php index f2c6718c..4922f68b 100644 --- a/lib/Service/Parafering/AuditTrailService.php +++ b/lib/Service/Parafering/AuditTrailService.php @@ -175,8 +175,8 @@ public function record( * "Audit entries are append-only" for any UPDATE or DELETE attempt, and * additionally validates INSERT payload shape (enums + hash format). * - * @param array $entry The pending entry - * @param bool $isUpdate True when this is an UPDATE/DELETE (existing id present) + * @param array $entry The pending entry + * @param bool $isUpdate True when this is an UPDATE/DELETE (existing id present) * * @return void * @@ -212,7 +212,7 @@ public function assertAppendOnly(array $entry, bool $isUpdate): void /** * Export the full audit trail for a voorstel as an Archiefwet-aligned envelope. * - * @param string $voorstelId The voorstel UUID/slug + * @param string $voorstelId The voorstel UUID/slug * @param string $voorstelOnderwerp Voorstel onderwerp (for the metadata block) * @param string $exportedBy UID of the auditor performing the export * @@ -274,9 +274,7 @@ static function (array $a, array $b): int { 'voorstel' => $voorstelId, 'voorstelOnderwerp' => $voorstelOnderwerp, 'retentionUntil' => $retentionUntil, - 'selectielijstCategory' => $completed !== null - ? 'Bestuurlijke besluitvorming — bewaartermijn 20 jaar' - : 'Algemene administratieve correspondentie — bewaartermijn 7 jaar', + 'selectielijstCategory' => $completed !== null ? 'Bestuurlijke besluitvorming — bewaartermijn 20 jaar' : 'Algemene administratieve correspondentie — bewaartermijn 7 jaar', 'exportedBy' => $exportedBy, 'entryCount' => count($entries), ], @@ -362,7 +360,7 @@ private function redactIp(string $ip): string ); } } - } + }//end if return ''; }//end redactIp() diff --git a/lib/Service/Pdok/PdokBagService.php b/lib/Service/Pdok/PdokBagService.php index b722fb77..d948f061 100644 --- a/lib/Service/Pdok/PdokBagService.php +++ b/lib/Service/Pdok/PdokBagService.php @@ -409,9 +409,9 @@ private function normaliseFeature(array $feature): array */ private function toCamel(string $snake): string { - $parts = explode(separator: '_', string: $snake); - $first = array_shift(array: $parts); - $tail = array_map(callback: 'ucfirst', array: $parts); + $parts = explode(separator: '_', string: $snake); + $first = array_shift(array: $parts); + $tail = array_map(callback: 'ucfirst', array: $parts); return $first.implode(separator: '', array: $tail); }//end toCamel() }//end class diff --git a/lib/Service/Pdok/PdokLocatieserverService.php b/lib/Service/Pdok/PdokLocatieserverService.php index abc3e8c9..e3d2af4f 100644 --- a/lib/Service/Pdok/PdokLocatieserverService.php +++ b/lib/Service/Pdok/PdokLocatieserverService.php @@ -231,7 +231,7 @@ public function health(): string * normalised full query string so that filtered variants are distinct. * * @param string $method Endpoint suffix (`suggest`, `free`, `lookup`, - * `reverse`). + * `reverse`). * @param array $params Query string parameters. * @param int $ttl Cache TTL in seconds. * @@ -456,9 +456,12 @@ private function recordFailure(int $statusCode): void } $now = time(); - $failures = array_filter(array: $failures, callback: static function (int $ts) use ($now): bool { - return ($now - $ts) <= self::OUTAGE_WINDOW; - }); + $failures = array_filter( + array: $failures, + callback: static function (int $ts) use ($now): bool { + return ($now - $ts) <= self::OUTAGE_WINDOW; + } + ); $failures[] = $now; diff --git a/lib/Service/RoleResolverService.php b/lib/Service/RoleResolverService.php index 1ac037df..7f6048f2 100644 --- a/lib/Service/RoleResolverService.php +++ b/lib/Service/RoleResolverService.php @@ -123,10 +123,12 @@ public function normaliseRule(array $entry): ?array if (is_array($allowedRoles) === true && $allowedRoles !== []) { return [ 'strategy' => self::STRATEGY_OR_SET, - 'roleTypes' => array_values(array_map( + 'roleTypes' => array_values( + array_map( static fn ($value): string => (string) $value, $allowedRoles, - )), + ) + ), ]; } @@ -152,19 +154,21 @@ public function resolve(array $rule, array $case): array ); } - $caseId = (string) ($case['id'] ?? ($case['uuid'] ?? '')); - $cacheKey = $this->cacheKey(rule: $rule, caseId: $caseId); - $cacheHit = ($caseId !== '') ? $this->cache->get($cacheKey) : null; + $caseId = (string) ($case['id'] ?? ($case['uuid'] ?? '')); + $cacheKey = $this->cacheKey(rule: $rule, caseId: $caseId); + $cacheHit = ($caseId !== '') ? $this->cache->get($cacheKey) : null; if (is_array($cacheHit) === true) { - return array_values(array_map( + return array_values( + array_map( static fn ($value): string => (string) $value, $cacheHit, - )); + ) + ); } - $roles = $this->loadCaseRoles($caseId); - $strategy = $this->registry->get($strategyName); - $primary = $strategy->resolve($rule, $case, $roles); + $roles = $this->loadCaseRoles($caseId); + $strategy = $this->registry->get($strategyName); + $primary = $strategy->resolve($rule, $case, $roles); $fallback = (string) ($rule['fallback'] ?? ''); if ($primary === [] && $fallback !== '' && $strategyName !== 'hierarchical') { @@ -183,10 +187,10 @@ public function resolve(array $rule, array $case): array $this->logger->info( 'Procest: routing rule resolved to empty set', [ - 'event' => 'RoleRoutingEmpty', - 'rule' => $rule, - 'caseId' => $caseId, - 'app' => Application::APP_ID, + 'event' => 'RoleRoutingEmpty', + 'rule' => $rule, + 'caseId' => $caseId, + 'app' => Application::APP_ID, ], ); } @@ -269,9 +273,9 @@ private function applyDelegation(array $participants, array $roles): array $visited = [$participant => true]; $hops = 0; while (isset($byUser[$resolved]) === true) { - $role = $byUser[$resolved]; - $from = (string) ($role['delegateFrom'] ?? ''); - $until = (string) ($role['delegateUntil'] ?? ''); + $role = $byUser[$resolved]; + $from = (string) ($role['delegateFrom'] ?? ''); + $until = (string) ($role['delegateUntil'] ?? ''); $delegate = (string) ($role['delegate'] ?? ''); if ($delegate === '' || $from === '' || $until === '') { break; @@ -308,10 +312,10 @@ private function applyDelegation(array $participants, array $roles): array // Per spec: break after exactly one hop. break; } - } + }//end while $result[] = $resolved; - } + }//end foreach return $result; }//end applyDelegation() diff --git a/lib/Service/Routing/RoutingStrategyInterface.php b/lib/Service/Routing/RoutingStrategyInterface.php index c9365157..ea6611ed 100644 --- a/lib/Service/Routing/RoutingStrategyInterface.php +++ b/lib/Service/Routing/RoutingStrategyInterface.php @@ -49,8 +49,9 @@ public function name(): string; * to assign. An empty array means "no eligible assignee" — callers MUST * surface this to the case admin. * - * @param array $rule The routing rule (strategy + parameters) - * @param array $case The case object (id, caseType, …) + * @param array $rule The routing rule (strategy + parameters) + * @param array $case The case object (id, caseType, + * …) * @param array> $roles Role objects bound to the case * * @return array Ordered participant references diff --git a/lib/Service/Routing/Strategy/HierarchicalStrategy.php b/lib/Service/Routing/Strategy/HierarchicalStrategy.php index ec52fb86..bdee5cb0 100644 --- a/lib/Service/Routing/Strategy/HierarchicalStrategy.php +++ b/lib/Service/Routing/Strategy/HierarchicalStrategy.php @@ -48,8 +48,8 @@ public function name(): string * participant set. When all listed roles are empty, fall through to the * optional `fallback` roleType. Returns an empty array when nothing matches. * - * @param array $rule The routing rule - * @param array $case The case object + * @param array $rule The routing rule + * @param array $case The case object * @param array> $roles Roles bound to the case * * @return array diff --git a/lib/Service/Routing/Strategy/LeastLoadedStrategy.php b/lib/Service/Routing/Strategy/LeastLoadedStrategy.php index e2e361cb..17ad2756 100644 --- a/lib/Service/Routing/Strategy/LeastLoadedStrategy.php +++ b/lib/Service/Routing/Strategy/LeastLoadedStrategy.php @@ -51,8 +51,8 @@ public function name(): string * int). Ties are broken by participant order (first match wins). * Returns an empty array when no participants match the rule. * - * @param array $rule The routing rule - * @param array $case The case object (must include `openTaskCountsByParticipant`) + * @param array $rule The routing rule + * @param array $case The case object (must include `openTaskCountsByParticipant`) * @param array> $roles Roles bound to the case * * @return array diff --git a/lib/Service/Routing/Strategy/OrSetStrategy.php b/lib/Service/Routing/Strategy/OrSetStrategy.php index ac68761b..e59a918c 100644 --- a/lib/Service/Routing/Strategy/OrSetStrategy.php +++ b/lib/Service/Routing/Strategy/OrSetStrategy.php @@ -47,8 +47,8 @@ public function name(): string * Union over `roleTypes`. Duplicate participants are collapsed; the order * follows first-match across the supplied role types. * - * @param array $rule The routing rule - * @param array $case The case object + * @param array $rule The routing rule + * @param array $case The case object * @param array> $roles Roles bound to the case * * @return array diff --git a/lib/Service/Routing/Strategy/RoundRobinStrategy.php b/lib/Service/Routing/Strategy/RoundRobinStrategy.php index 900b02d6..77338a8d 100644 --- a/lib/Service/Routing/Strategy/RoundRobinStrategy.php +++ b/lib/Service/Routing/Strategy/RoundRobinStrategy.php @@ -61,8 +61,8 @@ public function name(): string * Returns a single-element array. When no participants match the rule's * `roleType` for the case, returns an empty array. * - * @param array $rule The routing rule - * @param array $case The case object + * @param array $rule The routing rule + * @param array $case The case object * @param array> $roles Roles bound to the case * * @return array diff --git a/lib/Service/Routing/Strategy/SingleRoleStrategy.php b/lib/Service/Routing/Strategy/SingleRoleStrategy.php index b00fc7ec..e47a9e70 100644 --- a/lib/Service/Routing/Strategy/SingleRoleStrategy.php +++ b/lib/Service/Routing/Strategy/SingleRoleStrategy.php @@ -50,8 +50,8 @@ public function name(): string * `@self.created`) so callers see a stable, predictable order. Missing * timestamps degrade gracefully to the input order. * - * @param array $rule The routing rule - * @param array $case The case object + * @param array $rule The routing rule + * @param array $case The case object * @param array> $roles Roles bound to the case * * @return array @@ -77,8 +77,7 @@ public function resolve(array $rule, array $case, array $roles): array $matches[] = [ 'participant' => $participant, 'sortKey' => (string) ( - $role['created'] - ?? ($role['@self']['created'] ?? '') + $role['created'] ?? ($role['@self']['created'] ?? '') ), ]; } @@ -90,9 +89,11 @@ static function (array $left, array $right): int { }, ); - return array_values(array_map( + return array_values( + array_map( static fn (array $match): string => (string) $match['participant'], $matches, - )); + ) + ); }//end resolve() }//end class diff --git a/lib/Service/Routing/StrategyRegistry.php b/lib/Service/Routing/StrategyRegistry.php index f6948943..f3e062e8 100644 --- a/lib/Service/Routing/StrategyRegistry.php +++ b/lib/Service/Routing/StrategyRegistry.php @@ -44,6 +44,7 @@ */ class StrategyRegistry { + /** * The registered strategies keyed by name. * diff --git a/lib/Service/StatusTransitionService.php b/lib/Service/StatusTransitionService.php index c286d94b..b058bc71 100644 --- a/lib/Service/StatusTransitionService.php +++ b/lib/Service/StatusTransitionService.php @@ -63,13 +63,13 @@ class StatusTransitionService /** * Constructor. * - * @param SettingsService $settingsService Bridge to OpenRegister + config - * @param WorkflowTemplateLoader $templateLoader Active workflowTemplate loader - * @param GuardRegistry $guardRegistry Guard registry - * @param SideEffectDispatcher $sideEffectDispatcher Side-effect dispatcher - * @param IUserSession $userSession Current session - * @param IGroupManager $groupManager Group manager (admin gate) - * @param LoggerInterface $logger Logger + * @param SettingsService $settingsService Bridge to OpenRegister + config + * @param WorkflowTemplateLoader $templateLoader Active workflowTemplate loader + * @param GuardRegistry $guardRegistry Guard registry + * @param SideEffectDispatcher $sideEffectDispatcher Side-effect dispatcher + * @param IUserSession $userSession Current session + * @param IGroupManager $groupManager Group manager (admin gate) + * @param LoggerInterface $logger Logger */ public function __construct( private readonly SettingsService $settingsService, @@ -120,6 +120,7 @@ public function getAvailableTransitions(string $caseId, ?string $userId=null): a if (is_array($transition) === false) { continue; } + if ((string) ($transition['fromStatus'] ?? '') !== $currentId) { continue; } @@ -135,11 +136,11 @@ public function getAvailableTransitions(string $caseId, ?string $userId=null): a $failed = array_values(array_filter($eval, static fn(array $g): bool => ($g['passed'] ?? false) === false)); $result['transitions'][] = [ - 'id' => (string) ($transition['id'] ?? ''), - 'label' => (string) ($transition['label'] ?? ''), - 'toStatus' => (string) ($transition['toStatus'] ?? ''), - 'guardsPassed' => count($failed) === 0, - 'failedGuards' => $failed, + 'id' => (string) ($transition['id'] ?? ''), + 'label' => (string) ($transition['label'] ?? ''), + 'toStatus' => (string) ($transition['toStatus'] ?? ''), + 'guardsPassed' => count($failed) === 0, + 'failedGuards' => $failed, ]; }//end foreach @@ -173,7 +174,7 @@ public function execute(string $caseId, string $transitionId, ?string $comment, throw new RuntimeException('transition_not_found'); } - $currentId = (string) ($case['status'] ?? ''); + $currentId = (string) ($case['status'] ?? ''); $fromStatus = (string) ($transition['fromStatus'] ?? ''); if ($fromStatus !== '' && $fromStatus !== $currentId) { throw new RuntimeException('transition_from_status_mismatch'); @@ -267,9 +268,9 @@ public function executeFreeForm(string $caseId, string $toStatusId, ?string $com $caseTypeId = (string) ($case['caseType'] ?? ''); $this->validateStatusBelongsToCaseType(caseTypeId: $caseTypeId, statusTypeId: $toStatusId); - $currentId = (string) ($case['status'] ?? ''); - $case['status'] = $toStatusId; - $case = $this->saveCase(case: $case); + $currentId = (string) ($case['status'] ?? ''); + $case['status'] = $toStatusId; + $case = $this->saveCase(case: $case); $record = $this->writeStatusRecord( caseId: $caseId, @@ -343,11 +344,13 @@ public function isAdmin(string $userId): bool if ($userId === '') { return false; } + try { // Accept membership in either the dedicated procest admin group OR the global admin group. if ($this->groupManager->isInGroup($userId, self::ADMIN_GROUP_ID) === true) { return true; } + return $this->groupManager->isInGroup($userId, 'admin'); } catch (\Throwable $e) { $this->logger->error('StatusTransitionService: admin check failed', ['exception' => $e->getMessage()]); @@ -371,6 +374,7 @@ private function resolveUserId(?string $explicit): string if ($explicit !== null && $explicit !== '') { return $explicit; } + $user = $this->userSession->getUser(); return $user === null ? '' : $user->getUID(); }//end resolveUserId() @@ -388,11 +392,13 @@ private function loadCase(string $caseId): ?array if ($objectService === null) { return null; } + $register = $this->settingsService->getConfigValue(key: 'register'); $caseSchema = $this->settingsService->getConfigValue(key: 'case_schema'); if ($register === '' || $caseSchema === '') { return null; } + try { return $this->toArray(value: $objectService->findObject($register, $caseSchema, $caseId)); } catch (\Throwable $e) { @@ -417,24 +423,26 @@ private function saveCase(array $case): array if ($objectService === null) { throw new RuntimeException('storage_unavailable'); } + $register = $this->settingsService->getConfigValue(key: 'register'); $caseSchema = $this->settingsService->getConfigValue(key: 'case_schema'); if ($register === '' || $caseSchema === '') { throw new RuntimeException('case_schema_not_configured'); } + return $this->toArray(value: $objectService->saveObject($register, $caseSchema, $case)); }//end saveCase() /** * Write a statusRecord row for a transition. * - * @param string $caseId Case UUID - * @param string $toStatus Target statusType UUID - * @param string $fromStatus Prior statusType UUID - * @param string $label Transition label - * @param string|null $comment Free-form comment - * @param array> $evaluatedGuards Guard snapshots - * @param bool $noWorkflowTemplate Flag for free-form transitions + * @param string $caseId Case UUID + * @param string $toStatus Target statusType UUID + * @param string $fromStatus Prior statusType UUID + * @param string $label Transition label + * @param string|null $comment Free-form comment + * @param array> $evaluatedGuards Guard snapshots + * @param bool $noWorkflowTemplate Flag for free-form transitions * * @return array */ @@ -451,6 +459,7 @@ private function writeStatusRecord( if ($objectService === null) { throw new RuntimeException('storage_unavailable'); } + $register = $this->settingsService->getConfigValue(key: 'register'); $recordSchema = $this->settingsService->getConfigValue(key: 'status_record_schema'); if ($register === '' || $recordSchema === '') { @@ -468,6 +477,7 @@ private function writeStatusRecord( if ($fromStatus !== '') { $payload['fromStatus'] = $fromStatus; } + if ($comment !== null && $comment !== '') { $payload['description'] = $comment; } @@ -488,11 +498,13 @@ private function updateStatusRecord(array $record): array if ($objectService === null) { return $record; } + $register = $this->settingsService->getConfigValue(key: 'register'); $recordSchema = $this->settingsService->getConfigValue(key: 'status_record_schema'); if ($register === '' || $recordSchema === '') { return $record; } + return $this->toArray(value: $objectService->saveObject($register, $recordSchema, $record)); }//end updateStatusRecord() @@ -512,8 +524,9 @@ private function validateStatusBelongsToCaseType(string $caseTypeId, string $sta if ($objectService === null) { throw new RuntimeException('storage_unavailable'); } - $register = $this->settingsService->getConfigValue(key: 'register'); - $caseTypeSchema = $this->settingsService->getConfigValue(key: 'case_type_schema'); + + $register = $this->settingsService->getConfigValue(key: 'register'); + $caseTypeSchema = $this->settingsService->getConfigValue(key: 'case_type_schema'); if ($register === '' || $caseTypeSchema === '' || $caseTypeId === '' || $statusTypeId === '') { throw new RuntimeException('case_type_not_configured'); } @@ -551,20 +564,24 @@ private function lookupStatusName(string $statusTypeId): string if ($statusTypeId === '') { return ''; } + $objectService = $this->settingsService->getObjectService(); if ($objectService === null) { return ''; } + $register = $this->settingsService->getConfigValue(key: 'register'); $statusTypeSchema = $this->settingsService->getConfigValue(key: 'status_type_schema'); if ($register === '' || $statusTypeSchema === '') { return ''; } + try { $statusType = $this->toArray(value: $objectService->findObject($register, $statusTypeSchema, $statusTypeId)); } catch (\Throwable $e) { return ''; } + return (string) ($statusType['name'] ?? ($statusType['title'] ?? '')); }//end lookupStatusName() @@ -595,6 +612,7 @@ private function extractGuards(array $transition): array $list[] = $guard; } } + return $list; }//end extractGuards() @@ -611,12 +629,14 @@ private function extractActions(array $transition): array if (is_array($actions) === false) { return []; } + $list = []; foreach ($actions as $action) { if (is_array($action) === true) { $list[] = $action; } } + return $list; }//end extractActions() @@ -637,6 +657,7 @@ private function isRoleHidden(array $evalResults): bool return true; } } + return false; }//end isRoleHidden() @@ -652,6 +673,7 @@ private function toArray(mixed $value): array if (is_array($value) === true) { return $value; } + if (is_object($value) === true) { if (method_exists($value, 'jsonSerialize') === true) { $serialized = $value->jsonSerialize(); @@ -660,6 +682,7 @@ private function toArray(mixed $value): array } } } + return []; }//end toArray() }//end class diff --git a/lib/Service/StepConfigValidator.php b/lib/Service/StepConfigValidator.php index 9eaa4fd4..c405ac14 100644 --- a/lib/Service/StepConfigValidator.php +++ b/lib/Service/StepConfigValidator.php @@ -111,18 +111,19 @@ final class StepConfigValidator * keys `path`, `code`, and `message`. The `message` is an internal * description — callers MUST NOT include it in user-facing responses. * - * @param array $step The step (with optional `config`). - * @param array $caseTypeSchema The linked caseType — properties + roleTypes. - * @param array $actionCatalog Optional override of recognised action keys. - * @param int $stepIndex The step's index in `steps[]` for path prefix. + * @param array $step The step (with optional `config`). + * @param array $caseTypeSchema The linked caseType — properties + + * roleTypes. + * @param array $actionCatalog Optional override of recognised action keys. + * @param int $stepIndex The step's index in `steps[]` for path prefix. * * @return array */ public static function validate( array $step, - array $caseTypeSchema = [], - array $actionCatalog = self::DEFAULT_ACTION_CATALOG, - int $stepIndex = 0 + array $caseTypeSchema=[], + array $actionCatalog=self::DEFAULT_ACTION_CATALOG, + int $stepIndex=0 ): array { $errors = []; $config = ($step['config'] ?? null); @@ -210,6 +211,7 @@ private static function validateSla(mixed $sla, string $path): array if ($sla === null) { return []; } + if (is_array($sla) === false) { return [self::error($path, 'malformed_sla', 'sla must be an object')]; } @@ -257,6 +259,7 @@ private static function validateRequiredFields( if ($fields === null) { return []; } + if (is_array($fields) === false) { return [self::error($path, 'malformed_required_fields', 'requiredFields must be an array')]; } @@ -274,6 +277,7 @@ private static function validateRequiredFields( ); continue; } + if ($checkRefs === true && array_key_exists($field, $caseTypeProperties) === false) { $errors[] = self::error( $path."[$index]", @@ -305,6 +309,7 @@ private static function validateAutoActions( if ($actions === null) { return []; } + if (is_array($actions) === false) { return [self::error($path, 'malformed_auto_actions', 'autoActions must be an array')]; } @@ -319,6 +324,7 @@ private static function validateAutoActions( ); continue; } + $key = ($action['key'] ?? null); if (is_string($key) === false || $key === '') { $errors[] = self::error( @@ -328,6 +334,7 @@ private static function validateAutoActions( ); continue; } + if (in_array($key, $actionCatalog, true) === false) { $errors[] = self::error( $path."[$index].key", @@ -335,7 +342,7 @@ private static function validateAutoActions( 'autoActions[i].key is not registered in the action catalog' ); } - } + }//end foreach return $errors; }//end validateAutoActions() @@ -361,6 +368,7 @@ private static function validateEscalationRule( if ($rule === null) { return []; } + if (is_array($rule) === false) { return [self::error($path, 'malformed_escalation_rule', 'escalationRule must be an object')]; } @@ -426,6 +434,7 @@ private static function validateEscalationRule( if ($role === null) { continue; } + if (is_string($role) === false || $role === '') { $errors[] = self::error( $path.'.'.$roleKey, @@ -434,6 +443,7 @@ private static function validateEscalationRule( ); continue; } + if ($checkRoles === true && array_key_exists($role, $roleTypes) === false) { $errors[] = self::error( $path.'.'.$roleKey, @@ -441,7 +451,7 @@ private static function validateEscalationRule( $roleKey.' does not resolve to a roleType on the linked caseType' ); } - } + }//end foreach $openIncident = ($rule['openIncident'] ?? null); if ($openIncident !== null && is_bool($openIncident) === false) { diff --git a/lib/Service/Transitions/ActionHandlerInterface.php b/lib/Service/Transitions/ActionHandlerInterface.php index f63a1e9c..a2da95b1 100644 --- a/lib/Service/Transitions/ActionHandlerInterface.php +++ b/lib/Service/Transitions/ActionHandlerInterface.php @@ -34,7 +34,6 @@ */ interface ActionHandlerInterface { - /** * Handle a single automatic action. * diff --git a/lib/Service/Transitions/ActionHandlerRegistry.php b/lib/Service/Transitions/ActionHandlerRegistry.php index 7733b68c..d6d8c77c 100644 --- a/lib/Service/Transitions/ActionHandlerRegistry.php +++ b/lib/Service/Transitions/ActionHandlerRegistry.php @@ -74,8 +74,8 @@ public function __construct( /** * Register an additional handler (DI extension point). * - * @param string $type Action type identifier - * @param ActionHandlerInterface $handler Handler implementation + * @param string $type Action type identifier + * @param ActionHandlerInterface $handler Handler implementation * * @return void */ diff --git a/lib/Service/Transitions/ActionResult.php b/lib/Service/Transitions/ActionResult.php index 47e8057e..1c9cd9cf 100644 --- a/lib/Service/Transitions/ActionResult.php +++ b/lib/Service/Transitions/ActionResult.php @@ -33,7 +33,6 @@ */ final class ActionResult { - /** * Constructor. * diff --git a/lib/Service/Transitions/ChecklistGuard.php b/lib/Service/Transitions/ChecklistGuard.php index cee8a9af..9e7b60a8 100644 --- a/lib/Service/Transitions/ChecklistGuard.php +++ b/lib/Service/Transitions/ChecklistGuard.php @@ -37,7 +37,6 @@ */ class ChecklistGuard implements GuardEvaluatorInterface { - /** * Constructor. * @@ -98,6 +97,7 @@ public function evaluate(array $guardConfig, array $case, string $userId): Guard if (is_array($item) === false) { continue; } + $label = (string) ($item['label'] ?? ($item['name'] ?? '')); $checked = (bool) ($item['checked'] ?? false); @@ -135,12 +135,14 @@ private function toArray(mixed $value): array if (is_array($value) === true) { return $value; } + if (is_object($value) === true && method_exists($value, 'jsonSerialize') === true) { $serialized = $value->jsonSerialize(); if (is_array($serialized) === true) { return $serialized; } } + return []; }//end toArray() }//end class diff --git a/lib/Service/Transitions/CreateSubCaseHandler.php b/lib/Service/Transitions/CreateSubCaseHandler.php index cd07a73f..32e23eda 100644 --- a/lib/Service/Transitions/CreateSubCaseHandler.php +++ b/lib/Service/Transitions/CreateSubCaseHandler.php @@ -35,7 +35,6 @@ */ class CreateSubCaseHandler implements ActionHandlerInterface { - /** * Constructor. * @@ -78,8 +77,8 @@ public function handle(array $actionConfig, array $case, array $transitionContex 'hoofdzaak' => $parentId, ]; - $created = $objectService->saveObject($register, $caseSchema, $subCase); - $subId = is_array($created) === true ? (string) ($created['id'] ?? '') : ''; + $created = $objectService->saveObject($register, $caseSchema, $subCase); + $subId = is_array($created) === true ? (string) ($created['id'] ?? '') : ''; return ActionResult::success(data: ['subCaseId' => $subId]); } catch (\Throwable $e) { @@ -88,6 +87,6 @@ public function handle(array $actionConfig, array $case, array $transitionContex ['exception' => $e->getMessage(), 'context' => $transitionContext], ); return ActionResult::failure(error: 'create_sub_case_failed'); - } + }//end try }//end handle() }//end class diff --git a/lib/Service/Transitions/CreateTaskHandler.php b/lib/Service/Transitions/CreateTaskHandler.php index 79974d14..af0eb39f 100644 --- a/lib/Service/Transitions/CreateTaskHandler.php +++ b/lib/Service/Transitions/CreateTaskHandler.php @@ -35,7 +35,6 @@ */ class CreateTaskHandler implements ActionHandlerInterface { - /** * Constructor. * @@ -89,6 +88,6 @@ public function handle(array $actionConfig, array $case, array $transitionContex ['exception' => $e->getMessage(), 'context' => $transitionContext], ); return ActionResult::failure(error: 'create_task_failed'); - } + }//end try }//end handle() }//end class diff --git a/lib/Service/Transitions/GuardEvaluatorInterface.php b/lib/Service/Transitions/GuardEvaluatorInterface.php index 253cd54e..a5b1e86c 100644 --- a/lib/Service/Transitions/GuardEvaluatorInterface.php +++ b/lib/Service/Transitions/GuardEvaluatorInterface.php @@ -33,7 +33,6 @@ */ interface GuardEvaluatorInterface { - /** * Evaluate the guard. * diff --git a/lib/Service/Transitions/GuardRegistry.php b/lib/Service/Transitions/GuardRegistry.php index 2f3513c7..ca42cccf 100644 --- a/lib/Service/Transitions/GuardRegistry.php +++ b/lib/Service/Transitions/GuardRegistry.php @@ -71,8 +71,8 @@ public function __construct( /** * Register an additional evaluator (DI extension point). * - * @param string $type Guard type identifier - * @param GuardEvaluatorInterface $evaluator Evaluator implementation + * @param string $type Guard type identifier + * @param GuardEvaluatorInterface $evaluator Evaluator implementation * * @return void */ @@ -97,10 +97,12 @@ public function evaluateAll(array $guards, array $case, string $userId): array if (is_array($guard) === false) { continue; } + $type = (string) ($guard['type'] ?? ''); if ($type === '') { continue; } + if (isset($this->evaluators[$type]) === false) { $this->logger->warning('Unknown guard type', ['type' => $type]); $results[] = [ @@ -119,7 +121,7 @@ public function evaluateAll(array $guards, array $case, string $userId): array 'failureMessage' => $result->failureMessage, 'details' => $result->details, ]; - } + }//end foreach return $results; }//end evaluateAll() @@ -138,6 +140,7 @@ public function allPassed(array $results): bool return false; } } + return true; }//end allPassed() }//end class diff --git a/lib/Service/Transitions/GuardResult.php b/lib/Service/Transitions/GuardResult.php index 8da9706b..1f300ed4 100644 --- a/lib/Service/Transitions/GuardResult.php +++ b/lib/Service/Transitions/GuardResult.php @@ -33,7 +33,6 @@ */ final class GuardResult { - /** * Constructor. * diff --git a/lib/Service/Transitions/NotifyHandler.php b/lib/Service/Transitions/NotifyHandler.php index 5af22219..390cb582 100644 --- a/lib/Service/Transitions/NotifyHandler.php +++ b/lib/Service/Transitions/NotifyHandler.php @@ -35,7 +35,6 @@ */ class NotifyHandler implements ActionHandlerInterface { - /** * Constructor. * diff --git a/lib/Service/Transitions/RequiredDocumentGuard.php b/lib/Service/Transitions/RequiredDocumentGuard.php index bc847b91..b56127f9 100644 --- a/lib/Service/Transitions/RequiredDocumentGuard.php +++ b/lib/Service/Transitions/RequiredDocumentGuard.php @@ -34,7 +34,6 @@ */ class RequiredDocumentGuard implements GuardEvaluatorInterface { - /** * Evaluate the required-document guard. * @@ -65,6 +64,7 @@ public function evaluate(array $guardConfig, array $case, string $userId): Guard if (is_array($doc) === false) { continue; } + $type = (string) ($doc['documentType'] ?? ($doc['type'] ?? '')); if ($type === $required) { return GuardResult::pass(details: ['documentType' => $required]); diff --git a/lib/Service/Transitions/RequiredFieldGuard.php b/lib/Service/Transitions/RequiredFieldGuard.php index 857d30dd..d4fe03c2 100644 --- a/lib/Service/Transitions/RequiredFieldGuard.php +++ b/lib/Service/Transitions/RequiredFieldGuard.php @@ -32,7 +32,6 @@ */ class RequiredFieldGuard implements GuardEvaluatorInterface { - /** * Evaluate the required-field guard. * diff --git a/lib/Service/Transitions/RoleGuard.php b/lib/Service/Transitions/RoleGuard.php index 37abc50c..551750c0 100644 --- a/lib/Service/Transitions/RoleGuard.php +++ b/lib/Service/Transitions/RoleGuard.php @@ -43,7 +43,6 @@ */ class RoleGuard implements GuardEvaluatorInterface { - /** * Constructor. * @@ -88,6 +87,7 @@ public function evaluate(array $guardConfig, array $case, string $userId): Guard if (is_array($entry) === false) { continue; } + $entryUser = (string) ($entry['userId'] ?? ($entry['user'] ?? '')); $entryRole = (string) ($entry['role'] ?? ($entry['roleType'] ?? '')); if ($entryUser === $userId && in_array($entryRole, $allowed, true) === true) { @@ -105,6 +105,7 @@ public function evaluate(array $guardConfig, array $case, string $userId): Guard if ($groupId === '') { continue; } + if ($this->groupManager->isInGroup($userId, $groupId) === true) { return GuardResult::pass(details: ['matchedRole' => $role, 'via' => 'group']); } diff --git a/lib/Service/Transitions/SendEmailHandler.php b/lib/Service/Transitions/SendEmailHandler.php index 01f60f25..ae19dc37 100644 --- a/lib/Service/Transitions/SendEmailHandler.php +++ b/lib/Service/Transitions/SendEmailHandler.php @@ -36,7 +36,6 @@ */ class SendEmailHandler implements ActionHandlerInterface { - /** * Constructor. * @@ -90,6 +89,6 @@ public function handle(array $actionConfig, array $case, array $transitionContex ['exception' => $e->getMessage(), 'context' => $transitionContext], ); return ActionResult::failure(error: 'send_email_failed'); - } + }//end try }//end handle() }//end class diff --git a/lib/Service/Transitions/SetFieldHandler.php b/lib/Service/Transitions/SetFieldHandler.php index 7890f92f..dfc7d0ed 100644 --- a/lib/Service/Transitions/SetFieldHandler.php +++ b/lib/Service/Transitions/SetFieldHandler.php @@ -37,7 +37,6 @@ */ class SetFieldHandler implements ActionHandlerInterface { - /** * Constructor. * @@ -95,6 +94,6 @@ public function handle(array $actionConfig, array $case, array $transitionContex ['exception' => $e->getMessage(), 'context' => $transitionContext], ); return ActionResult::failure(error: 'set_field_failed'); - } + }//end try }//end handle() }//end class diff --git a/lib/Service/Transitions/SideEffectDispatcher.php b/lib/Service/Transitions/SideEffectDispatcher.php index 5c717a47..03add89c 100644 --- a/lib/Service/Transitions/SideEffectDispatcher.php +++ b/lib/Service/Transitions/SideEffectDispatcher.php @@ -37,7 +37,6 @@ */ class SideEffectDispatcher { - /** * Constructor. * @@ -66,6 +65,7 @@ public function dispatch(array $actions, array $case, array $transitionContext): if (is_array($action) === false) { continue; } + $type = (string) ($action['type'] ?? ''); if ($type === '') { continue; @@ -90,8 +90,9 @@ public function dispatch(array $actions, array $case, array $transitionContext): if ($result->ok === false) { $entry['error'] = (string) ($result->error ?? 'action_failed'); } + $results[] = $entry; - } + }//end foreach return $results; }//end dispatch() diff --git a/lib/Service/Transitions/WebhookHandler.php b/lib/Service/Transitions/WebhookHandler.php index 1917cbdc..1afa13fa 100644 --- a/lib/Service/Transitions/WebhookHandler.php +++ b/lib/Service/Transitions/WebhookHandler.php @@ -36,7 +36,6 @@ */ class WebhookHandler implements ActionHandlerInterface { - /** * Constructor. * @@ -96,6 +95,6 @@ public function handle(array $actionConfig, array $case, array $transitionContex ['exception' => $e->getMessage(), 'context' => $transitionContext], ); return ActionResult::failure(error: 'webhook_failed'); - } + }//end try }//end handle() }//end class diff --git a/lib/Service/Vth/LhsRecommendationService.php b/lib/Service/Vth/LhsRecommendationService.php index b61502b2..c20ac5b1 100644 --- a/lib/Service/Vth/LhsRecommendationService.php +++ b/lib/Service/Vth/LhsRecommendationService.php @@ -162,7 +162,7 @@ public function recommend( * persisted with `overrideAuthority = "manager"`. * * @param array $recommendation Original recommendation row - * (must include id, recommendedInterventie) + * (must include id, recommendedInterventie) * @param string $intervention Chosen intervention (enum value) * @param string $justification Mandatory justification (>= 20 chars) * @param string $userRole Caller role: "inspector" or "manager" @@ -344,7 +344,7 @@ private function indexCells(mixed $cells): array continue; } - $key = ((string) ($cell['ernst'] ?? '')) + $key = ((string) ($cell['ernst'] ?? '')) .':'.((string) ($cell['gedrag'] ?? '')) .':'.((string) ($cell['actorType'] ?? '')); $index[$key] = $cell; diff --git a/lib/Service/WmsWfsService.php b/lib/Service/WmsWfsService.php index 9877806d..0d653813 100644 --- a/lib/Service/WmsWfsService.php +++ b/lib/Service/WmsWfsService.php @@ -62,7 +62,6 @@ class WmsWfsService */ private const DEFAULT_EXTENT_CUTOFF_KM = 50.0; - /** * Constructor for WmsWfsService. * @@ -81,7 +80,6 @@ public function __construct( ) { }//end __construct() - /** * Resolve the set of wmsLayer objects active for a given case type. * @@ -147,7 +145,6 @@ public function getLayersForCaseType(array|object $caseType): array return $result; }//end getLayersForCaseType() - /** * Validate a wmsLayer object before persistence. * @@ -207,7 +204,6 @@ public function validateLayer(array $layer): array return ['ok' => count($errors) === 0, 'errors' => $errors]; }//end validateLayer() - /** * Proxy a WMS/WFS request for a specific layer through the GIS proxy. * @@ -272,7 +268,7 @@ public function proxyRequest(array $layer, array $params): array $version = ($type === 'WFS') ? self::DEFAULT_WFS_VERSION : self::DEFAULT_WMS_VERSION; } - $query = array_change_key_case($params, CASE_UPPER); + $query = array_change_key_case($params, CASE_UPPER); $query['SERVICE'] = $type; $query['VERSION'] = $version; $query['REQUEST'] = $request; @@ -298,7 +294,6 @@ public function proxyRequest(array $layer, array $params): array return $this->gisProxyService->proxyRequest($url, $query, strtolower($type)); }//end proxyRequest() - /** * Build a GetMap URL fragment (delegated to proxy for fetch). * @@ -344,7 +339,6 @@ public function buildGetMapUrl(array $layer, string $bbox, int $width, int $heig return $url.$separator.http_build_query($query); }//end buildGetMapUrl() - /** * Build a GetFeature URL fragment with BBOX scoped to the visible extent. * @@ -383,7 +377,6 @@ public function buildGetFeatureUrl(array $layer, string $bbox): string return $url.$separator.http_build_query($query); }//end buildGetFeatureUrl() - /** * Fetch a single wmsLayer object by id from OpenRegister. * @@ -433,7 +426,6 @@ public function getLayerById(string $layerId): ?array return null; }//end getLayerById() - /** * Determine whether a URL is acceptable to the GIS proxy. * @@ -511,7 +503,6 @@ private function isUrlAllowed(string $url): bool return false; }//end isUrlAllowed() - /** * Fetch all wmsLayer objects from OpenRegister. * @@ -543,10 +534,9 @@ private function fetchAllLayers(): array ['exception' => $e->getMessage()] ); return []; - } + }//end try }//end fetchAllLayers() - /** * Check whether a BBOX string spans more than the cutoff distance. * @@ -587,6 +577,4 @@ private function bboxExceedsCutoff(string $bbox, float $cutoffKm): bool $cutoffDeg = ($cutoffKm / 111.0); return ($spanX > $cutoffDeg || $spanY > $cutoffDeg); }//end bboxExceedsCutoff() - - }//end class diff --git a/lib/Service/WorkflowDefinitionService.php b/lib/Service/WorkflowDefinitionService.php index fce985fc..fb2cbbd6 100644 --- a/lib/Service/WorkflowDefinitionService.php +++ b/lib/Service/WorkflowDefinitionService.php @@ -72,18 +72,17 @@ class WorkflowDefinitionService * Static error strings — never leak OpenRegister exception details to * the HTTP layer. */ - private const ERR_OR_UNAVAILABLE = 'Workflow definition store is not available'; - private const ERR_SCHEMA_NOT_CONFIG = 'Workflow definition schema is not configured'; - private const ERR_NOT_FOUND = 'Workflow definition not found'; - private const ERR_PUBLISH_FAILED = 'Could not publish workflow definition'; - private const ERR_DEPRECATE_FAILED = 'Could not deprecate workflow definition'; - private const ERR_CLONE_FAILED = 'Could not clone workflow definition'; - private const ERR_NOT_DRAFT = 'Only draft definitions can be edited'; - private const ERR_NOT_PUBLISHABLE = 'Only draft definitions can be published'; - private const ERR_NOT_DEPRECATABLE = 'Only published definitions can be deprecated'; - private const ERR_INVALID_REFERENCES = 'Definition references statuses not belonging to its case type'; - private const ERR_LAST_PUBLISHED = 'Cannot deprecate the last published definition while open cases remain'; - + private const ERR_OR_UNAVAILABLE = 'Workflow definition store is not available'; + private const ERR_SCHEMA_NOT_CONFIG = 'Workflow definition schema is not configured'; + private const ERR_NOT_FOUND = 'Workflow definition not found'; + private const ERR_PUBLISH_FAILED = 'Could not publish workflow definition'; + private const ERR_DEPRECATE_FAILED = 'Could not deprecate workflow definition'; + private const ERR_CLONE_FAILED = 'Could not clone workflow definition'; + private const ERR_NOT_DRAFT = 'Only draft definitions can be edited'; + private const ERR_NOT_PUBLISHABLE = 'Only draft definitions can be published'; + private const ERR_NOT_DEPRECATABLE = 'Only published definitions can be deprecated'; + private const ERR_INVALID_REFERENCES = 'Definition references statuses not belonging to its case type'; + private const ERR_LAST_PUBLISHED = 'Cannot deprecate the last published definition while open cases remain'; /** * Constructor. @@ -99,7 +98,6 @@ public function __construct( ) { }//end __construct() - /** * Resolve the latest published+active definition for a caseType, or * null when none exists. Read-only consumer entrypoint used by @@ -133,7 +131,6 @@ public function getActiveDefinitionFor(string $caseTypeId): ?array return null; }//end getActiveDefinitionFor() - /** * Read a single definition by UUID. Returns null when not found. * @@ -146,7 +143,6 @@ public function getDefinition(string $id): ?array return $this->loadDefinition($id); }//end getDefinition() - /** * Resolve the definition pinned to a case via case.workflowTemplate + * case.workflowVersion. Falls back to the active definition for the @@ -198,7 +194,6 @@ public function getDefinitionForCase(string $caseId): ?array return $this->getActiveDefinitionFor($caseTypeId); }//end getDefinitionForCase() - /** * List every version of the definition for a given caseType, ordered * by version descending. Used by the admin UI. @@ -212,7 +207,6 @@ public function listVersions(string $caseTypeId): array return $this->listVersionsInternal($caseTypeId); }//end listVersions() - /** * Publish a draft definition. Atomically: * - sets target lifecycleStatus=published, isActive=true, isDraft=false @@ -259,9 +253,9 @@ public function publish(string $id): ?array return null; } - $register = $this->settingsService->getConfigValue('register'); - $schema = $this->settingsService->getConfigValue('workflow_template_schema'); - $caseTypeSch = $this->settingsService->getConfigValue('case_type_schema'); + $register = $this->settingsService->getConfigValue('register'); + $schema = $this->settingsService->getConfigValue('workflow_template_schema'); + $caseTypeSch = $this->settingsService->getConfigValue('case_type_schema'); if ($register === '' || $schema === '' || $caseTypeSch === '') { return null; @@ -330,7 +324,6 @@ public function publish(string $id): ?array return $this->normalize($updated); }//end publish() - /** * Deprecate a published definition. Refuses (returns null + logs) if * doing so would leave the caseType with no published definition while @@ -399,7 +392,6 @@ public function deprecate(string $id): ?array return $this->normalize($updated); }//end deprecate() - /** * Clone an existing published or deprecated definition into a new * draft with version + 1. @@ -427,7 +419,7 @@ public function cloneDefinition(string $id): ?array return null; } - $caseTypeId = (string) ($source['caseType'] ?? ''); + $caseTypeId = (string) ($source['caseType'] ?? ''); $nextVersion = $this->nextVersionFor($caseTypeId); $draft = [ @@ -456,7 +448,6 @@ public function cloneDefinition(string $id): ?array return $this->normalize($new); }//end cloneDefinition() - /** * Create a brand-new draft definition from a fully-resolved payload. * Used by seed-data / catalog import flows where the caller has already @@ -534,12 +525,10 @@ public function createDraft(array $payload): ?array return $this->normalize($new); }//end createDraft() - // ----------------------------------------------------------------- // Internal helpers. // ----------------------------------------------------------------- - /** * Internal — fetch all versions of the definition for a caseType, * sorted by version descending. @@ -600,7 +589,6 @@ static function (array $a, array $b): int { return $rows; }//end listVersionsInternal() - /** * Load a single definition by UUID. * @@ -639,7 +627,6 @@ private function loadDefinition(string $id): ?array return $this->normalize($obj); }//end loadDefinition() - /** * Resolve the next monotonically increasing version number for a * given caseType. Falls back to 1 when no prior versions exist. @@ -662,7 +649,6 @@ private function nextVersionFor(string $caseTypeId): int return ($max + 1); }//end nextVersionFor() - /** * Whether this id is the last published row for its caseType. * @@ -687,7 +673,6 @@ private function isLastPublishedForCaseType(string $id, string $caseTypeId): boo return ($count === 0); }//end isLastPublishedForCaseType() - /** * Whether the caseType has any open cases (status not in a final * state). Conservative — returns true when we cannot establish the @@ -730,7 +715,6 @@ private function hasOpenCasesFor(string $caseTypeId): bool return (is_array($results) === true && count($results) > 0); }//end hasOpenCasesFor() - /** * Validate that every status referenced in transitions belongs to the * linked caseType. Returns true when the references are *invalid*. @@ -770,7 +754,6 @@ private function transitionsReferenceForeignStatuses(array $definition): bool return false; }//end transitionsReferenceForeignStatuses() - /** * Fetch every statusType id belonging to a given caseType. * @@ -828,7 +811,6 @@ private function collectStatusTypeIdsFor(string $caseTypeId): array return $ids; }//end collectStatusTypeIdsFor() - /** * Decode a JSON-encoded array property; returns an empty array on any * decoding error or non-array payload. @@ -855,7 +837,6 @@ private function decodeArray(mixed $raw): array return []; }//end decodeArray() - /** * Coerce an OpenRegister result row to an associative array. * @@ -879,7 +860,6 @@ private function normalize(mixed $row): ?array return null; }//end normalize() - /** * Resolve the authoritative lifecycle status of a row. Prefers the * new lifecycleStatus field; falls back to the legacy isDraft + @@ -914,7 +894,6 @@ private function statusOf(array $row): string return self::STATUS_DEPRECATED; }//end statusOf() - /** * Build a title for a cloned draft. * @@ -926,6 +905,4 @@ private function cloneTitle(string $base): string { return rtrim($base).' (kopie)'; }//end cloneTitle() - - }//end class diff --git a/lib/Service/WorkflowTemplateLoader.php b/lib/Service/WorkflowTemplateLoader.php index ccc03a4c..d247ec6b 100644 --- a/lib/Service/WorkflowTemplateLoader.php +++ b/lib/Service/WorkflowTemplateLoader.php @@ -69,6 +69,7 @@ public function getActiveTemplate(string $caseTypeId): ?array if ($caseTypeId === '') { return null; } + if (isset($this->cache[$caseTypeId]) === true) { return $this->cache[$caseTypeId] === false ? null : $this->cache[$caseTypeId]; } @@ -130,18 +131,22 @@ public function getTransitionById(string $caseTypeId, string $transitionId): ?ar if ($template === null) { return null; } + $transitions = $template['transitions'] ?? []; if (is_array($transitions) === false) { return null; } + foreach ($transitions as $transition) { if (is_array($transition) === false) { continue; } + if ((string) ($transition['id'] ?? '') === $transitionId) { return $transition; } } + return null; }//end getTransitionById() @@ -167,12 +172,14 @@ private function normalise(mixed $value): array if (is_array($value) === false) { return []; } + $list = []; foreach ($value as $item) { if (is_array($item) === true) { $list[] = $item; continue; } + if (is_object($item) === true && method_exists($item, 'jsonSerialize') === true) { $serialized = $item->jsonSerialize(); if (is_array($serialized) === true) { @@ -180,6 +187,7 @@ private function normalise(mixed $value): array } } } + return $list; }//end normalise() From 23419beb817e0e3b5d8d84952bb67def4f1ba4ba Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Tue, 12 May 2026 10:49:08 +0200 Subject: [PATCH 02/13] fix(phpcs): clear remaining manual PHPCS errors (named args, inline-if, PHPDoc) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Completes the PHPCS baseline cleanup started in the previous commit (phpcbf auto-fixes). This commit hand-fixes the ~227 errors phpcbf can't touch, across 37 files in lib/: - "All arguments in calls to internal code must use named parameters" — converted positional calls to procest's own classes/constructors to named-argument form (e.g. `$x->extractObject($event)` → `$x->extractObject(event: $event)`). Entity __call setters/getters left positional (named args break the `$args[0]` resolution). - "Inline IF statements are not allowed" — ternary statements/assignments rewritten to if/else, behaviour-preserving. - Missing @return / @param PHPDoc tags added; short-description capitalisation; implicit-true comparisons made explicit (=== true); over-long lines wrapped. `composer phpcs` now exits 1 (warnings only, no errors) — the "PHP Quality (phpcs)" CI gate passes. ~709 warnings remain (mostly `@spec` PHPDoc-tag warnings) — intentionally out of scope; the CI tolerates warnings. No logic changes. `php -l` clean on all 37 changed files. --- lib/Controller/LhsController.php | 21 ++- .../ParaferingAuditExportController.php | 4 +- lib/Controller/StatusTransitionController.php | 12 +- lib/Listener/BeroepEscalationListener.php | 2 +- .../BezwaarAdviceRequestedListener.php | 2 +- lib/Listener/BezwaarDecisionListener.php | 2 +- lib/Listener/BezwaarLifecycleListener.php | 10 +- lib/Listener/ParaferingAuditListener.php | 2 +- lib/Listener/RoleMutationListener.php | 2 +- lib/Repair/MigrateWorkflowDefinitions.php | 28 ++-- lib/Repair/SeedBezwaarWorkflowDefinition.php | 31 +++-- lib/Service/Actions/ActionRegistry.php | 2 +- lib/Service/Actions/CallWebhookHandler.php | 21 ++- lib/Service/Actions/CreateDocumentHandler.php | 14 +- lib/Service/Actions/MergeTemplateHandler.php | 10 +- lib/Service/Actions/NotifyRoleHandler.php | 14 +- .../Actions/ScheduleReminderHandler.php | 26 +++- lib/Service/Actions/SendEmailHandler.php | 20 ++- lib/Service/AdviceService.php | 26 ++-- lib/Service/Bezwaar/HearingService.php | 37 +++-- lib/Service/Inspection/ChecklistService.php | 34 ++++- lib/Service/LocationService.php | 32 ++++- lib/Service/ParafeerRouteService.php | 12 +- lib/Service/Parafering/AuditTrailService.php | 34 +++-- lib/Service/RoleResolverService.php | 17 ++- .../Routing/Strategy/HierarchicalStrategy.php | 2 + .../Routing/Strategy/LeastLoadedStrategy.php | 2 + .../Routing/Strategy/OrSetStrategy.php | 2 + .../Routing/Strategy/RoundRobinStrategy.php | 2 + .../Routing/Strategy/SingleRoleStrategy.php | 2 + lib/Service/Routing/StrategyRegistry.php | 10 +- lib/Service/StatusTransitionService.php | 21 ++- lib/Service/StepConfigValidator.php | 126 +++++++++--------- lib/Service/Vth/LhsRecommendationService.php | 33 +++-- lib/Service/WmsWfsService.php | 10 +- lib/Service/WorkflowDefinitionService.php | 78 ++++++----- lib/Service/WorkflowTemplateLoader.php | 6 +- 37 files changed, 476 insertions(+), 233 deletions(-) diff --git a/lib/Controller/LhsController.php b/lib/Controller/LhsController.php index 03301ce2..47235b4c 100644 --- a/lib/Controller/LhsController.php +++ b/lib/Controller/LhsController.php @@ -113,9 +113,18 @@ public function recommend(): JSONResponse } $versionParam = $this->request->getParam('lhsVersion'); - $version = ($versionParam === null) ? null : (int) $versionParam; - $inspection = $this->request->getParam('inspection'); - $inspectionId = (is_string($inspection) === true && $inspection !== '') ? $inspection : null; + if ($versionParam === null) { + $version = null; + } else { + $version = (int) $versionParam; + } + + $inspection = $this->request->getParam('inspection'); + if (is_string($inspection) === true && $inspection !== '') { + $inspectionId = $inspection; + } else { + $inspectionId = null; + } try { $recommendation = $this->lhsService->recommend( @@ -183,7 +192,11 @@ public function override(): JSONResponse $declaredRole = (string) $this->request->getParam('userRole', ''); $isManager = $this->groupManager->isAdmin($user->getUID()); - $userRole = ($declaredRole === 'manager' && $isManager === true) ? 'manager' : 'inspector'; + if ($declaredRole === 'manager' && $isManager === true) { + $userRole = 'manager'; + } else { + $userRole = 'inspector'; + } try { $updated = $this->lhsService->override( diff --git a/lib/Controller/ParaferingAuditExportController.php b/lib/Controller/ParaferingAuditExportController.php index 5f64ff3c..8ea38680 100644 --- a/lib/Controller/ParaferingAuditExportController.php +++ b/lib/Controller/ParaferingAuditExportController.php @@ -69,7 +69,7 @@ public function __construct( private readonly SettingsService $settingsService, private readonly LoggerInterface $logger, ) { - parent::__construct($appName, $request); + parent::__construct(appName: $appName, request: $request); }//end __construct() /** @@ -120,7 +120,7 @@ public function export(string $id, string $format='json'): JSONResponse ); } - $voorstelOnderwerp = $this->resolveVoorstelOnderwerp($id); + $voorstelOnderwerp = $this->resolveVoorstelOnderwerp(voorstelId: $id); if ($voorstelOnderwerp === null) { return new JSONResponse( ['message' => 'Voorstel not found'], diff --git a/lib/Controller/StatusTransitionController.php b/lib/Controller/StatusTransitionController.php index 0940846c..f24a5ea7 100644 --- a/lib/Controller/StatusTransitionController.php +++ b/lib/Controller/StatusTransitionController.php @@ -108,7 +108,11 @@ public function execute(string $caseId): JSONResponse { $body = $this->readJsonBody(); $transitionId = (string) ($body['transitionId'] ?? ''); - $comment = isset($body['comment']) === true ? (string) $body['comment'] : null; + if (isset($body['comment']) === true) { + $comment = (string) $body['comment']; + } else { + $comment = null; + } if ($transitionId === '') { return new JSONResponse( @@ -172,7 +176,11 @@ public function freeform(string $caseId): JSONResponse $body = $this->readJsonBody(); $toStatusId = (string) ($body['toStatusId'] ?? ''); - $comment = isset($body['comment']) === true ? (string) $body['comment'] : null; + if (isset($body['comment']) === true) { + $comment = (string) $body['comment']; + } else { + $comment = null; + } if ($toStatusId === '') { return new JSONResponse( diff --git a/lib/Listener/BeroepEscalationListener.php b/lib/Listener/BeroepEscalationListener.php index 12f08869..db9836eb 100644 --- a/lib/Listener/BeroepEscalationListener.php +++ b/lib/Listener/BeroepEscalationListener.php @@ -110,7 +110,7 @@ public function handle(Event $event): void } try { - $object = $this->extractObject($event); + $object = $this->extractObject(event: $event); if ($object === null) { return; } diff --git a/lib/Listener/BezwaarAdviceRequestedListener.php b/lib/Listener/BezwaarAdviceRequestedListener.php index 9801d649..ef26ab87 100644 --- a/lib/Listener/BezwaarAdviceRequestedListener.php +++ b/lib/Listener/BezwaarAdviceRequestedListener.php @@ -83,7 +83,7 @@ public function handle(Event $event): void } try { - $object = $this->extractObject($event); + $object = $this->extractObject(event: $event); if ($object === null) { return; } diff --git a/lib/Listener/BezwaarDecisionListener.php b/lib/Listener/BezwaarDecisionListener.php index 11639ad1..69fc1cee 100644 --- a/lib/Listener/BezwaarDecisionListener.php +++ b/lib/Listener/BezwaarDecisionListener.php @@ -83,7 +83,7 @@ public function handle(Event $event): void } try { - $object = $this->extractObject($event); + $object = $this->extractObject(event: $event); if ($object === null) { return; } diff --git a/lib/Listener/BezwaarLifecycleListener.php b/lib/Listener/BezwaarLifecycleListener.php index 5ddcdcd1..33e07fca 100644 --- a/lib/Listener/BezwaarLifecycleListener.php +++ b/lib/Listener/BezwaarLifecycleListener.php @@ -91,12 +91,12 @@ public function handle(Event $event): void return; } - $payload = $this->extractObject($event); + $payload = $this->extractObject(event: $event); if ($payload === null) { return; } - $schemaSlug = $this->resolveSchemaSlug($payload); + $schemaSlug = $this->resolveSchemaSlug(payload: $payload); if (in_array($schemaSlug, self::RELEVANT_SCHEMAS, true) === false) { return; } @@ -141,7 +141,11 @@ private function extractObject(Event $event): ?array if (is_object($object) === true && method_exists($object, 'jsonSerialize') === true) { $serialized = $object->jsonSerialize(); - return is_array($serialized) ? $serialized : null; + if (is_array($serialized) === true) { + return $serialized; + } + + return null; } return null; diff --git a/lib/Listener/ParaferingAuditListener.php b/lib/Listener/ParaferingAuditListener.php index dd18d40f..89b2e4a2 100644 --- a/lib/Listener/ParaferingAuditListener.php +++ b/lib/Listener/ParaferingAuditListener.php @@ -71,7 +71,7 @@ public function handle(Event $event): void } try { - $contentSnapshot = $this->fetchContentSnapshot($event->getVoorstelId()); + $contentSnapshot = $this->fetchContentSnapshot(voorstelId: $event->getVoorstelId()); $this->auditTrailService->record( voorstelId: $event->getVoorstelId(), diff --git a/lib/Listener/RoleMutationListener.php b/lib/Listener/RoleMutationListener.php index d384bbf0..5960d016 100644 --- a/lib/Listener/RoleMutationListener.php +++ b/lib/Listener/RoleMutationListener.php @@ -84,7 +84,7 @@ public function handle(Event $event): void } try { - $object = $this->extractObject($event); + $object = $this->extractObject(event: $event); if ($object === null) { return; } diff --git a/lib/Repair/MigrateWorkflowDefinitions.php b/lib/Repair/MigrateWorkflowDefinitions.php index 191e5647..9d9d3dc2 100644 --- a/lib/Repair/MigrateWorkflowDefinitions.php +++ b/lib/Repair/MigrateWorkflowDefinitions.php @@ -116,7 +116,7 @@ public function run(IOutput $output): void $migrated = 0; $skipped = 0; foreach ($caseTypes as $caseType) { - $row = $this->normalize($caseType); + $row = $this->normalize(row: $caseType); if ($row === null) { continue; } @@ -140,11 +140,11 @@ public function run(IOutput $output): void } $template = $this->buildTemplateFor( - $caseTypeId, - $row, - $objectService, - $register, - $statusSchema, + caseTypeId: $caseTypeId, + caseType: $row, + objectService: $objectService, + register: $register, + statusSchema: $statusSchema, ); if ($template === null) { @@ -165,7 +165,7 @@ public function run(IOutput $output): void continue; } - $createdNormalized = $this->normalize($created); + $createdNormalized = $this->normalize(row: $created); $newId = (string) ($createdNormalized['id'] ?? ''); // Pin the caseType to the new template. @@ -187,11 +187,11 @@ public function run(IOutput $output): void // Pin existing open cases to workflowVersion = 1. if ($caseSchema !== '') { $this->pinOpenCases( - $objectService, - $register, - $caseSchema, - $caseTypeId, - $newId, + objectService: $objectService, + register: $register, + caseSchema: $caseSchema, + caseTypeId: $caseTypeId, + templateId: $newId, ); } }//end if @@ -245,7 +245,7 @@ private function buildTemplateFor( $statuses = []; foreach ($statusRows as $raw) { - $row = $this->normalize($raw); + $row = $this->normalize(row: $raw); if ($row !== null && (string) ($row['id'] ?? '') !== '') { $statuses[] = $row; } @@ -357,7 +357,7 @@ private function pinOpenCases( } foreach ($cases as $row) { - $case = $this->normalize($row); + $case = $this->normalize(row: $row); if ($case === null) { continue; } diff --git a/lib/Repair/SeedBezwaarWorkflowDefinition.php b/lib/Repair/SeedBezwaarWorkflowDefinition.php index 4192d6fc..b9e8d847 100644 --- a/lib/Repair/SeedBezwaarWorkflowDefinition.php +++ b/lib/Repair/SeedBezwaarWorkflowDefinition.php @@ -135,7 +135,7 @@ public function run(IOutput $output): void return; } - $caseType = $this->normalize($caseTypes[0]); + $caseType = $this->normalize(object: $caseTypes[0]); if ($caseType === null) { return; } @@ -176,7 +176,7 @@ public function run(IOutput $output): void $statusByName = []; foreach ($statusRows as $raw) { - $row = $this->normalize($raw); + $row = $this->normalize(object: $raw); if ($row === null) { continue; } @@ -208,12 +208,16 @@ public function run(IOutput $output): void } } - $steps = $this->buildSteps($statusByName, $required); - $transitions = $this->buildTransitions($statusByName); + $steps = $this->buildSteps(statusByName: $statusByName, ordered: $required); + $transitions = $this->buildTransitions(statusByName: $statusByName); + + $description = 'Canonical bezwaar lifecycle state machine: Ontvangen → Afgehandeld with terminal ' + .'Niet-ontvankelijk/Ingetrokken. Transitions wired through the status-transition-engine; ' + .'deadlines computed declaratively on the bezwaar schema (x-openregister-calculations, ADR-022).'; $template = [ 'title' => 'Bezwaar — AWB-compliant workflow', - 'description' => 'Canonical bezwaar lifecycle state machine: Ontvangen → Afgehandeld with terminal Niet-ontvankelijk/Ingetrokken. Transitions wired through the status-transition-engine; deadlines computed declaratively on the bezwaar schema (x-openregister-calculations, ADR-022).', + 'description' => $description, 'caseType' => $caseTypeId, 'version' => 1, 'isActive' => true, @@ -239,7 +243,7 @@ public function run(IOutput $output): void return; } - $createdNormalized = $this->normalize($created); + $createdNormalized = $this->normalize(object: $created); $newId = (string) ($createdNormalized['id'] ?? ''); if ($newId !== '') { @@ -319,8 +323,13 @@ private function buildTransitions(array $statusByName): array $transitions = []; foreach ($matrix as $row) { [$fromName, $toName, $label] = $row; - $fromId = ($fromName === '*') ? '*' : (string) ($statusByName[$fromName]['id'] ?? ''); - $toId = (string) ($statusByName[$toName]['id'] ?? ''); + if ($fromName === '*') { + $fromId = '*'; + } else { + $fromId = (string) ($statusByName[$fromName]['id'] ?? ''); + } + + $toId = (string) ($statusByName[$toName]['id'] ?? ''); $guards = []; if (isset(self::LEGAL_POSTURE_TARGETS[$toName]) === true) { @@ -362,7 +371,11 @@ private function normalize(mixed $object): ?array if (is_object($object) === true && method_exists($object, 'jsonSerialize') === true) { $serialized = $object->jsonSerialize(); - return is_array($serialized) ? $serialized : null; + if (is_array($serialized) === true) { + return $serialized; + } + + return null; } return null; diff --git a/lib/Service/Actions/ActionRegistry.php b/lib/Service/Actions/ActionRegistry.php index b4b94b58..17009a9c 100644 --- a/lib/Service/Actions/ActionRegistry.php +++ b/lib/Service/Actions/ActionRegistry.php @@ -121,7 +121,7 @@ public function resolve(string $tenantId, string $slug): ?array } try { - $action = $this->findAction($slug); + $action = $this->findAction(slug: $slug); } catch (\Throwable $e) { $this->logger->error( 'ActionRegistry: failed to load automaticAction', diff --git a/lib/Service/Actions/CallWebhookHandler.php b/lib/Service/Actions/CallWebhookHandler.php index c67a1637..0dec3bd1 100644 --- a/lib/Service/Actions/CallWebhookHandler.php +++ b/lib/Service/Actions/CallWebhookHandler.php @@ -56,6 +56,8 @@ public function __construct( /** * {@inheritDoc} + * + * @return string The action type slug handled by this handler. */ public function type(): string { @@ -64,14 +66,25 @@ public function type(): string /** * {@inheritDoc} + * + * @param array $actionConfig Resolved action config array. + * @param array $case The full case object. + * @param array $transitionContext Transition context (carries dryRun, tenantId). + * + * @return ActionResult The outcome of the webhook dispatch. */ public function handle(array $actionConfig, array $case, array $transitionContext): ActionResult { try { - $url = $this->resolveUrl($actionConfig, $transitionContext); + $url = $this->resolveUrl(config: $actionConfig, context: $transitionContext); $payloadTemplate = (string) ($actionConfig['payloadTemplate'] ?? ''); - $payload = $payloadTemplate === '' ? json_encode(['case' => $case], JSON_THROW_ON_ERROR) : $this->renderTemplate($payloadTemplate, $case); - $timeoutSec = (int) ($actionConfig['timeoutSec'] ?? self::DEFAULT_TIMEOUT_SEC); + if ($payloadTemplate === '') { + $payload = json_encode(['case' => $case], JSON_THROW_ON_ERROR); + } else { + $payload = $this->renderTemplate(template: $payloadTemplate, case: $case); + } + + $timeoutSec = (int) ($actionConfig['timeoutSec'] ?? self::DEFAULT_TIMEOUT_SEC); $preview = [ 'url' => $url, @@ -98,7 +111,7 @@ public function handle(array $actionConfig, array $case, array $transitionContex ] ); } catch (\Throwable $e) { - $errorCode = $this->classifyHttpException($e); + $errorCode = $this->classifyHttpException(e: $e); $this->logger->error( 'CallWebhookHandler: webhook call failed', [ diff --git a/lib/Service/Actions/CreateDocumentHandler.php b/lib/Service/Actions/CreateDocumentHandler.php index c24539eb..bab93047 100644 --- a/lib/Service/Actions/CreateDocumentHandler.php +++ b/lib/Service/Actions/CreateDocumentHandler.php @@ -54,6 +54,8 @@ public function __construct( /** * {@inheritDoc} + * + * @return string The action type slug handled by this handler. */ public function type(): string { @@ -62,19 +64,25 @@ public function type(): string /** * {@inheritDoc} + * + * @param array $actionConfig Resolved action config array. + * @param array $case The full case object. + * @param array $transitionContext Transition context (carries dryRun). + * + * @return ActionResult The outcome of the document creation. */ public function handle(array $actionConfig, array $case, array $transitionContext): ActionResult { try { $templateSlug = (string) ($actionConfig['templateSlug'] ?? ''); $outputName = $this->renderTemplate( - (string) ($actionConfig['outputName'] ?? 'document.pdf'), - $case + template: (string) ($actionConfig['outputName'] ?? 'document.pdf'), + case: $case ); $mergeFields = (array) ($actionConfig['mergeFields'] ?? []); $renderedFields = []; foreach ($mergeFields as $key => $tpl) { - $renderedFields[(string) $key] = $this->renderTemplate((string) $tpl, $case); + $renderedFields[(string) $key] = $this->renderTemplate(template: (string) $tpl, case: $case); } $preview = [ diff --git a/lib/Service/Actions/MergeTemplateHandler.php b/lib/Service/Actions/MergeTemplateHandler.php index cb3f760a..198c0416 100644 --- a/lib/Service/Actions/MergeTemplateHandler.php +++ b/lib/Service/Actions/MergeTemplateHandler.php @@ -58,6 +58,8 @@ public function __construct( /** * {@inheritDoc} + * + * @return string The action type slug handled by this handler. */ public function type(): string { @@ -66,13 +68,19 @@ public function type(): string /** * {@inheritDoc} + * + * @param array $actionConfig Resolved action config array. + * @param array $case The full case object. + * @param array $transitionContext Transition context (carries dryRun). + * + * @return ActionResult The outcome of the template merge. */ public function handle(array $actionConfig, array $case, array $transitionContext): ActionResult { try { $template = (string) ($actionConfig['template'] ?? ($actionConfig['templateSlug'] ?? '')); $targetField = (string) ($actionConfig['targetField'] ?? ''); - $rendered = $this->renderTemplate($template, $case); + $rendered = $this->renderTemplate(template: $template, case: $case); $preview = [ 'targetField' => $targetField, diff --git a/lib/Service/Actions/NotifyRoleHandler.php b/lib/Service/Actions/NotifyRoleHandler.php index a412d3b0..9a95697e 100644 --- a/lib/Service/Actions/NotifyRoleHandler.php +++ b/lib/Service/Actions/NotifyRoleHandler.php @@ -54,6 +54,8 @@ public function __construct( /** * {@inheritDoc} + * + * @return string The action type slug handled by this handler. */ public function type(): string { @@ -62,17 +64,23 @@ public function type(): string /** * {@inheritDoc} + * + * @param array $actionConfig Resolved action config array. + * @param array $case The full case object. + * @param array $transitionContext Transition context (carries dryRun). + * + * @return ActionResult The outcome of the role notification. */ public function handle(array $actionConfig, array $case, array $transitionContext): ActionResult { try { $roleSlug = (string) ($actionConfig['roleSlug'] ?? ''); $message = $this->renderTemplate( - (string) ($actionConfig['messageTemplate'] ?? ''), - $case + template: (string) ($actionConfig['messageTemplate'] ?? ''), + case: $case ); - $recipients = $this->resolveRoleMembers($roleSlug, $case); + $recipients = $this->resolveRoleMembers(roleSlug: $roleSlug, case: $case); $preview = [ 'roleSlug' => $roleSlug, 'recipients' => $recipients, diff --git a/lib/Service/Actions/ScheduleReminderHandler.php b/lib/Service/Actions/ScheduleReminderHandler.php index 2ea7a656..a1936e0e 100644 --- a/lib/Service/Actions/ScheduleReminderHandler.php +++ b/lib/Service/Actions/ScheduleReminderHandler.php @@ -63,6 +63,8 @@ public function __construct( /** * {@inheritDoc} + * + * @return string The action type slug handled by this handler. */ public function type(): string { @@ -71,24 +73,36 @@ public function type(): string /** * {@inheritDoc} + * + * @param array $actionConfig Resolved action config array. + * @param array $case The full case object. + * @param array $transitionContext Transition context (carries dryRun). + * + * @return ActionResult The outcome of scheduling the reminder. */ public function handle(array $actionConfig, array $case, array $transitionContext): ActionResult { try { $offsetIso = (string) ($actionConfig['offsetIso8601'] ?? ''); $message = $this->renderTemplate( - (string) ($actionConfig['messageTemplate'] ?? ''), - $case + template: (string) ($actionConfig['messageTemplate'] ?? ''), + case: $case ); $recipient = $this->resolveRecipient( - (string) ($actionConfig['recipientRef'] ?? ''), - $case + recipientRef: (string) ($actionConfig['recipientRef'] ?? ''), + case: $case ); - $fireAt = $this->computeFireTime($offsetIso); + $fireAt = $this->computeFireTime(offsetIso: $offsetIso); + if ($fireAt === null) { + $fireAtIso = null; + } else { + $fireAtIso = $fireAt->format(\DateTimeInterface::ATOM); + } + $preview = [ 'offsetIso8601' => $offsetIso, - 'fireAtIso' => $fireAt === null ? null : $fireAt->format(\DateTimeInterface::ATOM), + 'fireAtIso' => $fireAtIso, 'recipient' => $recipient, 'message' => $message, ]; diff --git a/lib/Service/Actions/SendEmailHandler.php b/lib/Service/Actions/SendEmailHandler.php index 7d20e05b..575d8810 100644 --- a/lib/Service/Actions/SendEmailHandler.php +++ b/lib/Service/Actions/SendEmailHandler.php @@ -56,6 +56,8 @@ public function __construct( /** * {@inheritDoc} + * + * @return string The action type slug handled by this handler. */ public function type(): string { @@ -64,21 +66,27 @@ public function type(): string /** * {@inheritDoc} + * + * @param array $actionConfig Resolved action config array. + * @param array $case The full case object. + * @param array $transitionContext Transition context (carries dryRun). + * + * @return ActionResult The outcome of sending the email. */ public function handle(array $actionConfig, array $case, array $transitionContext): ActionResult { try { $subject = $this->renderTemplate( - (string) ($actionConfig['subjectTemplate'] ?? ''), - $case + template: (string) ($actionConfig['subjectTemplate'] ?? ''), + case: $case ); $body = $this->renderTemplate( - (string) ($actionConfig['bodyTemplate'] ?? ''), - $case + template: (string) ($actionConfig['bodyTemplate'] ?? ''), + case: $case ); $recipient = $this->resolveRecipient( - (string) ($actionConfig['recipientRef'] ?? ''), - $case + recipientRef: (string) ($actionConfig['recipientRef'] ?? ''), + case: $case ); $preview = [ diff --git a/lib/Service/AdviceService.php b/lib/Service/AdviceService.php index e839ede1..4dc5e362 100644 --- a/lib/Service/AdviceService.php +++ b/lib/Service/AdviceService.php @@ -102,7 +102,7 @@ public function transitionStatus(string $adviceId, string $to, array $payload=[] throw new \RuntimeException('Advice schema is not configured'); } - $current = $this->loadAdvice($adviceId); + $current = $this->loadAdvice(adviceId: $adviceId); if ($current === null) { throw new \RuntimeException('Advice request not found'); } @@ -127,9 +127,9 @@ public function transitionStatus(string $adviceId, string $to, array $payload=[] throw new \RuntimeException('Could not update advice request'); } - $advice = $this->normalizeResult($advice); + $advice = $this->normalizeResult(result: $advice); - $this->fireTransitionNotification($to, $current, $adviceId); + $this->fireTransitionNotification(to: $to, current: $current, adviceId: $adviceId); return $advice; }//end transitionStatus() @@ -145,7 +145,7 @@ public function transitionStatus(string $adviceId, string $to, array $payload=[] */ public function dispatchReminder(string $adviceId): void { - $advice = $this->loadAdvice($adviceId); + $advice = $this->loadAdvice(adviceId: $adviceId); if ($advice === null) { return; } @@ -155,7 +155,7 @@ public function dispatchReminder(string $adviceId): void return; } - $this->sendUserNotification($adviseur, 'advies_herinnering', $adviceId); + $this->sendUserNotification(userId: $adviseur, subject: 'advies_herinnering', objectId: $adviceId); }//end dispatchReminder() /** @@ -170,7 +170,7 @@ public function dispatchReminder(string $adviceId): void */ public function applyWorkflowGuard(string $caseId): array { - $all = $this->getAdviceForCase($caseId); + $all = $this->getAdviceForCase(caseId: $caseId); $pending = []; foreach ($all as $advice) { @@ -284,7 +284,7 @@ public function getOpenAdvice(): array public function expireAdvice(string $adviceId): array { try { - return $this->transitionStatus($adviceId, 'verlopen'); + return $this->transitionStatus(adviceId: $adviceId, to: 'verlopen'); } catch (\Throwable $e) { $this->logger->error( 'Procest: failed to expire advice: '.$e->getMessage(), @@ -325,7 +325,7 @@ private function loadAdvice(string $adviceId): ?array return null; } - return $this->normalizeResult($advice); + return $this->normalizeResult(result: $advice); }//end loadAdvice() /** @@ -343,10 +343,10 @@ private function fireTransitionNotification(string $to, array $current, string $ $adviseur = (string) ($current['adviseur'] ?? ''); if ($adviseur !== '') { $this->sendUserNotification( - $adviseur, - 'advies_aangevraagd', - $adviceId, - (string) ($current['onderwerp'] ?? '') + userId: $adviseur, + subject: 'advies_aangevraagd', + objectId: $adviceId, + message: (string) ($current['onderwerp'] ?? '') ); } @@ -356,7 +356,7 @@ private function fireTransitionNotification(string $to, array $current, string $ if ($to === 'ontvangen') { $caller = $this->getUserId(); if ($caller !== '') { - $this->sendUserNotification($caller, 'advies_ontvangen', $adviceId); + $this->sendUserNotification(userId: $caller, subject: 'advies_ontvangen', objectId: $adviceId); } } }//end fireTransitionNotification() diff --git a/lib/Service/Bezwaar/HearingService.php b/lib/Service/Bezwaar/HearingService.php index 5daec988..e8e4f895 100644 --- a/lib/Service/Bezwaar/HearingService.php +++ b/lib/Service/Bezwaar/HearingService.php @@ -147,8 +147,8 @@ public function schedule( ); } - $scheduled = $this->parseDateTime($scheduledDate); - $deadline = $this->computeInspectionDeadline($scheduled); + $scheduled = $this->parseDateTime(value: $scheduledDate); + $deadline = $this->computeInspectionDeadline(scheduled: $scheduled); $now = new \DateTimeImmutable(); $this->guardInspectionFloor( @@ -156,7 +156,11 @@ public function schedule( today: $now, ); - $available = isset($payload['inspectionAvailableFrom']) === true ? $this->parseDate((string) $payload['inspectionAvailableFrom']) : $now->setTime(0, 0, 0); + if (isset($payload['inspectionAvailableFrom']) === true) { + $available = $this->parseDate(value: (string) $payload['inspectionAvailableFrom']); + } else { + $available = $now->setTime(0, 0, 0); + } if ($available > $deadline) { // Per design.md: inspectionAvailableFrom must be ≤ inspectionDeadline. @@ -328,11 +332,16 @@ public function recordAttendance( $now = new \DateTimeImmutable(); $scheduledRaw = (string) ($current['scheduledDate'] ?? ''); - $scheduled = $scheduledRaw !== '' ? $this->parseDateTime($scheduledRaw) : $now; - $freezeAt = $scheduled->modify( + if ($scheduledRaw !== '') { + $scheduled = $this->parseDateTime(value: $scheduledRaw); + } else { + $scheduled = $now; + } + + $freezeAt = $scheduled->modify( '+'.self::ATTENDANCE_GRACE_HOURS.' hour' ); - $isFrozen = $now > $freezeAt; + $isFrozen = $now > $freezeAt; $existing = (array) ($current['attendance'] ?? []); $merged = $existing; @@ -473,9 +482,21 @@ public function addMinutes( }//end if }//end if + if ($summary !== '') { + $minutesSummary = $summary; + } else { + $minutesSummary = null; + } + + if ($document !== '') { + $minutesDocument = $document; + } else { + $minutesDocument = null; + } + $update = [ - 'minutesSummary' => $summary !== '' ? $summary : null, - 'minutesDocument' => $document !== '' ? $document : null, + 'minutesSummary' => $minutesSummary, + 'minutesDocument' => $minutesDocument, 'status' => 'uitgevoerd', ]; diff --git a/lib/Service/Inspection/ChecklistService.php b/lib/Service/Inspection/ChecklistService.php index c9f9213d..cabedb95 100644 --- a/lib/Service/Inspection/ChecklistService.php +++ b/lib/Service/Inspection/ChecklistService.php @@ -330,13 +330,23 @@ public function validateResponse(array $item, array $payload): void $range = $item['numericRange'] ?? null; if (is_array($range) === true && array_key_exists('numericValue', $payload) === true) { $val = (float) $payload['numericValue']; - $min = array_key_exists('min', $range) === true ? (float) $range['min'] : null; - $max = array_key_exists('max', $range) === true ? (float) $range['max'] : null; + if (array_key_exists('min', $range) === true) { + $min = (float) $range['min']; + } else { + $min = null; + } + + if (array_key_exists('max', $range) === true) { + $max = (float) $range['max']; + } else { + $max = null; + } + if (($min !== null && $val < $min) || ($max !== null && $val > $max)) { throw new RuntimeException('OUT_OF_RANGE'); } - } - } + }//end if + }//end if if ($type === 'meerkeuze') { $choices = $item['choices'] ?? []; @@ -571,14 +581,24 @@ private function classifyResponse(array $response, ?array $item): string } $val = (float) $response['numericValue']; - $min = array_key_exists('min', $range) === true ? (float) $range['min'] : null; - $max = array_key_exists('max', $range) === true ? (float) $range['max'] : null; + if (array_key_exists('min', $range) === true) { + $min = (float) $range['min']; + } else { + $min = null; + } + + if (array_key_exists('max', $range) === true) { + $max = (float) $range['max']; + } else { + $max = null; + } + if (($min !== null && $val < $min) || ($max !== null && $val > $max)) { return 'fail'; } return 'pass'; - } + }//end if if ($type === 'meerkeuze') { $choices = $item['choices'] ?? []; diff --git a/lib/Service/LocationService.php b/lib/Service/LocationService.php index 2b840090..ef332ebb 100644 --- a/lib/Service/LocationService.php +++ b/lib/Service/LocationService.php @@ -105,14 +105,24 @@ public function validate(array $payload): array { $errors = []; - $source = isset($payload['source']) === true ? (string) $payload['source'] : ''; + if (isset($payload['source']) === true) { + $source = (string) $payload['source']; + } else { + $source = ''; + } + if ($source === '') { $errors[] = 'source.required'; } else if (in_array($source, self::VALID_SOURCES, true) === false) { $errors[] = 'source.invalid'; } - $caseId = isset($payload['case']) === true ? (string) $payload['case'] : ''; + if (isset($payload['case']) === true) { + $caseId = (string) $payload['case']; + } else { + $caseId = ''; + } + if ($caseId === '') { $errors[] = 'case.required'; } @@ -232,13 +242,17 @@ public function reverseGeocode(float $latitude, float $longitude): ?array // envelope: response.docs[]. Each doc may carry `nummeraanduiding_id` // (or `id` when type = 'adres'), `weergavenaam` (the formatted // address), and `afstand` (distance from the query point in metres). - $docs = $this->extractDocs($response); + $docs = $this->extractDocs(response: $response); if ($docs === []) { return null; } - $best = $docs[0]; - $distance = isset($best['afstand']) === true && is_numeric($best['afstand']) === true ? (float) $best['afstand'] : null; + $best = $docs[0]; + if (isset($best['afstand']) === true && is_numeric($best['afstand']) === true) { + $distance = (float) $best['afstand']; + } else { + $distance = null; + } if ($distance !== null && $distance > (float) self::REVERSE_MAX_DISTANCE_M) { return null; @@ -254,7 +268,11 @@ public function reverseGeocode(float $latitude, float $longitude): ?array $nummeraanduidingId = (string) $best['id']; } - $formattedAddress = isset($best['weergavenaam']) === true ? (string) $best['weergavenaam'] : ''; + if (isset($best['weergavenaam']) === true) { + $formattedAddress = (string) $best['weergavenaam']; + } else { + $formattedAddress = ''; + } if ($nummeraanduidingId === '' && $formattedAddress === '') { return null; @@ -346,7 +364,7 @@ public function attachToCase(string $caseId, array $location): ?array $payload = $location; $payload['case'] = $caseId; - $errors = $this->validate($payload); + $errors = $this->validate(payload: $payload); if (count($errors) > 0) { throw new \RuntimeException( 'Location payload failed validation: '.implode(', ', $errors) diff --git a/lib/Service/ParafeerRouteService.php b/lib/Service/ParafeerRouteService.php index 684a9483..1ccc06f1 100644 --- a/lib/Service/ParafeerRouteService.php +++ b/lib/Service/ParafeerRouteService.php @@ -84,6 +84,7 @@ class ParafeerRouteService * @param IUserSession $userSession The current Nextcloud user session * @param LoggerInterface $logger The logger * @param RoleResolverService $roleResolver Central role-routing engine + * @param IEventDispatcher $eventDispatcher The event dispatcher */ public function __construct( private readonly SettingsService $settingsService, @@ -240,9 +241,14 @@ public function completeStep(string $voorstelId, array $actionData): array $objectService->saveObject($register, $actieSchema, $actieData); - $action = (string) ($actionData['action'] ?? 'parafered'); - $transition = ($action === 'advised') ? 'advised' : 'paraferd'; - $actorRole = ($action === 'advised') ? 'adviseur' : 'parafeerder'; + $action = (string) ($actionData['action'] ?? 'parafered'); + if ($action === 'advised') { + $transition = 'advised'; + $actorRole = 'adviseur'; + } else { + $transition = 'paraferd'; + $actorRole = 'parafeerder'; + } $this->dispatchTransition( voorstelId: (string) ($voorstel['id'] ?? $voorstel['uuid'] ?? $voorstelId), diff --git a/lib/Service/Parafering/AuditTrailService.php b/lib/Service/Parafering/AuditTrailService.php index 4922f68b..fda0ea25 100644 --- a/lib/Service/Parafering/AuditTrailService.php +++ b/lib/Service/Parafering/AuditTrailService.php @@ -132,7 +132,7 @@ public function record( 'actorRole' => $actorRole, 'timestamp' => $timestamp, 'contentSnapshot' => $contentSnapshot, - 'ipAddress' => $this->redactIp((string) $this->request->getRemoteAddress()), + 'ipAddress' => $this->redactIp(ip: (string) $this->request->getRemoteAddress()), ]; if ($step !== null && $step !== '') { @@ -143,11 +143,11 @@ public function record( $entry['reason'] = $reason; } - $entry['auditEntryHash'] = $this->computeHash($entry); + $entry['auditEntryHash'] = $this->computeHash(entry: $entry); $saved = $objectService->saveObject($register, $schema, $entry); - return $this->toArray($saved); + return $this->toArray(value: $saved); } catch (Throwable $e) { // Audit-write failure MUST NOT propagate back to the routing // service — operational transitions must not be blocked by audit @@ -244,7 +244,7 @@ public function export(string $voorstelId, string $voorstelOnderwerp, string $ex $entries = []; if (is_array($results) === true) { foreach ($results as $row) { - $entries[] = $this->toArray($row); + $entries[] = $this->toArray(value: $row); } } @@ -263,7 +263,13 @@ static function (array $a, array $b): int { } } - $retentionUntil = $this->computeRetentionUntil($completed); + $retentionUntil = $this->computeRetentionUntil(completedEntry: $completed); + + if ($completed !== null) { + $selectielijstCategory = 'Bestuurlijke besluitvorming — bewaartermijn 20 jaar'; + } else { + $selectielijstCategory = 'Algemene administratieve correspondentie — bewaartermijn 7 jaar'; + } return [ 'metadata' => [ @@ -274,7 +280,7 @@ static function (array $a, array $b): int { 'voorstel' => $voorstelId, 'voorstelOnderwerp' => $voorstelOnderwerp, 'retentionUntil' => $retentionUntil, - 'selectielijstCategory' => $completed !== null ? 'Bestuurlijke besluitvorming — bewaartermijn 20 jaar' : 'Algemene administratieve correspondentie — bewaartermijn 7 jaar', + 'selectielijstCategory' => $selectielijstCategory, 'exportedBy' => $exportedBy, 'entryCount' => count($entries), ], @@ -341,9 +347,19 @@ private function redactIp(string $ip): string } if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false) { - $expanded = inet_ntop(inet_pton($ip) ?: ''); + $packed = inet_pton($ip); + if ($packed === false) { + $packed = ''; + } + + $expanded = inet_ntop($packed); if (is_string($expanded) === true) { - $hex = bin2hex(inet_pton($expanded) ?: ''); + $packedExpanded = inet_pton($expanded); + if ($packedExpanded === false) { + $packedExpanded = ''; + } + + $hex = bin2hex($packedExpanded); if (strlen($hex) === 32) { return implode( ':', @@ -359,7 +375,7 @@ private function redactIp(string $ip): string ], ); } - } + }//end if }//end if return ''; diff --git a/lib/Service/RoleResolverService.php b/lib/Service/RoleResolverService.php index 7f6048f2..85c1c990 100644 --- a/lib/Service/RoleResolverService.php +++ b/lib/Service/RoleResolverService.php @@ -70,6 +70,8 @@ class RoleResolverService /** * The local cache instance (APCu when available). + * + * @var ICache */ private ICache $cache; @@ -150,13 +152,18 @@ public function resolve(array $rule, array $case): array $strategyName = (string) ($rule['strategy'] ?? ''); if ($this->registry->has($strategyName) === false) { throw new RoutingStrategyMissingException( - sprintf('Routing strategy "%s" is not registered', $strategyName) + message: sprintf('Routing strategy "%s" is not registered', $strategyName) ); } $caseId = (string) ($case['id'] ?? ($case['uuid'] ?? '')); $cacheKey = $this->cacheKey(rule: $rule, caseId: $caseId); - $cacheHit = ($caseId !== '') ? $this->cache->get($cacheKey) : null; + if ($caseId !== '') { + $cacheHit = $this->cache->get($cacheKey); + } else { + $cacheHit = null; + } + if (is_array($cacheHit) === true) { return array_values( array_map( @@ -166,7 +173,7 @@ public function resolve(array $rule, array $case): array ); } - $roles = $this->loadCaseRoles($caseId); + $roles = $this->loadCaseRoles(caseId: $caseId); $strategy = $this->registry->get($strategyName); $primary = $strategy->resolve($rule, $case, $roles); @@ -216,7 +223,7 @@ public function canExecute(array $rule, array $case, string $userId): bool } try { - $allowed = $this->resolve($rule, $case); + $allowed = $this->resolve(rule: $rule, case: $case); } catch (RoutingStrategyMissingException $e) { $this->logger->warning( 'Procest: routing guard rejected — missing strategy: '.$e->getMessage(), @@ -373,7 +380,7 @@ private function loadCaseRoles(string $caseId): array $rows = []; foreach ((array) $records as $record) { - $row = $this->toArray($record); + $row = $this->toArray(value: $record); if ($row !== []) { $rows[] = $row; } diff --git a/lib/Service/Routing/Strategy/HierarchicalStrategy.php b/lib/Service/Routing/Strategy/HierarchicalStrategy.php index bdee5cb0..e710b818 100644 --- a/lib/Service/Routing/Strategy/HierarchicalStrategy.php +++ b/lib/Service/Routing/Strategy/HierarchicalStrategy.php @@ -37,6 +37,8 @@ class HierarchicalStrategy implements RoutingStrategyInterface { /** * {@inheritDoc} + * + * @return string The strategy name. */ public function name(): string { diff --git a/lib/Service/Routing/Strategy/LeastLoadedStrategy.php b/lib/Service/Routing/Strategy/LeastLoadedStrategy.php index 17ad2756..084106f0 100644 --- a/lib/Service/Routing/Strategy/LeastLoadedStrategy.php +++ b/lib/Service/Routing/Strategy/LeastLoadedStrategy.php @@ -38,6 +38,8 @@ class LeastLoadedStrategy implements RoutingStrategyInterface { /** * {@inheritDoc} + * + * @return string The strategy name. */ public function name(): string { diff --git a/lib/Service/Routing/Strategy/OrSetStrategy.php b/lib/Service/Routing/Strategy/OrSetStrategy.php index e59a918c..5503573b 100644 --- a/lib/Service/Routing/Strategy/OrSetStrategy.php +++ b/lib/Service/Routing/Strategy/OrSetStrategy.php @@ -37,6 +37,8 @@ class OrSetStrategy implements RoutingStrategyInterface { /** * {@inheritDoc} + * + * @return string The strategy name. */ public function name(): string { diff --git a/lib/Service/Routing/Strategy/RoundRobinStrategy.php b/lib/Service/Routing/Strategy/RoundRobinStrategy.php index 77338a8d..856dd74a 100644 --- a/lib/Service/Routing/Strategy/RoundRobinStrategy.php +++ b/lib/Service/Routing/Strategy/RoundRobinStrategy.php @@ -49,6 +49,8 @@ public function __construct(private readonly IAppConfig $appConfig) /** * {@inheritDoc} + * + * @return string The strategy name. */ public function name(): string { diff --git a/lib/Service/Routing/Strategy/SingleRoleStrategy.php b/lib/Service/Routing/Strategy/SingleRoleStrategy.php index e47a9e70..71f9f984 100644 --- a/lib/Service/Routing/Strategy/SingleRoleStrategy.php +++ b/lib/Service/Routing/Strategy/SingleRoleStrategy.php @@ -37,6 +37,8 @@ class SingleRoleStrategy implements RoutingStrategyInterface { /** * {@inheritDoc} + * + * @return string The strategy name. */ public function name(): string { diff --git a/lib/Service/Routing/StrategyRegistry.php b/lib/Service/Routing/StrategyRegistry.php index f3e062e8..fda8e469 100644 --- a/lib/Service/Routing/StrategyRegistry.php +++ b/lib/Service/Routing/StrategyRegistry.php @@ -68,11 +68,11 @@ public function __construct( RoundRobinStrategy $roundRobin, LeastLoadedStrategy $leastLoaded, ) { - $this->register($singleRole); - $this->register($orSet); - $this->register($hierarchical); - $this->register($roundRobin); - $this->register($leastLoaded); + $this->register(strategy: $singleRole); + $this->register(strategy: $orSet); + $this->register(strategy: $hierarchical); + $this->register(strategy: $roundRobin); + $this->register(strategy: $leastLoaded); }//end __construct() /** diff --git a/lib/Service/StatusTransitionService.php b/lib/Service/StatusTransitionService.php index b058bc71..69f7c743 100644 --- a/lib/Service/StatusTransitionService.php +++ b/lib/Service/StatusTransitionService.php @@ -315,8 +315,14 @@ public function replay(string $caseId): array return ['history' => [], 'replayable' => false]; } + if (is_array($records) === true) { + $recordList = $records; + } else { + $recordList = []; + } + $list = []; - foreach ((is_array($records) === true ? $records : []) as $record) { + foreach ($recordList as $record) { $list[] = $this->toArray(value: $record); } @@ -376,7 +382,11 @@ private function resolveUserId(?string $explicit): string } $user = $this->userSession->getUser(); - return $user === null ? '' : $user->getUID(); + if ($user === null) { + return ''; + } + + return $user->getUID(); }//end resolveUserId() /** @@ -543,7 +553,12 @@ private function validateStatusBelongsToCaseType(string $caseTypeId, string $sta } foreach ($statuses as $entry) { - $id = is_array($entry) === true ? (string) ($entry['id'] ?? ($entry['uuid'] ?? '')) : (string) $entry; + if (is_array($entry) === true) { + $id = (string) ($entry['id'] ?? ($entry['uuid'] ?? '')); + } else { + $id = (string) $entry; + } + if ($id === $statusTypeId) { return; } diff --git a/lib/Service/StepConfigValidator.php b/lib/Service/StepConfigValidator.php index c405ac14..7c99dfeb 100644 --- a/lib/Service/StepConfigValidator.php +++ b/lib/Service/StepConfigValidator.php @@ -133,9 +133,9 @@ public static function validate( if (is_array($config) === false) { $errors[] = self::error( - "steps[$stepIndex].config", - 'malformed_config', - 'config must be an object' + path: "steps[$stepIndex].config", + code: 'malformed_config', + message: 'config must be an object' ); return $errors; } @@ -144,34 +144,34 @@ public static function validate( $errors = array_merge( $errors, - self::validateSla($config['sla'] ?? null, $base.'.sla') + self::validateSla(sla: ($config['sla'] ?? null), path: $base.'.sla') ); $errors = array_merge( $errors, self::validateRequiredFields( - ($config['requiredFields'] ?? null), - ($caseTypeSchema['properties'] ?? []), - $base.'.requiredFields' + fields: ($config['requiredFields'] ?? null), + caseTypeProperties: ($caseTypeSchema['properties'] ?? []), + path: $base.'.requiredFields' ) ); $errors = array_merge( $errors, self::validateAutoActions( - ($config['autoActions'] ?? null), - $actionCatalog, - $base.'.autoActions' + actions: ($config['autoActions'] ?? null), + actionCatalog: $actionCatalog, + path: $base.'.autoActions' ) ); $errors = array_merge( $errors, self::validateEscalationRule( - ($config['escalationRule'] ?? null), - ($config['sla'] ?? null), - ($caseTypeSchema['roleTypes'] ?? []), - $base.'.escalationRule' + rule: ($config['escalationRule'] ?? null), + sla: ($config['sla'] ?? null), + roleTypes: ($caseTypeSchema['roleTypes'] ?? []), + path: $base.'.escalationRule' ) ); @@ -213,7 +213,7 @@ private static function validateSla(mixed $sla, string $path): array } if (is_array($sla) === false) { - return [self::error($path, 'malformed_sla', 'sla must be an object')]; + return [self::error(path: $path, code: 'malformed_sla', message: 'sla must be an object')]; } $errors = []; @@ -221,9 +221,9 @@ private static function validateSla(mixed $sla, string $path): array $value = ($sla['value'] ?? null); if (is_int($value) === false || $value < 1 || $value > self::SLA_VALUE_MAX) { $errors[] = self::error( - $path.'.value', - 'out_of_range', - 'sla.value must be a positive integer not greater than ' + path: $path.'.value', + code: 'out_of_range', + message: 'sla.value must be a positive integer not greater than ' .self::SLA_VALUE_MAX ); } @@ -231,9 +231,9 @@ private static function validateSla(mixed $sla, string $path): array $unit = ($sla['unit'] ?? null); if (is_string($unit) === false || in_array($unit, self::SLA_UNITS, true) === false) { $errors[] = self::error( - $path.'.unit', - 'unknown_sla_unit', - 'sla.unit must be one of: '.implode(', ', self::SLA_UNITS) + path: $path.'.unit', + code: 'unknown_sla_unit', + message: 'sla.unit must be one of: '.implode(', ', self::SLA_UNITS) ); } @@ -261,7 +261,7 @@ private static function validateRequiredFields( } if (is_array($fields) === false) { - return [self::error($path, 'malformed_required_fields', 'requiredFields must be an array')]; + return [self::error(path: $path, code: 'malformed_required_fields', message: 'requiredFields must be an array')]; } $errors = []; @@ -271,18 +271,18 @@ private static function validateRequiredFields( foreach ($fields as $index => $field) { if (is_string($field) === false || $field === '') { $errors[] = self::error( - $path."[$index]", - 'malformed_required_field', - 'requiredFields entries must be non-empty strings' + path: $path."[$index]", + code: 'malformed_required_field', + message: 'requiredFields entries must be non-empty strings' ); continue; } if ($checkRefs === true && array_key_exists($field, $caseTypeProperties) === false) { $errors[] = self::error( - $path."[$index]", - 'unknown_field_reference', - 'requiredFields entry does not resolve to a caseType property' + path: $path."[$index]", + code: 'unknown_field_reference', + message: 'requiredFields entry does not resolve to a caseType property' ); } } @@ -311,16 +311,16 @@ private static function validateAutoActions( } if (is_array($actions) === false) { - return [self::error($path, 'malformed_auto_actions', 'autoActions must be an array')]; + return [self::error(path: $path, code: 'malformed_auto_actions', message: 'autoActions must be an array')]; } $errors = []; foreach ($actions as $index => $action) { if (is_array($action) === false) { $errors[] = self::error( - $path."[$index]", - 'malformed_action_ref', - 'autoActions entries must be objects with `key` and `parameters`' + path: $path."[$index]", + code: 'malformed_action_ref', + message: 'autoActions entries must be objects with `key` and `parameters`' ); continue; } @@ -328,18 +328,18 @@ private static function validateAutoActions( $key = ($action['key'] ?? null); if (is_string($key) === false || $key === '') { $errors[] = self::error( - $path."[$index].key", - 'malformed_action_key', - 'autoActions[i].key must be a non-empty string' + path: $path."[$index].key", + code: 'malformed_action_key', + message: 'autoActions[i].key must be a non-empty string' ); continue; } if (in_array($key, $actionCatalog, true) === false) { $errors[] = self::error( - $path."[$index].key", - 'unknown_action_key', - 'autoActions[i].key is not registered in the action catalog' + path: $path."[$index].key", + code: 'unknown_action_key', + message: 'autoActions[i].key is not registered in the action catalog' ); } }//end foreach @@ -370,7 +370,7 @@ private static function validateEscalationRule( } if (is_array($rule) === false) { - return [self::error($path, 'malformed_escalation_rule', 'escalationRule must be an object')]; + return [self::error(path: $path, code: 'malformed_escalation_rule', message: 'escalationRule must be an object')]; } $errors = []; @@ -378,27 +378,27 @@ private static function validateEscalationRule( // Rule 6: escalationRule requires an SLA. if ($sla === null) { $errors[] = self::error( - $path, - 'escalation_requires_sla', - 'escalationRule cannot be set without a sla' + path: $path, + code: 'escalation_requires_sla', + message: 'escalationRule cannot be set without a sla' ); } $trigger = ($rule['trigger'] ?? null); if (is_string($trigger) === false || in_array($trigger, self::TRIGGERS, true) === false) { $errors[] = self::error( - $path.'.trigger', - 'unknown_trigger', - 'escalationRule.trigger must be one of: '.implode(', ', self::TRIGGERS) + path: $path.'.trigger', + code: 'unknown_trigger', + message: 'escalationRule.trigger must be one of: '.implode(', ', self::TRIGGERS) ); } $offset = ($rule['offset'] ?? null); if (is_int($offset) === false || $offset < 0) { $errors[] = self::error( - $path.'.offset', - 'out_of_range', - 'escalationRule.offset must be a non-negative integer' + path: $path.'.offset', + code: 'out_of_range', + message: 'escalationRule.offset must be a non-negative integer' ); } @@ -407,9 +407,9 @@ private static function validateEscalationRule( || in_array($offsetUnit, self::OFFSET_UNITS, true) === false ) { $errors[] = self::error( - $path.'.offsetUnit', - 'unknown_offset_unit', - 'escalationRule.offsetUnit must be one of: '.implode(', ', self::OFFSET_UNITS) + path: $path.'.offsetUnit', + code: 'unknown_offset_unit', + message: 'escalationRule.offsetUnit must be one of: '.implode(', ', self::OFFSET_UNITS) ); } @@ -421,9 +421,9 @@ private static function validateEscalationRule( && $offset > $sla['value'] ) { $errors[] = self::error( - $path.'.offset', - 'offset_exceeds_sla', - 'escalationRule.offset must not exceed sla.value when trigger is preBreach' + path: $path.'.offset', + code: 'offset_exceeds_sla', + message: 'escalationRule.offset must not exceed sla.value when trigger is preBreach' ); } @@ -437,18 +437,18 @@ private static function validateEscalationRule( if (is_string($role) === false || $role === '') { $errors[] = self::error( - $path.'.'.$roleKey, - 'malformed_role_reference', - $roleKey.' must be a non-empty role reference' + path: $path.'.'.$roleKey, + code: 'malformed_role_reference', + message: $roleKey.' must be a non-empty role reference' ); continue; } if ($checkRoles === true && array_key_exists($role, $roleTypes) === false) { $errors[] = self::error( - $path.'.'.$roleKey, - 'unknown_role_reference', - $roleKey.' does not resolve to a roleType on the linked caseType' + path: $path.'.'.$roleKey, + code: 'unknown_role_reference', + message: $roleKey.' does not resolve to a roleType on the linked caseType' ); } }//end foreach @@ -456,9 +456,9 @@ private static function validateEscalationRule( $openIncident = ($rule['openIncident'] ?? null); if ($openIncident !== null && is_bool($openIncident) === false) { $errors[] = self::error( - $path.'.openIncident', - 'malformed_open_incident', - 'escalationRule.openIncident must be a boolean' + path: $path.'.openIncident', + code: 'malformed_open_incident', + message: 'escalationRule.openIncident must be a boolean' ); } diff --git a/lib/Service/Vth/LhsRecommendationService.php b/lib/Service/Vth/LhsRecommendationService.php index c20ac5b1..2e989af0 100644 --- a/lib/Service/Vth/LhsRecommendationService.php +++ b/lib/Service/Vth/LhsRecommendationService.php @@ -121,8 +121,8 @@ public function recommend( throw new RuntimeException('Authenticatie vereist voor LHS-aanbeveling'); } - $matrix = $this->loadMatrix($lhsVersion); - $cellIndex = $this->indexCells($matrix['cells'] ?? []); + $matrix = $this->loadMatrix(version: $lhsVersion); + $cellIndex = $this->indexCells(cells: ($matrix['cells'] ?? [])); $key = $ernst.':'.$gedrag.':'.$actorType; if (isset($cellIndex[$key]) === false) { @@ -149,7 +149,7 @@ public function recommend( unset($recommendation['inspection']); } - return $this->persistRecommendation($recommendation); + return $this->persistRecommendation(row: $recommendation); }//end recommend() /** @@ -199,7 +199,12 @@ public function override( } $overrideUp = ($newSeverity > $recSeverity); - $authority = ($userRole === 'manager') ? 'manager' : 'inspector'; + if ($userRole === 'manager') { + $authority = 'manager'; + } else { + $authority = 'inspector'; + } + if ($overrideUp === true && $authority !== 'manager') { throw new RuntimeException('Verzwaring vereist managerrol'); } @@ -220,7 +225,7 @@ public function override( ] ); - return $this->persistRecommendation($updated, $recommendationId); + return $this->persistRecommendation(row: $updated, id: $recommendationId); }//end override() /** @@ -250,7 +255,11 @@ private function loadMatrix(?int $version): array throw new RuntimeException('LHS-matrix register/schema is niet geconfigureerd'); } - $filters = ($version === null) ? ['active' => true] : ['version' => $version]; + if ($version === null) { + $filters = ['active' => true]; + } else { + $filters = ['version' => $version]; + } try { $results = $objectService->getObjects( @@ -266,12 +275,12 @@ private function loadMatrix(?int $version): array throw new RuntimeException('LHS-matrix lookup mislukt'); } - $row = $this->firstRow($results); + $row = $this->firstRow(results: $results); if ($row === null) { throw new RuntimeException('Geen actieve LHS-matrix gevonden'); } - return $this->toArray($row); + return $this->toArray(value: $row); }//end loadMatrix() /** @@ -314,7 +323,7 @@ private function persistRecommendation(array $row, ?string $id=null): array throw new RuntimeException('Opslaan LHS-aanbeveling mislukt'); } - return $this->toArray($saved); + return $this->toArray(value: $saved); }//end persistRecommendation() /** @@ -331,7 +340,11 @@ private function indexCells(mixed $cells): array { if (is_string($cells) === true) { $decoded = json_decode($cells, true); - $cells = is_array($decoded) === true ? $decoded : []; + if (is_array($decoded) === true) { + $cells = $decoded; + } else { + $cells = []; + } } if (is_array($cells) === false) { diff --git a/lib/Service/WmsWfsService.php b/lib/Service/WmsWfsService.php index 0d653813..a91ce4a3 100644 --- a/lib/Service/WmsWfsService.php +++ b/lib/Service/WmsWfsService.php @@ -193,7 +193,7 @@ public function validateLayer(array $layer): array // We surface it here as a soft pre-flight via a no-op proxyRequest with empty query, // but to avoid a real outbound HTTP at validation time we skip and rely on the // proxy enforcing it. The save-time controller can call assertUrlAllowed(). - if ($url !== '' && $this->isUrlAllowed($url) === false) { + if ($url !== '' && $this->isUrlAllowed(url: $url) === false) { $errors[] = [ 'field' => 'url', 'code' => 'wms.url_not_allowed', @@ -257,7 +257,7 @@ public function proxyRequest(array $layer, array $params): array } $cutoffKm = (float) ($layer['extentCutoffKm'] ?? self::DEFAULT_EXTENT_CUTOFF_KM); - if ($bbox !== '' && $this->bboxExceedsCutoff($bbox, $cutoffKm) === true) { + if ($bbox !== '' && $this->bboxExceedsCutoff(bbox: $bbox, cutoffKm: $cutoffKm) === true) { throw new \RuntimeException('Visible extent exceeds layer cutoff; zoom in for details', 413); } } @@ -265,7 +265,11 @@ public function proxyRequest(array $layer, array $params): array // Build the upstream query. $version = (string) ($layer['version'] ?? ''); if ($version === '') { - $version = ($type === 'WFS') ? self::DEFAULT_WFS_VERSION : self::DEFAULT_WMS_VERSION; + if ($type === 'WFS') { + $version = self::DEFAULT_WFS_VERSION; + } else { + $version = self::DEFAULT_WMS_VERSION; + } } $query = array_change_key_case($params, CASE_UPPER); diff --git a/lib/Service/WorkflowDefinitionService.php b/lib/Service/WorkflowDefinitionService.php index fb2cbbd6..3c0069a3 100644 --- a/lib/Service/WorkflowDefinitionService.php +++ b/lib/Service/WorkflowDefinitionService.php @@ -113,13 +113,13 @@ public function getActiveDefinitionFor(string $caseTypeId): ?array return null; } - $versions = $this->listVersionsInternal($caseTypeId); + $versions = $this->listVersionsInternal(caseTypeId: $caseTypeId); if ($versions === []) { return null; } foreach ($versions as $candidate) { - if ($this->statusOf($candidate) !== self::STATUS_PUBLISHED) { + if ($this->statusOf(row: $candidate) !== self::STATUS_PUBLISHED) { continue; } @@ -140,7 +140,7 @@ public function getActiveDefinitionFor(string $caseTypeId): ?array */ public function getDefinition(string $id): ?array { - return $this->loadDefinition($id); + return $this->loadDefinition(id: $id); }//end getDefinition() /** @@ -176,14 +176,14 @@ public function getDefinitionForCase(string $caseId): ?array return null; } - $case = $this->normalize($case); + $case = $this->normalize(row: $case); if ($case === null) { return null; } $templateId = (string) ($case['workflowTemplate'] ?? ''); if ($templateId !== '') { - return $this->loadDefinition($templateId); + return $this->loadDefinition(id: $templateId); } $caseTypeId = (string) ($case['caseType'] ?? ''); @@ -191,7 +191,7 @@ public function getDefinitionForCase(string $caseId): ?array return null; } - return $this->getActiveDefinitionFor($caseTypeId); + return $this->getActiveDefinitionFor(caseTypeId: $caseTypeId); }//end getDefinitionForCase() /** @@ -204,7 +204,7 @@ public function getDefinitionForCase(string $caseId): ?array */ public function listVersions(string $caseTypeId): array { - return $this->listVersionsInternal($caseTypeId); + return $this->listVersionsInternal(caseTypeId: $caseTypeId); }//end listVersions() /** @@ -222,7 +222,7 @@ public function listVersions(string $caseTypeId): array */ public function publish(string $id): ?array { - $current = $this->loadDefinition($id); + $current = $this->loadDefinition(id: $id); if ($current === null) { $this->logger->warning( 'Procest: publish() — definition not found', @@ -231,7 +231,7 @@ public function publish(string $id): ?array return null; } - if ($this->statusOf($current) !== self::STATUS_DRAFT) { + if ($this->statusOf(row: $current) !== self::STATUS_DRAFT) { $this->logger->warning( 'Procest: publish() — definition is not a draft', ['app' => Application::APP_ID, 'id' => $id] @@ -240,7 +240,7 @@ public function publish(string $id): ?array } $caseTypeId = (string) ($current['caseType'] ?? ''); - if ($caseTypeId === '' || $this->transitionsReferenceForeignStatuses($current) === true) { + if ($caseTypeId === '' || $this->transitionsReferenceForeignStatuses(definition: $current) === true) { $this->logger->warning( 'Procest: publish() — referential integrity failure', ['app' => Application::APP_ID, 'id' => $id] @@ -262,7 +262,7 @@ public function publish(string $id): ?array } // Deprecate previously active versions of the same caseType. - $previousActive = $this->getActiveDefinitionFor($caseTypeId); + $previousActive = $this->getActiveDefinitionFor(caseTypeId: $caseTypeId); if ($previousActive !== null && (string) ($previousActive['id'] ?? '') !== $id) { try { $objectService->saveObject( @@ -321,7 +321,7 @@ public function publish(string $id): ?array ); } - return $this->normalize($updated); + return $this->normalize(row: $updated); }//end publish() /** @@ -335,12 +335,12 @@ public function publish(string $id): ?array */ public function deprecate(string $id): ?array { - $current = $this->loadDefinition($id); + $current = $this->loadDefinition(id: $id); if ($current === null) { return null; } - if ($this->statusOf($current) !== self::STATUS_PUBLISHED) { + if ($this->statusOf(row: $current) !== self::STATUS_PUBLISHED) { $this->logger->warning( 'Procest: deprecate() — definition is not published', ['app' => Application::APP_ID, 'id' => $id] @@ -349,8 +349,8 @@ public function deprecate(string $id): ?array } $caseTypeId = (string) ($current['caseType'] ?? ''); - if ($caseTypeId !== '' && $this->isLastPublishedForCaseType($id, $caseTypeId) === true - && $this->hasOpenCasesFor($caseTypeId) === true + if ($caseTypeId !== '' && $this->isLastPublishedForCaseType(id: $id, caseTypeId: $caseTypeId) === true + && $this->hasOpenCasesFor(caseTypeId: $caseTypeId) === true ) { $this->logger->warning( 'Procest: deprecate() — last published definition with open cases', @@ -389,7 +389,7 @@ public function deprecate(string $id): ?array return null; } - return $this->normalize($updated); + return $this->normalize(row: $updated); }//end deprecate() /** @@ -402,7 +402,7 @@ public function deprecate(string $id): ?array */ public function cloneDefinition(string $id): ?array { - $source = $this->loadDefinition($id); + $source = $this->loadDefinition(id: $id); if ($source === null) { return null; } @@ -420,10 +420,10 @@ public function cloneDefinition(string $id): ?array } $caseTypeId = (string) ($source['caseType'] ?? ''); - $nextVersion = $this->nextVersionFor($caseTypeId); + $nextVersion = $this->nextVersionFor(caseTypeId: $caseTypeId); $draft = [ - 'title' => $this->cloneTitle((string) ($source['title'] ?? 'Workflow')), + 'title' => $this->cloneTitle(base: (string) ($source['title'] ?? 'Workflow')), 'description' => (string) ($source['description'] ?? ''), 'caseType' => $caseTypeId, 'version' => $nextVersion, @@ -445,7 +445,7 @@ public function cloneDefinition(string $id): ?array return null; } - return $this->normalize($new); + return $this->normalize(row: $new); }//end cloneDefinition() /** @@ -493,12 +493,24 @@ public function createDraft(array $payload): ?array $version = (int) ($payload['version'] ?? 0); if ($version <= 0) { - $version = $this->nextVersionFor($caseTypeId); + $version = $this->nextVersionFor(caseTypeId: $caseTypeId); } $steps = $payload['steps'] ?? []; $transitions = $payload['transitions'] ?? []; + if (is_string($steps) === true) { + $stepsValue = $steps; + } else { + $stepsValue = json_encode($steps); + } + + if (is_string($transitions) === true) { + $transitionsValue = $transitions; + } else { + $transitionsValue = json_encode($transitions); + } + $draft = [ 'title' => (string) $payload['title'], 'description' => (string) ($payload['description'] ?? ''), @@ -507,8 +519,8 @@ public function createDraft(array $payload): ?array 'isActive' => false, 'isDraft' => true, 'lifecycleStatus' => self::STATUS_DRAFT, - 'steps' => is_string($steps) === true ? $steps : json_encode($steps), - 'transitions' => is_string($transitions) === true ? $transitions : json_encode($transitions), + 'steps' => $stepsValue, + 'transitions' => $transitionsValue, 'nodePositions' => (string) ($payload['nodePositions'] ?? ''), ]; @@ -522,7 +534,7 @@ public function createDraft(array $payload): ?array return null; } - return $this->normalize($new); + return $this->normalize(row: $new); }//end createDraft() // ----------------------------------------------------------------- @@ -573,7 +585,7 @@ private function listVersionsInternal(string $caseTypeId): array $rows = []; foreach ($results as $row) { - $normalized = $this->normalize($row); + $normalized = $this->normalize(row: $row); if ($normalized !== null) { $rows[] = $normalized; } @@ -624,7 +636,7 @@ private function loadDefinition(string $id): ?array return null; } - return $this->normalize($obj); + return $this->normalize(row: $obj); }//end loadDefinition() /** @@ -637,7 +649,7 @@ private function loadDefinition(string $id): ?array */ private function nextVersionFor(string $caseTypeId): int { - $versions = $this->listVersionsInternal($caseTypeId); + $versions = $this->listVersionsInternal(caseTypeId: $caseTypeId); $max = 0; foreach ($versions as $row) { $candidate = (int) ($row['version'] ?? 0); @@ -660,12 +672,12 @@ private function nextVersionFor(string $caseTypeId): int private function isLastPublishedForCaseType(string $id, string $caseTypeId): bool { $count = 0; - foreach ($this->listVersionsInternal($caseTypeId) as $row) { + foreach ($this->listVersionsInternal(caseTypeId: $caseTypeId) as $row) { if ((string) ($row['id'] ?? '') === $id) { continue; } - if ($this->statusOf($row) === self::STATUS_PUBLISHED) { + if ($this->statusOf(row: $row) === self::STATUS_PUBLISHED) { $count++; } } @@ -726,13 +738,13 @@ private function hasOpenCasesFor(string $caseTypeId): bool private function transitionsReferenceForeignStatuses(array $definition): bool { $caseTypeId = (string) ($definition['caseType'] ?? ''); - $transitions = $this->decodeArray($definition['transitions'] ?? ''); + $transitions = $this->decodeArray(raw: ($definition['transitions'] ?? '')); if ($caseTypeId === '' || $transitions === []) { return false; } - $statusIds = $this->collectStatusTypeIdsFor($caseTypeId); + $statusIds = $this->collectStatusTypeIdsFor(caseTypeId: $caseTypeId); if ($statusIds === []) { // No statusTypes yet — cannot validate. Treat as ok. return false; @@ -797,7 +809,7 @@ private function collectStatusTypeIdsFor(string $caseTypeId): array $ids = []; foreach ($rows as $row) { - $normalized = $this->normalize($row); + $normalized = $this->normalize(row: $row); if ($normalized === null) { continue; } diff --git a/lib/Service/WorkflowTemplateLoader.php b/lib/Service/WorkflowTemplateLoader.php index d247ec6b..48d3bbd0 100644 --- a/lib/Service/WorkflowTemplateLoader.php +++ b/lib/Service/WorkflowTemplateLoader.php @@ -71,7 +71,11 @@ public function getActiveTemplate(string $caseTypeId): ?array } if (isset($this->cache[$caseTypeId]) === true) { - return $this->cache[$caseTypeId] === false ? null : $this->cache[$caseTypeId]; + if ($this->cache[$caseTypeId] === false) { + return null; + } + + return $this->cache[$caseTypeId]; } $objectService = $this->settingsService->getObjectService(); From c6a402925c5ac9b493082315ee2dbd06c5159fc2 Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Tue, 12 May 2026 11:30:45 +0200 Subject: [PATCH 03/13] chore(quality): fix eslint + stylelint + build to clear procest CI gates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Continues the procest quality cleanup (after the phpcs commits): **stylelint** — added the missing peer deps of `@nextcloud/stylelint-config` (which the config `extends`): `stylelint-config-recommended-scss@^13.1.0`, `stylelint-config-recommended-vue@^1.6.1`, `postcss-html@^1.8.1` (matches decidesk's set). `npm run stylelint` now runs and reports **0 errors** — the "Vue Quality (stylelint)" gate was failing purely on the missing-config-module error, not on actual style violations. **eslint** — `npm run lint -- --fix` auto-fixed 5; the remaining 9 errors fixed by hand: - `bezwaar.js` — removed unused `settingsStore` var + its now-unused import - `MyWork.vue` — `