fix : validation bulk des heures. Moins de lag et de bug
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
This commit is contained in:
103
src/Service/WorkHours/WorkHourBulkValidationExecutor.php
Normal file
103
src/Service/WorkHours/WorkHourBulkValidationExecutor.php
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service\WorkHours;
|
||||
|
||||
use App\ApiResource\WorkHourBulkValidationResult;
|
||||
use App\Entity\User;
|
||||
use App\Entity\WorkHour;
|
||||
use App\Repository\EmployeeRepository;
|
||||
use App\Repository\WorkHourRepository;
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
|
||||
|
||||
final readonly class WorkHourBulkValidationExecutor
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManagerInterface $entityManager,
|
||||
private EmployeeRepository $employeeRepository,
|
||||
private WorkHourRepository $workHourRepository,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @param list<mixed> $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<mixed> $employeeIds
|
||||
*
|
||||
* @return list<int>
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user