feat: implementation des dossiers candidats PDF, gestion des entretiens et optimisation de l'analyse IA
This commit is contained in:
131
app/Http/Controllers/Admin/CandidateExportController.php
Normal file
131
app/Http/Controllers/Admin/CandidateExportController.php
Normal file
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Candidate;
|
||||
use Barryvdh\DomPDF\Facade\Pdf;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class CandidateExportController extends Controller
|
||||
{
|
||||
public function exportDossier(Candidate $candidate)
|
||||
{
|
||||
$candidate->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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user