dimension = $dimension; $this->field = trim($field); $this->weight = max(0.0, $weight); $this->criterion = $criterion; $this->target = max(1, $target); $this->critical = $critical; $this->impact = trim($impact) ?: 'Improves ' . $dimension; } public function evaluate($value): QualityEvidence { $actual = $this->measure($value); $score = $this->criterion === self::PRESENT ? ($actual > 0 ? 100.0 : 0.0) : min(100.0, ($actual / $this->target) * 100); $satisfied = $score >= 100.0; $reason = $satisfied ? $this->field . ' meets the quality target.' : $this->field . ' is missing or below the quality target.'; return new QualityEvidence($this->dimension, $this->field, $score, $satisfied, $reason); } public function getDimension(): string { return $this->dimension; } public function getField(): string { return $this->field; } public function getWeight(): float { return $this->weight; } public function isCritical(): bool { return $this->critical; } public function getImpact(): string { return $this->impact; } private function measure($value): int { if ($value === null || $value === '' || $value === []) return 0; if ($this->criterion === self::MIN_COUNT) return is_array($value) ? count($value) : 1; if ($this->criterion === self::MIN_LENGTH) return strlen(trim((string) $value)); return 1; } }