*/ public function resolvePhases(Employee $employee): array { $periods = $employee->getContractPeriods()->toArray(); usort( $periods, static fn (EmployeeContractPeriod $a, EmployeeContractPeriod $b): int => $a->getStartDate() <=> $b->getStartDate() ); $today = new DateTimeImmutable('today'); $phases = []; $group = []; $signature = null; foreach ($periods as $period) { $currentSignature = $this->signature($period); if (null !== $signature && $currentSignature !== $signature) { $phases[] = $this->buildPhase($group, $today); $group = []; } $group[] = $period; $signature = $currentSignature; } if ([] !== $group) { $phases[] = $this->buildPhase($group, $today); } // Most recent first. return array_reverse($phases); } private function signature(EmployeeContractPeriod $period): string { $contract = $period->getContract(); $type = $contract?->getType()->value ?? ''; $hours = $contract?->getWeeklyHours() ?? -1; $driver = $period->getIsDriver() ? '1' : '0'; return sprintf('%s|%d|%s', $type, $hours, $driver); } /** * @param non-empty-list $group */ private function buildPhase(array $group, DateTimeImmutable $today): ContractPhase { $first = $group[0]; $last = end($group); $endDate = $last->getEndDate(); $isCurrent = null === $endDate || $endDate >= $today; $contract = $first->getContract(); return new ContractPhase( id: (int) $first->getId(), contractType: $contract?->getType() ?? throw new LogicException('Phase requires a contract type'), weeklyHours: $contract?->getWeeklyHours(), isDriver: $first->getIsDriver(), startDate: $first->getStartDate(), endDate: $endDate, periodIds: array_map(static fn (EmployeeContractPeriod $p): int => (int) $p->getId(), $group), isCurrent: $isCurrent, contractNature: $first->getContractNatureEnum(), ); } }