feat: decide when a conditional questionnaire question is shown

This commit is contained in:
fromme committed 2026-10-27 16:43:14 +01:00
1 parent a84275b40e
commit d06b647dac
4 files changed
+170

No files matched your search

+22
View File
@@ -19,4 +19,26 @@ readonly class Condition
public string|array|int $value,
) {
}
/**
* Whether the controlling question's answer satisfies this condition. An unanswered question
* satisfies none: a follow-up stays hidden until there is something to follow up on.
*
* This says nothing about whether the controlling question is itself shown; that is
* Definition::isVisible().
*
* @param array<string, mixed> $answers keyed by question key
*/
public function isMet(array $answers): bool
{
$answer = $answers[$this->question] ?? null;
return match ($this->operator) {
ConditionOperator::EQUALS => $answer === $this->value,
ConditionOperator::IN => in_array($answer, $this->value, true),
// A rating arrives as an int from the form and from stored JSON alike; anything else
// is not a rating.
ConditionOperator::LTE => is_int($answer) && $answer <= $this->value,
};
}
}
+23
View File
@@ -40,4 +40,27 @@ readonly class Definition
{
return $this->getQuestions()[$key] ?? null;
}
/**
* Whether a question is shown for these answers: it has no show_if, or its condition is met
* and the question it depends on is shown in turn. A hidden question's answer counts for
* nothing, even if one was given before it was hidden - otherwise a follow-up could stay open
* on an answer the respondent can no longer see.
*
* Terminates because a show_if may only name an earlier question (QuestionnaireCatalog).
*
* @param array<string, mixed> $answers keyed by question key
*/
public function isVisible(Question $question, array $answers): bool
{
if (null === $question->showIf) {
return true;
}
$controlling = $this->getQuestion($question->showIf->question);
return null !== $controlling
&& $this->isVisible($controlling, $answers)
&& $question->showIf->isMet($answers);
}
}