requestStack->getCurrentRequest(); if (!$request) { return new Response('Missing request.', Response::HTTP_BAD_REQUEST); } $employeeId = (int) $request->query->get('employeeId', '0'); if ($employeeId <= 0) { throw new UnprocessableEntityHttpException('employeeId must be a positive integer.'); } $employee = $this->employeeRepository->find($employeeId); if (!$employee instanceof Employee) { throw new NotFoundHttpException('Employee not found.'); } $yearRaw = (string) $request->query->get('year'); if (!preg_match('/^\d{4}$/', $yearRaw)) { throw new UnprocessableEntityHttpException('year must use YYYY format.'); } $year = (int) $yearRaw; $monthRaw = (string) $request->query->get('month', ''); $month = null; if ('' !== $monthRaw) { if (!preg_match('/^(?:0?[1-9]|1[0-2])$/', $monthRaw)) { throw new UnprocessableEntityHttpException('month must be between 1 and 12.'); } $month = (int) $monthRaw; } if (null !== $month) { $from = new DateTimeImmutable(sprintf('%d-%02d-01', $year, $month)); $to = $from->modify('last day of this month'); } else { $from = new DateTimeImmutable("{$year}-01-01"); $to = new DateTimeImmutable("{$year}-12-31"); } $entries = $this->exportBuilder->buildForEmployee($employee, $from, $to); $employeeName = trim(($employee->getLastName() ?? '').' '.($employee->getFirstName() ?? '')); $contractLabel = $this->exportBuilder->buildContractLabel($employee); $options = new Options(); $options->set('isRemoteEnabled', true); $dompdf = new Dompdf($options); $html = $this->twig->render('employee-yearly-hours/print.html.twig', [ 'employeeName' => $employeeName, 'contractLabel' => $contractLabel, 'year' => $year, 'month' => $month, 'segments' => $entries[0]['segments'] ?? [], ]); $dompdf->loadHtml($html); $dompdf->setPaper('A4', 'portrait'); $dompdf->render(); $filename = null !== $month ? sprintf( '%s_%s_%d-%02d.pdf', $this->sanitizeFilename($employee->getLastName() ?? ''), $this->sanitizeFilename($employee->getFirstName() ?? ''), $year, $month, ) : sprintf( '%s_%s_%d.pdf', $this->sanitizeFilename($employee->getLastName() ?? ''), $this->sanitizeFilename($employee->getFirstName() ?? ''), $year, ); return new Response($dompdf->output(), Response::HTTP_OK, [ 'Content-Type' => 'application/pdf', 'Content-Disposition' => 'inline; filename="'.$filename.'"', ]); } private function sanitizeFilename(string $name): string { $name = str_replace(' ', '_', $name); return preg_replace('/[^a-zA-Z0-9_\-]/', '', $name) ?? $name; } }