* - VANITY_URL (optional) * * INTEGRATION IN config.yaml: * --------------------------- * * fireflyImport: * # Pfad zur JSON-Konfiguration (aus Firefly III exportiert) * jsonConfig: '/opt/firefly/configs/ubs-import.json' * * # Firefly Data Importer Kommando * # Option 1: Docker * importerCommand: 'docker exec -it firefly-importer php artisan importer:import' * * # Option 2: Standalone * # importerCommand: 'cd /opt/firefly-data-importer && php artisan importer:import' * * # Automatisch nach Transformation importieren? * autoImport: true * * # Output-Datei nach erfolgreichem Import löschen? * deleteAfterImport: true * * # Timeout für Import (Sekunden) * timeout: 300 * * # Environment-Variablen für Firefly Data Importer * environment: * FIREFLY_III_URL: 'https://your-firefly.com' * FIREFLY_III_ACCESS_TOKEN: 'your-token-here' * * VERWENDUNG: * ----------- * * // Automatisch beim Auto-Import * ./bin/transformer auto-import config/config.yaml * * // Oder manuell nach Transformation * $importer = new FireflyImporter($config['fireflyImport']); * $result = $importer->import('/path/to/transformed.csv'); */ class FireflyImporter { private array $config; private string $jsonConfigPath; private string $importerCommand; private bool $deleteAfterImport; private array $environment; /** * @param array $config Firefly Import-Konfiguration aus config.yaml * @throws \RuntimeException wenn Konfiguration ungültig */ public function __construct(array $config) { $this->config = $config; // JSON-Konfigurationspfad validieren $this->jsonConfigPath = $config['jsonConfig'] ?? ''; if (empty($this->jsonConfigPath)) { throw new \RuntimeException("Firefly Import: 'jsonConfig' nicht konfiguriert"); } if (!file_exists($this->jsonConfigPath)) { throw new \RuntimeException("Firefly JSON-Konfiguration nicht gefunden: {$this->jsonConfigPath}"); } // Importer-Kommando $this->importerCommand = $config['importerCommand'] ?? ''; if (empty($this->importerCommand)) { throw new \RuntimeException("Firefly Import: 'importerCommand' nicht konfiguriert"); } // Optionale Einstellungen $this->deleteAfterImport = $config['deleteAfterImport'] ?? false; $this->environment = $config['environment'] ?? []; } /** * Importiert eine transformierte CSV-Datei in Firefly III * * Der Import erfolgt über den Firefly III Data Importer CLI: * php artisan importer:import * * @param string $csvFile Pfad zur transformierten CSV-Datei * @return array Import-Ergebnis mit Status und Ausgabe */ public function import(string $csvFile): array { if (!file_exists($csvFile)) { return [ 'success' => false, 'error' => "CSV-Datei nicht gefunden: {$csvFile}", 'output' => '', 'exit_code' => -1 ]; } // Kommando zusammenbauen $command = $this->buildImportCommand($csvFile); // Environment-Variablen setzen $env = $this->buildEnvironment(); // Import ausführen $output = []; $exitCode = 0; $startTime = microtime(true); try { // Kommando ausführen mit Timeout $descriptors = [ 0 => ["pipe", "r"], // stdin 1 => ["pipe", "w"], // stdout 2 => ["pipe", "w"] // stderr ]; $process = proc_open($command, $descriptors, $pipes, null, $env); if (!is_resource($process)) { throw new \RuntimeException("Konnte Import-Prozess nicht starten"); } // stdin schließen fclose($pipes[0]); // stdout und stderr lesen $stdout = stream_get_contents($pipes[1]); $stderr = stream_get_contents($pipes[2]); fclose($pipes[1]); fclose($pipes[2]); // Auf Prozess-Ende warten $exitCode = proc_close($process); $output = [ 'stdout' => $stdout, 'stderr' => $stderr ]; $duration = microtime(true) - $startTime; $success = ($exitCode === 0); // Bei Erfolg: Optional CSV-Datei löschen if ($success && $this->deleteAfterImport) { @unlink($csvFile); } return [ 'success' => $success, 'exit_code' => $exitCode, 'output' => $output, 'duration' => round($duration, 2), 'csv_file' => $csvFile, 'config_file' => $this->jsonConfigPath, 'deleted' => ($success && $this->deleteAfterImport) ]; } catch (\Exception $e) { return [ 'success' => false, 'error' => $e->getMessage(), 'output' => $output, 'exit_code' => $exitCode ]; } } /** * Baut das Import-Kommando zusammen * * @param string $csvFile Pfad zur CSV-Datei * @return string Vollständiges Kommando */ private function buildImportCommand(string $csvFile): string { // Firefly Data Importer CLI-Format: // php artisan importer:import return sprintf( '%s %s %s', $this->importerCommand, escapeshellarg($csvFile), escapeshellarg($this->jsonConfigPath) ); } /** * Baut Environment-Variablen zusammen * * @return array|null Environment-Variablen oder null */ private function buildEnvironment(): ?array { if (empty($this->environment)) { return null; } // Aktuelle Environment übernehmen und mit Custom-Vars erweitern $env = $_ENV; foreach ($this->environment as $key => $value) { $env[$key] = $value; } return $env; } /** * Testet die Firefly-Verbindung * * @return array Test-Ergebnis */ public function testConnection(): array { // Test ob Importer-Kommando verfügbar ist $testCommand = str_replace('importer:import', '--version', $this->importerCommand); exec($testCommand . ' 2>&1', $output, $exitCode); return [ 'available' => ($exitCode === 0), 'output' => implode("\n", $output), 'exit_code' => $exitCode ]; } /** * Validiert die JSON-Konfiguration * * @return array Validierungsergebnis */ public function validateConfig(): array { if (!file_exists($this->jsonConfigPath)) { return [ 'valid' => false, 'error' => 'JSON-Konfiguration nicht gefunden' ]; } $json = file_get_contents($this->jsonConfigPath); if ($json === false) { return [ 'valid' => false, 'error' => 'Konfigurationsdatei nicht lesbar' ]; } $config = json_decode($json, true); if ($config === null) { return [ 'valid' => false, 'error' => 'Ungültiges JSON: ' . json_last_error_msg() ]; } // Prüfe erforderliche Felder in Firefly-Config $requiredFields = ['file_type', 'import_account']; $missingFields = []; foreach ($requiredFields as $field) { if (!isset($config[$field])) { $missingFields[] = $field; } } if (!empty($missingFields)) { return [ 'valid' => false, 'error' => 'Fehlende Felder: ' . implode(', ', $missingFields) ]; } return [ 'valid' => true, 'config' => $config ]; } /** * Gibt die Konfiguration zurück * * @return array Firefly Import-Konfiguration */ public function getConfig(): array { return $this->config; } }