refactor: split the questionnaire into teamer and bus feedback
This commit is contained in:
1 parent
2f4f9800dd
commit
a0170f5952
35 files changed
+1114
-554
No files matched your search
@@ -21,8 +21,10 @@ use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
/**
|
||||
* Builds a questionnaire form from its definition. The data is the flat answers array keyed by
|
||||
* question key; each section is a child with inherit_data, so it groups the fields on screen
|
||||
* Builds one form from one or more questionnaire definitions - a teamer after a bus escort answers
|
||||
* teamer_feedback and bus_feedback on one page. The data is keyed by questionnaire key, each
|
||||
* holding that questionnaire's flat answers keyed by question key: every questionnaire is a child
|
||||
* of its own, and each of its sections a child with inherit_data, which groups the fields on screen
|
||||
* without nesting the answers.
|
||||
*
|
||||
* Two buttons: "draft" saves whatever is filled in, "submit" also demands every required question
|
||||
@@ -39,21 +41,32 @@ class QuestionnaireType extends AbstractType
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
{
|
||||
/** @var Definition $definition */
|
||||
$definition = $options['definition'];
|
||||
/** @var list<Definition> $definitions */
|
||||
$definitions = $options['definitions'];
|
||||
|
||||
foreach ($definition->sections as $section) {
|
||||
$sectionBuilder = $builder->create($section->key, FormType::class, [
|
||||
'inherit_data' => true,
|
||||
'label' => $section->title ?? false,
|
||||
'block_prefix' => 'questionnaire_section',
|
||||
foreach ($definitions as $definition) {
|
||||
$questionnaireBuilder = $builder->create($definition->key, FormType::class, [
|
||||
'label' => $definition->title,
|
||||
'help' => $definition->description,
|
||||
'empty_data' => [],
|
||||
'block_prefix' => 'questionnaire_part',
|
||||
]);
|
||||
|
||||
foreach ($section->questions as $question) {
|
||||
$sectionBuilder->add($question->key, ...$this->field($question));
|
||||
foreach ($definition->sections as $section) {
|
||||
$sectionBuilder = $builder->create($section->key, FormType::class, [
|
||||
'inherit_data' => true,
|
||||
'label' => $section->title ?? false,
|
||||
'block_prefix' => 'questionnaire_section',
|
||||
]);
|
||||
|
||||
foreach ($section->questions as $question) {
|
||||
$sectionBuilder->add($question->key, ...$this->field($definition, $question));
|
||||
}
|
||||
|
||||
$questionnaireBuilder->add($sectionBuilder);
|
||||
}
|
||||
|
||||
$builder->add($sectionBuilder);
|
||||
$builder->add($questionnaireBuilder);
|
||||
}
|
||||
|
||||
$builder
|
||||
@@ -63,24 +76,26 @@ class QuestionnaireType extends AbstractType
|
||||
->add(self::SUBMIT, SubmitType::class, [
|
||||
'label' => 'Absenden',
|
||||
])
|
||||
->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) use ($definition): void {
|
||||
->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) use ($definitions): void {
|
||||
$form = $event->getForm();
|
||||
|
||||
if (!$this->isFinal($form)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$answers = $form->getData();
|
||||
foreach ($definitions as $definition) {
|
||||
$answers = $form->getData()[$definition->key] ?? [];
|
||||
|
||||
foreach ($definition->sections as $section) {
|
||||
foreach ($section->questions as $question) {
|
||||
if ($question->required
|
||||
&& $definition->isVisible($question, $answers)
|
||||
&& $this->isEmpty($answers[$question->key] ?? null)
|
||||
) {
|
||||
$form->get($section->key)->get($question->key)->addError(
|
||||
new FormError('Bitte beantworte diese Frage.')
|
||||
);
|
||||
foreach ($definition->sections as $section) {
|
||||
foreach ($section->questions as $question) {
|
||||
if ($question->required
|
||||
&& $definition->isVisible($question, $answers)
|
||||
&& $this->isEmpty($answers[$question->key] ?? null)
|
||||
) {
|
||||
$form->get($definition->key)->get($section->key)->get($question->key)->addError(
|
||||
new FormError('Bitte beantworte diese Frage.')
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -91,8 +106,10 @@ class QuestionnaireType extends AbstractType
|
||||
public function configureOptions(OptionsResolver $resolver): void
|
||||
{
|
||||
$resolver
|
||||
->setRequired('definition')
|
||||
->setAllowedTypes('definition', Definition::class)
|
||||
->setRequired('definitions')
|
||||
->setAllowedTypes('definitions', Definition::class.'[]')
|
||||
->setAllowedValues('definitions', static fn (array $definitions): bool => [] !== $definitions
|
||||
&& count($definitions) === count(array_unique(array_map(static fn (Definition $definition): string => $definition->key, $definitions))))
|
||||
->setDefaults([
|
||||
'data_class' => null,
|
||||
'empty_data' => [],
|
||||
@@ -114,16 +131,17 @@ class QuestionnaireType extends AbstractType
|
||||
/**
|
||||
* @return array{0: class-string, 1: array<string, mixed>}
|
||||
*/
|
||||
private function field(Question $question): array
|
||||
private function field(Definition $definition, Question $question): array
|
||||
{
|
||||
$common = [
|
||||
'label' => $question->label,
|
||||
'help' => $question->help,
|
||||
'required' => false,
|
||||
// read by assets/controllers/questionnaire_controller.js
|
||||
'row_attr' => ['data-question-key' => $question->key] + (null === $question->showIf ? [] : [
|
||||
// read by assets/controllers/questionnaire_controller.js; prefixed with the questionnaire,
|
||||
// since question keys are only unique within one
|
||||
'row_attr' => ['data-question-key' => $definition->key.'.'.$question->key] + (null === $question->showIf ? [] : [
|
||||
'data-show-if' => json_encode([
|
||||
'question' => $question->showIf->question,
|
||||
'question' => $definition->key.'.'.$question->showIf->question,
|
||||
'operator' => $question->showIf->operator->value,
|
||||
'value' => $question->showIf->value,
|
||||
], JSON_THROW_ON_ERROR),
|
||||
|
||||
Reference in new issue
Block a user