PostgresCodeDateiRepository.php
Pfad: src/Infrastructure/Persistence/PostgresCodeDateiRepository.php
Ext: php
Größe: 5579 Bytes
Geändert: 2026-07-16T10:06:48+02:00
Frühere Version vom 2026-07-16T10:06:48+02:00 · zur aktuellen Fassung
<?php
declare(strict_types=1);
namespace Demo\Infrastructure\Persistence;
use Demo\Domain\Code\CodeDatei;
use Demo\Domain\Code\CodeDateiRepository;
use PDO;
use PDOStatement;
use Throwable;
final class PostgresCodeDateiRepository implements CodeDateiRepository
{
private PdoConnectionFactory $factory;
private ?PDO $pdo = null;
public function __construct(PdoConnectionFactory $factory)
{
$this->factory = $factory;
}
public function liste(): array
{
$sql = 'SELECT id, relativer_pfad, datei_name, datei_erweiterung, code, code_hash,'
. ' datei_groesse, datei_mtime, created_at, updated_at FROM code_datei ORDER BY relativer_pfad';
$stmt = $this->pdo()->query($sql);
$ausgabe = [];
foreach ($stmt === false ? [] : $stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
$ausgabe[] = $this->hydrate($row);
}
return $ausgabe;
}
public function byId(int $id): ?CodeDatei
{
$sql = 'SELECT id, relativer_pfad, datei_name, datei_erweiterung, code, code_hash,'
. ' datei_groesse, datei_mtime, created_at, updated_at FROM code_datei WHERE id = :id';
$stmt = $this->pdo()->prepare($sql);
$stmt->execute([':id' => $id]);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
return $row === false ? null : $this->hydrate((array) $row);
}
public function synchronisiere(array $dateien): void
{
$pdo = $this->pdo();
$pdo->beginTransaction();
try {
$bestehende = $this->bestehendeZeilen();
$einsetzen = $pdo->prepare(
'INSERT INTO code_datei (relativer_pfad, datei_name, datei_erweiterung, code, code_hash,'
. ' datei_groesse, datei_mtime)'
. ' VALUES (:relativer_pfad, :datei_name, :datei_erweiterung, :code, :code_hash,'
. ' :datei_groesse, :datei_mtime)'
);
$aktualisieren = $pdo->prepare(
'UPDATE code_datei'
. ' SET datei_name = :datei_name, datei_erweiterung = :datei_erweiterung,'
. ' code = :code, code_hash = :code_hash, datei_groesse = :datei_groesse,'
. ' datei_mtime = :datei_mtime WHERE id = :id'
);
$entfernen = $pdo->prepare('DELETE FROM code_datei WHERE relativer_pfad = :relativer_pfad');
foreach ($dateien as $datei) {
if (!$datei instanceof CodeDatei) {
continue;
}
$this->importiereDatei($datei, $bestehende, $einsetzen, $aktualisieren);
unset($bestehende[$datei->relativerPfad]);
}
foreach (array_keys($bestehende) as $zuLoeschen) {
$entfernen->execute([':relativer_pfad' => $zuLoeschen]);
}
$pdo->commit();
} catch (Throwable $throwable) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
throw $throwable;
}
}
private function importiereDatei(CodeDatei $datei, array &$bestehende, PDOStatement $einsetzen, PDOStatement $aktualisieren): void
{
$pfad = $datei->relativerPfad;
if (!isset($bestehende[$pfad])) {
$this->speichereNeu($einsetzen, $datei);
return;
}
if ($bestehende[$pfad]['hash'] !== $datei->codeHash) {
$aktualisieren->execute([
':id' => $bestehende[$pfad]['id'],
':datei_name' => $datei->dateiName,
':datei_erweiterung' => $datei->dateiErweiterung,
':code' => $datei->code,
':code_hash' => $datei->codeHash,
':datei_groesse' => $datei->dateiGroesse,
':datei_mtime' => $this->zeitstempelFromDatei($datei->geaendert),
]);
}
}
private function speichereNeu(PDOStatement $einsetzen, CodeDatei $datei): void
{
$einsetzen->execute([
':relativer_pfad' => $datei->relativerPfad,
':datei_name' => $datei->dateiName,
':datei_erweiterung' => $datei->dateiErweiterung,
':code' => $datei->code,
':code_hash' => $datei->codeHash,
':datei_groesse' => $datei->dateiGroesse,
':datei_mtime' => $this->zeitstempelFromDatei($datei->geaendert),
]);
}
private function bestehendeZeilen(): array
{
$bestehende = [];
$stmt = $this->pdo()->query('SELECT id, relativer_pfad, code_hash FROM code_datei');
foreach ($stmt === false ? [] : $stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
$bestehende[(string) $row['relativer_pfad']] = ['id' => (int) $row['id'], 'hash' => (string) $row['code_hash']];
}
return $bestehende;
}
private function hydrate(array $row): CodeDatei
{
return new CodeDatei(
(int) $row['id'],
(string) $row['relativer_pfad'],
(string) $row['datei_name'],
(string) $row['datei_erweiterung'],
(string) $row['code'],
(string) $row['code_hash'],
(int) $row['datei_groesse'],
(string) $row['datei_mtime'],
(string) $row['updated_at'],
(string) $row['created_at']
);
}
private function zeitstempelFromDatei(string $iso): string
{
return gmdate('Y-m-d H:i:s', strtotime($iso) ?: time());
}
private function pdo(): PDO
{
return $this->pdo ??= $this->factory->create();
}
}