08-traitement-fichiers

<?php
class FileProcessor {
    public function process(string $filePath): array {
        $extension = pathinfo($filePath, PATHINFO_EXTENSION);
        $results = [];
        
        if($extension === 'csv') {
            $handle = fopen($filePath, 'r');
            $headers = fgetcsv($handle);
            $data = [];
            while(($row = fgetcsv($handle)) !== false) {
                $data[] = array_combine($headers, $row);
            }
            fclose($handle);
            
            $validated = $this->validateData($data);
            $transformed = $this->transformData($validated);
            
            $db = new PDO('mysql:host=localhost;dbname=imports','root','');
            foreach($transformed as $row) {
                $stmt = $db->prepare('INSERT INTO records (name,email,amount) VALUES (?,?,?)');
                $stmt->execute([$row['name'], $row['email'], $row['amount']]);
            }
            
            $results['imported'] = count($transformed);
            $results['errors'] = [];
            
            $this->sendNotification('CSV import complete', count($transformed) . ' records imported');
            
        } elseif($extension === 'json') {
            $content = file_get_contents($filePath);
            $data = json_decode($content, true);
            
            if(!$data) {
                throw new Exception("Invalid JSON");
            }
            
            $validated = $this->validateData($data);
            $transformed = $this->transformData($validated);
            
            $db = new PDO('mysql:host=localhost;dbname=imports','root','');
            foreach($transformed as $row) {
                $stmt = $db->prepare('INSERT INTO records (name,email,amount) VALUES (?,?,?)');
                $stmt->execute([$row['name'], $row['email'], $row['amount']]);
            }
            
            $results['imported'] = count($transformed);
            $results['errors'] = [];
            
            $this->sendNotification('JSON import complete', count($transformed) . ' records imported');
            
        } elseif($extension === 'xml') {
            $xml = simplexml_load_file($filePath);
            $data = [];
            foreach($xml->record as $record) {
                $data[] = [
                    'name' => (string)$record->name,
                    'email' => (string)$record->email,
                    'amount' => (float)$record->amount
                ];
            }
            
            $validated = $this->validateData($data);
            $transformed = $this->transformData($validated);
            
            $db = new PDO('mysql:host=localhost;dbname=imports','root','');
            foreach($transformed as $row) {
                $stmt = $db->prepare('INSERT INTO records (name,email,amount) VALUES (?,?,?)');
                $stmt->execute([$row['name'], $row['email'], $row['amount']]);
            }
            
            $results['imported'] = count($transformed);
            $results['errors'] = [];
            
            $this->sendNotification('XML import complete', count($transformed) . ' records imported');
        } else {
            throw new Exception("Format not supported: $extension");
        }
        
        $this->archiveFile($filePath);
        $this->logProcessing($filePath, $results);
        
        return $results;
    }
    
    private function validateData(array $data): array {
        $valid = [];
        foreach($data as $row) {
            if(isset($row['email']) && filter_var($row['email'], FILTER_VALIDATE_EMAIL)) {
                if(isset($row['amount']) && is_numeric($row['amount']) && $row['amount'] > 0) {
                    $valid[] = $row;
                }
            }
        }
        return $valid;
    }
    
    private function transformData(array $data): array {
        return array_map(function($row) {
            return [
                'name' => ucwords(strtolower($row['name'] ?? 'Unknown')),
                'email' => strtolower($row['email']),
                'amount' => round($row['amount'], 2)
            ];
        }, $data);
    }
    
    private function archiveFile(string $path): void {
        $archivePath = '/var/archives/' . basename($path);
        rename($path, $archivePath);
    }
    
    private function logProcessing(string $file, array $results): void {
        $db = new PDO('mysql:host=localhost;dbname=imports','root','');
        $stmt = $db->prepare('INSERT INTO processing_log (filename,imported_count,timestamp) VALUES (?,?,?)');
        $stmt->execute([basename($file), $results['imported'], time()]);
    }
    
    private function sendNotification(string $subject, string $message): void {
        mail('admin@example.com', $subject, $message);
    }
}

/*
=== USER STORIES ===

US1: En tant que data analyst, je veux pouvoir importer des fichiers Excel (.xlsx) 
     en plus des formats existants.

US2: En tant que développeur, je veux tester la logique de validation et transformation 
     sans dépendre du système de fichiers ni de la base de données.

US3: En tant que product owner, je veux stocker les données importées dans MongoDB 
     au lieu de MySQL, selon la configuration.

US4: En tant que data manager, je veux pouvoir définir des règles de transformation 
     différentes selon le type de données (clients, produits, commandes) sans 
     modifier la classe FileProcessor.

US5: En tant que sysadmin, je veux recevoir les notifications via Slack au lieu 
     d'email, et logger dans Elasticsearch au lieu de MySQL.

US6: En tant que compliance officer, je veux pouvoir appliquer des validations 
     supplémentaires spécifiques à certains formats (RGPD, formats comptables) 
     sans toucher au code existant.

US7: En tant que product manager, je veux supporter le streaming de gros fichiers 
     (plusieurs Go) sans charger tout le fichier en mémoire.
*/