"`$c`", $cols)) . ') VALUES (' . implode(',', array_fill(0, count($cols), '?')) . ')'; Database::execute($sql, array_values($row)); return (int)Database::lastInsertId(); } public static function update(int $id, array $data): void { $row = self::dehydrate($data); if (empty($row)) { return; } $sets = implode(', ', array_map(fn($c) => "`$c` = ?", array_keys($row))); $params = array_values($row); $params[] = $id; Database::execute("UPDATE bank_sources SET $sets WHERE id = ?", $params); } public static function updateField(int $id, string $field, mixed $value): void { if (in_array($field, ['client_id', 'secret', 'pin'], true)) { $field = $field . '_enc'; $value = $value !== null && $value !== '' ? Crypto::encrypt((string)$value) : null; } Database::execute("UPDATE bank_sources SET `$field` = ? WHERE id = ?", [$value, $id]); } public static function delete(int $id): void { Database::execute('DELETE FROM bank_sources WHERE id = ?', [$id]); } public static function updateLastFetched(int $id): void { Database::execute('UPDATE bank_sources SET last_fetched_at = NOW() WHERE id = ?', [$id]); } /** Aktualisiert sort_order anhand der übergebenen ID-Reihenfolge (Position 0..N). */ public static function updateOrder(array $orderedIds): void { foreach (array_values($orderedIds) as $pos => $id) { $id = (int)$id; if ($id <= 0) continue; Database::execute( 'UPDATE bank_sources SET sort_order = ? WHERE id = ?', [$pos, $id] ); } } private static function hydrate(array $row): array { $row['name'] = $row['bezeichnung']; $row['client_id'] = Crypto::decrypt((string)($row['client_id_enc'] ?? '')); $row['secret'] = Crypto::decrypt((string)($row['secret_enc'] ?? '')); $row['pin'] = Crypto::decrypt((string)($row['pin_enc'] ?? '')); return $row; } /** * Überführt ein Eingabe-Array in die DB-Spalten: * - client_id/secret/pin → *_enc (verschlüsselt) * - nur erlaubte Spalten werden zurückgegeben */ private static function dehydrate(array $data): array { $allowed = [ 'type', 'provider_id', 'bezeichnung', 'kuerzel', 'farbe', 'skip_rows', 'has_header_row', 'delimiter', 'enclosure', 'col_buchungstag', 'col_wertstellung', 'col_vorgang', 'col_buchungstext', 'col_wert', 'col_zahlungspflichtiger', 'col_zahlungsempfaenger', 'col_verwendungszweck', 'date_format', 'decimal_separator', 'thousands_separator', 'buchungstext_template_debit', 'buchungstext_template_credit', 'sandbox', 'last_fetched_at', 'app_name', 'client_id_enc', 'secret_enc', 'blz', 'fints_url', 'benutzerkennung', 'pin_enc', 'account_filter', ]; $out = []; foreach ($allowed as $col) { if (array_key_exists($col, $data)) { $out[$col] = $data[$col]; } } // Klartext-Felder verschlüsseln foreach (['client_id' => 'client_id_enc', 'secret' => 'secret_enc', 'pin' => 'pin_enc'] as $plain => $enc) { if (array_key_exists($plain, $data)) { $val = $data[$plain]; $out[$enc] = ($val === null || $val === '') ? null : Crypto::encrypt((string)$val); } } return $out; } }