firefly-import-preprocessor/src/FireflyImporter.php
Reindl David (IT-PTR-CEN2-SL10) 170b2d2016 release 1.0
2026-05-02 17:53:19 +02:00

318 lines
9.0 KiB
PHP

<?php
namespace UbsCsvTransformer;
/**
* Firefly III Data Importer Integration
*
* Diese Klasse integriert den Firefly III Data Importer.
* Der Import erfolgt über die offizielle Firefly III Data Importer CLI.
*
* SETUP-VORAUSSETZUNGEN:
* ----------------------
*
* 1. Firefly III Data Importer installiert und konfiguriert
* - Docker: firefly/data-importer:latest
* - Oder: Standalone Installation
*
* 2. Import-Konfiguration erstellt (config.json):
* - In Firefly III Web-UI: Import → Configure
* - CSV-Format konfigurieren
* - JSON-Konfiguration herunterladen
* - Speichern als z.B.: /opt/firefly/configs/ubs-import.json
*
* 3. Umgebungsvariablen für Firefly Data Importer:
* - FIREFLY_III_URL=https://your-firefly-instance.com
* - FIREFLY_III_ACCESS_TOKEN=<personal_access_token>
* - 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 <csv_file> <config_file>
*
* @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 <csv_file> <config_file>
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;
}
}