← Code-Übersicht

PostgresProzessRepository.php

Pfad: src/Infrastructure/Persistence/PostgresProzessRepository.php

Ext: php

Größe: 3064 Bytes

Geändert: 2026-07-16T01:41:14+02:00

Frühere Version vom 2026-07-16T01:41:14+02:00 · zur aktuellen Fassung

<?php
declare(strict_types=1);

namespace Demo\Infrastructure\Persistence;

use Demo\Domain\Prozess\Prozess;
use Demo\Domain\Prozess\ProzessDetail;
use Demo\Domain\Prozess\ProzessRepository;
use PDO;

/**
 * Postgres-Adapter des ProzessRepository. Ausschliesslich PDO Prepared Statements;
 * die Detailbestandteile laedt der injizierte ProzessDetailLader.
 */
final class PostgresProzessRepository implements ProzessRepository
{
    /** @var PdoConnectionFactory Verbindungs-Fabrik. */
    private PdoConnectionFactory $factory;

    /** @var ProzessDetailLader Laedt Schritte, Kanten und Doku-Verweise. */
    private ProzessDetailLader $lader;

    /** @var PDO|null Zwischengespeicherte Verbindung. */
    private ?PDO $pdo = null;

    /**
     * @param PdoConnectionFactory $factory Injizierte Verbindungs-Fabrik.
     * @param ProzessDetailLader   $lader   Laedt die Detailbestandteile.
     */
    public function __construct(PdoConnectionFactory $factory, ProzessDetailLader $lader)
    {
        $this->factory = $factory;
        $this->lader = $lader;
    }

    /**
     * @inheritDoc
     */
    public function liste(): array
    {
        $sql = 'SELECT id, slug, titel, beschreibung, array_to_json(tags) AS tags, '
            . 'created_at, updated_at FROM prozesse ORDER BY updated_at DESC';
        $stmt = $this->pdo()->query($sql);
        $out = [];
        foreach ($stmt === false ? [] : $stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
            $out[] = $this->kopf($row);
        }

        return $out;
    }

    /**
     * @inheritDoc
     */
    public function detail(string $slug): ?ProzessDetail
    {
        $sql = 'SELECT id, slug, titel, beschreibung, array_to_json(tags) AS tags, '
            . 'created_at, updated_at FROM prozesse WHERE slug = :slug';
        $stmt = $this->pdo()->prepare($sql);
        $stmt->execute([':slug' => $slug]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);
        if ($row === false) {
            return null;
        }
        $pid = (int) $row['id'];

        return new ProzessDetail(
            $this->kopf($row),
            $this->lader->schritte($pid),
            $this->lader->kanten($pid),
            $this->lader->dokus($pid)
        );
    }

    /**
     * Baut den Prozess-Kopf aus einer Zeile.
     *
     * @param array<string,mixed> $row Ergebniszeile.
     * @return Prozess Kopf.
     */
    private function kopf(array $row): Prozess
    {
        $tags = json_decode((string) $row['tags'], true);

        return new Prozess(
            (int) $row['id'],
            (string) $row['slug'],
            (string) $row['titel'],
            (string) $row['beschreibung'],
            is_array($tags) ? array_values(array_map('strval', $tags)) : [],
            (string) $row['created_at'],
            (string) $row['updated_at']
        );
    }

    /**
     * Liefert die zwischengespeicherte Verbindung (lazy).
     *
     * @return PDO Aktive Verbindung.
     */
    private function pdo(): PDO
    {
        return $this->pdo ??= $this->factory->create();
    }
}