feat: complete jobcard operations and access controls

This commit is contained in:
Marco0300
2026-09-01 20:07:20 +02:00
parent 703c3ca67d
commit 168c15c6ae
12 changed files with 1241 additions and 29 deletions
@@ -0,0 +1,58 @@
<?php
declare(strict_types=1);
namespace App\Domain\Jobcard;
/**
* Validates and normalizes the command used to replace a jobcard's technician assignments.
*/
final class AssignmentValidator
{
/**
* @return array{valid: bool, jobcard_id: ?int, user_ids: list<int>, errors: array<string, string>}
*/
public function validate(array $payload): array
{
$errors = [];
$jobcardId = $this->positiveInteger($payload['jobcard_id'] ?? null);
if ($jobcardId === null) {
$errors['jobcard_id'] = 'Jobcard ID must be a positive integer.';
}
$userIds = [];
$assignments = $payload['user_ids'] ?? null;
if (!is_array($assignments) || $assignments === []) {
$errors['user_ids'] = 'At least one technician ID is required.';
} else {
foreach ($assignments as $userId) {
$normalized = $this->positiveInteger($userId);
if ($normalized === null) {
$errors['user_ids'] = 'Technician IDs must be positive integers.';
continue;
}
if (!in_array($normalized, $userIds, true)) {
$userIds[] = $normalized;
}
}
}
return [
'valid' => $errors === [],
'jobcard_id' => $jobcardId,
'user_ids' => $userIds,
'errors' => $errors,
];
}
private function positiveInteger(mixed $value): ?int
{
if (is_int($value)) {
return $value > 0 ? $value : null;
}
if (is_string($value) && preg_match('/^[1-9]\d*$/', $value) === 1) {
$integer = filter_var($value, FILTER_VALIDATE_INT);
return $integer !== false ? $integer : null;
}
return null;
}
}