<?php
declare(strict_types=1);
namespace Domain\DTO;
// @responsibility: DTO für Content-Kritik-Daten aus Repository
final readonly class CritiqueDTO
{
public function __construct(
public int $id,
public int $versionId,
public int $criticId,
public string $criticName,
public string $feedback,
public ?int $score,
public string $model,
public int $tokensInput,
public int $tokensOutput,
public float $costUsd,
public int $durationMs,
public \DateTimeImmutable $createdAt,
) {}
/**
* Create from database row.
*
* @param array<string, mixed> $row
*/
public static function fromDatabaseRow(array $row): self
{
return new self(
id: (int) $row['id'],
versionId: (int) $row['version_id'],
criticId: (int) $row['critic_id'],
criticName: (string) ($row['critic_name'] ?? 'Unbekannt'),
feedback: (string) $row['feedback'],
score: isset($row['score']) ? (int) $row['score'] : null,
model: (string) ($row['model'] ?? 'unknown'),
tokensInput: (int) ($row['tokens_input'] ?? 0),
tokensOutput: (int) ($row['tokens_output'] ?? 0),
costUsd: (float) ($row['cost_usd'] ?? 0.0),
durationMs: (int) ($row['duration_ms'] ?? 0),
createdAt: new \DateTimeImmutable($row['created_at'] ?? 'now'),
);
}
/**
* Check if critique has a score.
*/
public function hasScore(): bool
{
return $this->score !== null;
}
/**
* Get score as percentage (0-100).
*/
public function scorePercentage(): ?int
{
return $this->score;
}
/**
* Get feedback preview.
*/
public function feedbackPreview(int $length = 150): string
{
if (mb_strlen($this->feedback) <= $length) {
return $this->feedback;
}
return mb_substr($this->feedback, 0, $length) . '...';
}
}