load([ 'user', 'jobPosition', 'tenant', 'attempts.quiz.questions', 'attempts.answers.option', 'attempts.answers.question', 'documents' ]); $filename = 'Dossier_' . str_replace(' ', '_', $candidate->user->name) . '_' . date('Ymd') . '.pdf'; // 1. Generate Main Report with DomPDF $pdfReport = Pdf::loadView('pdfs.candidate-dossier', [ 'candidate' => $candidate ]); $reportBinary = $pdfReport->output(); // 2. Setup FPDI for merging $mergedPdf = new \setasign\Fpdi\Fpdi(); // Add Main Report Pages $reportTmp = tempnam(sys_get_temp_dir(), 'pdf_report_'); file_put_contents($reportTmp, $reportBinary); try { $pageCount = $mergedPdf->setSourceFile($reportTmp); for ($pageNo = 1; $pageNo <= $pageCount; $pageNo++) { $templateId = $mergedPdf->importPage($pageNo); $size = $mergedPdf->getTemplateSize($templateId); $mergedPdf->AddPage($size['orientation'], [$size['width'], $size['height']]); $mergedPdf->useTemplate($templateId); } } catch (\Exception $e) { \Log::error('FPDI Error on report: ' . $e->getMessage()); } @unlink($reportTmp); // 3. Append Candidate Documents (CV, Letter) foreach ($candidate->documents as $doc) { if (\Storage::disk('local')->exists($doc->file_path)) { $filePath = \Storage::disk('local')->path($doc->file_path); try { $pageCount = $mergedPdf->setSourceFile($filePath); for ($pageNo = 1; $pageNo <= $pageCount; $pageNo++) { $templateId = $mergedPdf->importPage($pageNo); $size = $mergedPdf->getTemplateSize($templateId); $mergedPdf->AddPage($size['orientation'], [$size['width'], $size['height']]); $mergedPdf->useTemplate($templateId); } } catch (\Exception $e) { \Log::warning('Could not merge document ID ' . $doc->id . ': ' . $e->getMessage()); // Add a professional placeholder page for unmergable documents $mergedPdf->AddPage('P', 'A4'); $mergedPdf->SetFont('Arial', 'B', 16); $mergedPdf->SetTextColor(0, 79, 130); // Primary color $mergedPdf->Ln(50); $mergedPdf->Cell(0, 20, utf8_decode("DOCUMENT JOINT : " . strtoupper($doc->type)), 0, 1, 'C'); $mergedPdf->SetFont('Arial', 'I', 12); $mergedPdf->Cell(0, 10, utf8_decode($doc->original_name), 0, 1, 'C'); $mergedPdf->Ln(30); $mergedPdf->SetFont('Arial', '', 11); $mergedPdf->SetTextColor(100, 100, 100); $mergedPdf->MultiCell(0, 8, utf8_decode("Ce document n'a pas pu être fusionné automatiquement au dossier car son format est trop récent (PDF 1.5+).\n\nPour garantir l'intégrité de la mise en page, veuillez consulter ce document séparément via l'interface du tableau de bord candidat."), 0, 'C'); $mergedPdf->Ln(20); $mergedPdf->SetDrawColor(224, 176, 76); // Highlight color $mergedPdf->Line(60, $mergedPdf->GetY(), 150, $mergedPdf->GetY()); } } } return response($mergedPdf->Output('S'), 200, [ 'Content-Type' => 'application/pdf', 'Content-Disposition' => 'attachment; filename="' . $filename . '"', 'Cache-Control' => 'no-cache, no-store, must-revalidate', 'Pragma' => 'no-cache', 'Expires' => '0', ]); } public function exportZip(Candidate $candidate) { $candidate->load(['user', 'jobPosition', 'tenant', 'attempts.quiz.questions', 'attempts.answers.option', 'attempts.answers.question', 'documents']); $baseName = 'Dossier_' . str_replace(' ', '_', $candidate->user->name) . '_' . date('Ymd'); $zipPath = tempnam(sys_get_temp_dir(), 'candidate_zip_'); $zip = new \ZipArchive(); if ($zip->open($zipPath, \ZipArchive::CREATE | \ZipArchive::OVERWRITE) !== true) { return back()->with('error', 'Impossible de créer le fichier ZIP.'); } // 1. Add the main report (Rapport CABM) $pdfReport = Pdf::loadView('pdfs.candidate-dossier', [ 'candidate' => $candidate ]); $zip->addFromString($baseName . '/Rapport_Synthese_CABM.pdf', $pdfReport->output()); // 2. Add original documents foreach ($candidate->documents as $doc) { if (\Storage::disk('local')->exists($doc->file_path)) { $content = \Storage::disk('local')->get($doc->file_path); // Sanitize original name or use type $ext = pathinfo($doc->original_name, PATHINFO_EXTENSION); $fileName = strtoupper($doc->type) . '_' . $doc->original_name; $zip->addFromString($baseName . '/Documents_Originaux/' . $fileName, $content); } } $zip->close(); return response()->download($zipPath, $baseName . '.zip')->deleteFileAfterSend(true); } }