05-generation-rapports
<?php
class ReportGenerator {
private array $data;
public function __construct(array $rawData) {
$this->data = $rawData;
}
public function generateSalesReport(string $format, string $period): string {
$filtered = $this->filterByPeriod($period);
$total = 0;
$count = 0;
$productStats = [];
foreach($filtered as $sale) {
$total += $sale['amount'];
$count++;
if(!isset($productStats[$sale['product']])) {
$productStats[$sale['product']] = ['count' => 0, 'revenue' => 0];
}
$productStats[$sale['product']]['count']++;
$productStats[$sale['product']]['revenue'] += $sale['amount'];
}
$average = $count > 0 ? $total / $count : 0;
arsort($productStats);
$topProducts = array_slice($productStats, 0, 5, true);
if($format === 'pdf') {
return $this->formatAsPDF($total, $average, $count, $topProducts);
} elseif($format === 'excel') {
return $this->formatAsExcel($total, $average, $count, $topProducts);
} elseif($format === 'html') {
return $this->formatAsHTML($total, $average, $count, $topProducts);
} elseif($format === 'json') {
return json_encode(['total' => $total, 'average' => $average,
'count' => $count, 'top_products' => $topProducts]);
}
throw new Exception("Format non supporté");
}
private function filterByPeriod(string $period): array {
$now = new DateTime();
return array_filter($this->data, function($sale) use ($period, $now) {
$saleDate = new DateTime($sale['date']);
$diff = $now->diff($saleDate)->days;
return match($period) {
'week' => $diff <= 7,
'month' => $diff <= 30,
'quarter' => $diff <= 90,
'year' => $diff <= 365,
default => true
};
});
}
private function formatAsPDF($total, $avg, $count, $top): string {
$pdf = new PDFLib();
$pdf->addText("Total: $total EUR");
$pdf->addText("Moyenne: $avg EUR");
$pdf->addText("Nombre de ventes: $count");
return $pdf->output();
}
private function formatAsExcel($total, $avg, $count, $top): string {
$excel = new ExcelLib();
$excel->setCellValue('A1', 'Total');
$excel->setCellValue('B1', $total);
return $excel->save();
}
private function formatAsHTML($total, $avg, $count, $top): string {
$html = "<html><body>";
$html .= "<h1>Rapport de ventes</h1>";
$html .= "<p>Total: $total EUR</p>";
$html .= "<p>Moyenne: $avg EUR</p>";
$html .= "</body></html>";
return $html;
}
}
class PDFLib {
public function addText(string $text): void { /* ... */ }
public function output(): string { return "PDF content"; }
}
class ExcelLib {
public function setCellValue(string $cell, $value): void { /* ... */ }
public function save(): string { return "Excel content"; }
}
/*
=== USER STORIES ===
US1: En tant que manager, je veux générer des rapports au format CSV en plus
des formats existants.
US2: En tant que développeur, je veux tester la logique de calcul (total, moyenne,
top produits) indépendamment de la génération de fichiers.
US3: En tant que product owner, je veux ajouter un nouveau type de rapport
"Rapport de stock" avec des calculs différents mais les mêmes formats de sortie.
US4: En tant que manager, je veux pouvoir appliquer des filtres supplémentaires
(par catégorie de produit, par région) sans modifier la classe existante.
US5: En tant que développeur, je veux remplacer les bibliothèques PDF et Excel
par d'autres implémentations sans toucher à la logique métier.
*/