$employeeIds * @param callable(?WorkHour, int): bool $shouldSkip * @param callable(WorkHour, int): void $applyUpdate */ public function execute( User $user, string $workDateValue, array $employeeIds, callable $shouldSkip, callable $applyUpdate ): WorkHourBulkValidationResult { $workDate = DateTimeImmutable::createFromFormat('Y-m-d', $workDateValue); if (!$workDate || $workDate->format('Y-m-d') !== $workDateValue) { throw new UnprocessableEntityHttpException('workDate must use Y-m-d format.'); } $normalizedEmployeeIds = $this->normalizeEmployeeIds($employeeIds); if ([] === $normalizedEmployeeIds) { throw new UnprocessableEntityHttpException('employeeIds must contain at least one employee.'); } $employeesById = $this->employeeRepository->findAccessibleByIds($normalizedEmployeeIds, $user); if (count($employeesById) !== count($normalizedEmployeeIds)) { throw new AccessDeniedHttpException('At least one employee is unknown or outside your scope.'); } $existingByEmployeeId = $this->workHourRepository ->findByDateAndEmployeesIndexedByEmployeeId($workDate, array_values($employeesById)) ; $result = new WorkHourBulkValidationResult(); $result->requested = count($normalizedEmployeeIds); foreach ($normalizedEmployeeIds as $employeeId) { $workHour = $existingByEmployeeId[$employeeId] ?? null; if (null === $workHour || $shouldSkip($workHour, $employeeId)) { ++$result->skipped; $result->skippedEmployeeIds[] = $employeeId; continue; } $applyUpdate($workHour, $employeeId); ++$result->updated; $result->updatedEmployeeIds[] = $employeeId; } if ($result->updated > 0) { $this->entityManager->flush(); } return $result; } /** * @param list $employeeIds * * @return list */ private function normalizeEmployeeIds(array $employeeIds): array { $normalized = []; foreach ($employeeIds as $index => $rawId) { $employeeId = (int) $rawId; if ($employeeId <= 0) { throw new UnprocessableEntityHttpException(sprintf('employeeIds[%d] must be a positive integer.', $index)); } if (isset($normalized[$employeeId])) { throw new UnprocessableEntityHttpException(sprintf('Employee %d appears multiple times in payload.', $employeeId)); } $normalized[$employeeId] = $employeeId; } return array_values($normalized); } }