Backup #116
| ID | 116 |
| Dateipfad | /var/www/dev.campus.systemische-tools.de/src/Infrastructure/Persistence/FileBackupRepository.php |
| Version | 1 |
| Typ |
modified |
| Größe | 6.3 KB |
| Hash | c7ed5a2664c8cbde82027d58c9f4e208b473b8d7ae2ecd27983f8818351dec66 |
| Datum | 2025-12-20 19:24:12 |
| Geändert von | claude-code-hook |
| Grund | Claude Code Pre-Hook Backup vor Edit-Operation |
| Datei existiert |
Ja
|
Dateiinhalt
<?php
declare(strict_types=1);
namespace Infrastructure\Persistence;
use Infrastructure\Config\DatabaseFactory;
use PDO;
/**
* Repository for file_backup_history table.
*/
class FileBackupRepository
{
private PDO $db;
public function __construct()
{
$this->db = DatabaseFactory::dev();
}
/**
* Find all backups with optional filters.
*
* @param array<string, mixed> $filters
*/
public function findAll(array $filters = [], int $limit = 50, int $offset = 0): array
{
$sql = 'SELECT id, file_path, content_hash, file_size, version, change_type,
changed_at, changed_by, reason
FROM file_backup_history WHERE 1=1';
$params = [];
if (!empty($filters['search'])) {
$sql .= ' AND file_path LIKE :search';
$params['search'] = '%' . $filters['search'] . '%';
}
if (!empty($filters['change_type'])) {
$sql .= ' AND change_type = :change_type';
$params['change_type'] = $filters['change_type'];
}
$sql .= ' ORDER BY changed_at DESC LIMIT :limit OFFSET :offset';
$stmt = $this->db->prepare($sql);
foreach ($params as $key => $value) {
$stmt->bindValue($key, $value);
}
$stmt->bindValue('limit', $limit, PDO::PARAM_INT);
$stmt->bindValue('offset', $offset, PDO::PARAM_INT);
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
/**
* Count total backups with filters.
*
* @param array<string, mixed> $filters
*/
public function count(array $filters = []): int
{
$sql = 'SELECT COUNT(*) FROM file_backup_history WHERE 1=1';
$params = [];
if (!empty($filters['search'])) {
$sql .= ' AND file_path LIKE :search';
$params['search'] = '%' . $filters['search'] . '%';
}
if (!empty($filters['change_type'])) {
$sql .= ' AND change_type = :change_type';
$params['change_type'] = $filters['change_type'];
}
$stmt = $this->db->prepare($sql);
$stmt->execute($params);
return (int) $stmt->fetchColumn();
}
/**
* Find backup by ID.
*/
public function findById(int $id): ?array
{
$stmt = $this->db->prepare(
'SELECT * FROM file_backup_history WHERE id = :id'
);
$stmt->execute(['id' => $id]);
$result = $stmt->fetch(PDO::FETCH_ASSOC);
return $result !== false ? $result : null;
}
/**
* Find all backups for a specific file path.
*/
public function findByFilePath(string $path): array
{
$stmt = $this->db->prepare(
'SELECT id, file_path, content_hash, file_size, version, change_type,
changed_at, changed_by, reason
FROM file_backup_history
WHERE file_path = :path
ORDER BY version DESC'
);
$stmt->execute(['path' => $path]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
/**
* Get statistics about backups.
*
* @return array<string, int>
*/
public function getStatistics(): array
{
$stats = [];
// Total backups
$stats['total'] = (int) $this->db->query(
'SELECT COUNT(*) FROM file_backup_history'
)->fetchColumn();
// Unique files
$stats['files'] = (int) $this->db->query(
'SELECT COUNT(DISTINCT file_path) FROM file_backup_history'
)->fetchColumn();
// Total versions (max version per file summed)
$stats['versions'] = (int) $this->db->query(
'SELECT COALESCE(SUM(max_version), 0) FROM (
SELECT MAX(version) as max_version FROM file_backup_history GROUP BY file_path
) as v'
)->fetchColumn();
// Last 24 hours
$stats['recent'] = (int) $this->db->query(
'SELECT COUNT(*) FROM file_backup_history WHERE changed_at >= NOW() - INTERVAL 24 HOUR'
)->fetchColumn();
// By change type
$stats['created'] = (int) $this->db->query(
"SELECT COUNT(*) FROM file_backup_history WHERE change_type = 'created'"
)->fetchColumn();
$stats['modified'] = (int) $this->db->query(
"SELECT COUNT(*) FROM file_backup_history WHERE change_type = 'modified'"
)->fetchColumn();
return $stats;
}
/**
* Restore a file from backup.
*
* @throws \RuntimeException If restore fails
*/
public function restore(int $id): bool
{
$backup = $this->findById($id);
if ($backup === null) {
throw new \RuntimeException('Backup not found');
}
$filePath = $backup['file_path'];
$content = $backup['file_content'];
// Check if directory exists
$dir = dirname($filePath);
if (!is_dir($dir)) {
throw new \RuntimeException("Directory does not exist: {$dir}");
}
// Write content back to file
$result = file_put_contents($filePath, $content);
if ($result === false) {
throw new \RuntimeException("Failed to write to file: {$filePath}");
}
// Log the restore action
$this->logRestore($id, $filePath);
return true;
}
/**
* Log restore action to mcp_log.
*/
private function logRestore(int $backupId, string $filePath): void
{
$stmt = $this->db->prepare(
"INSERT INTO mcp_log (tool, operation, parameters, result, logged_at)
VALUES ('backup_restore', 'restore', :params, 'success', NOW())"
);
$stmt->execute([
'params' => json_encode(['backup_id' => $backupId, 'file_path' => $filePath]),
]);
}
/**
* Get content preview (first N lines).
*/
public function getContentPreview(int $id, int $maxLines = 500): ?string
{
$backup = $this->findById($id);
if ($backup === null || empty($backup['file_content'])) {
return null;
}
$lines = explode("\n", $backup['file_content']);
if (count($lines) <= $maxLines) {
return $backup['file_content'];
}
return implode("\n", array_slice($lines, 0, $maxLines)) . "\n\n... (" . (count($lines) - $maxLines) . ' weitere Zeilen)';
}
}
Vollständig herunterladen
Aktionen
Andere Versionen dieser Datei
| ID |
Version |
Typ |
Größe |
Datum |
| 133 |
4 |
modified |
8.6 KB |
2025-12-20 19:53 |
| 129 |
3 |
modified |
8.6 KB |
2025-12-20 19:40 |
| 117 |
2 |
modified |
6.6 KB |
2025-12-20 19:24 |
| 116 |
1 |
modified |
6.3 KB |
2025-12-20 19:24 |
← Zurück zur Übersicht