diff --git a/Form/Type/RepeatedChildWrappedType.php b/Form/Type/RepeatedChildWrappedType.php new file mode 100644 index 00000000..3c6afe15 --- /dev/null +++ b/Form/Type/RepeatedChildWrappedType.php @@ -0,0 +1,50 @@ +add('wrapped_child', $options['child_form'], $options['child_options']) + ->add('position', HiddenType::class, ['data' => $options['position']]) + ; + + $dataCallback = function (FormEvent $event) { + $data = $event->getData(); + + $data = ['wrapped_child' => $data]; + + $event->setData($data); + }; + + $builder->addEventListener(FormEvents::PRE_SET_DATA, $dataCallback, -5); + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults([ + 'position' => 0, + 'child_options'=> [], + ]); + $resolver->setRequired(['child_form']); + $resolver->setNormalizer('child_options', function (Options $options, $value) { + unset($value['property_path']); + + return $value; + }); + } +} diff --git a/Form/Type/RepeaterType.php b/Form/Type/RepeaterType.php index e8ddda36..c7d171b1 100644 --- a/Form/Type/RepeaterType.php +++ b/Form/Type/RepeaterType.php @@ -20,6 +20,17 @@ public function buildForm(FormBuilderInterface $builder, array $options) $prototype = $builder->getAttribute('prototype'); if ($prototype->getConfig()->getCompound()) { $prototype->add('position', HiddenType::class); + } else { + // rebuild prototype using the RepeatedChildWrappedType + $prototypeOptions = $prototype->getConfig()->getOptions(); + $prototypeOptions = array_merge($prototypeOptions, [ + 'child_options' => $prototype->getConfig()->getOptions(), + 'child_form' => get_class($prototype->getConfig()->getType()->getInnerType()), + 'compound' => true, + ]); + + $prototype = $builder->create($prototype->getConfig()->getName(), RepeatedChildWrappedType::class, $prototypeOptions); + $builder->setAttribute('prototype', $prototype->getForm()); } } @@ -27,12 +38,19 @@ public function buildForm(FormBuilderInterface $builder, array $options) $positionCallback = function (FormEvent $event) { $form = $event->getForm(); - foreach ($form->all() as $child) { + foreach ($form->all() as $i => $child) { if ($child->getConfig()->getCompound()) { - $child->add('position', HiddenType::class); + $child->add('position', HiddenType::class, ['data' => $i]); + } else { + $form->add($i, RepeatedChildWrappedType::class, [ + 'child_options' => $child->getConfig()->getOptions(), + 'child_form' => get_class($child->getConfig()->getType()->getInnerType()), + 'position' => $i + ]); } } }; + $builder->addEventListener(FormEvents::PRE_SET_DATA, $positionCallback, -10); $builder->addEventListener(FormEvents::PRE_SUBMIT, $positionCallback, -10); @@ -54,9 +72,21 @@ public function buildForm(FormBuilderInterface $builder, array $options) return $a['position'] <=> $b['position']; }); + // unset the position key in the saved data + $orderedData = array_map(function ($item) { + if (is_array($item)) { + unset($item['position']); + if (isset($item['wrapped_child'])) { + $item = $item['wrapped_child']; + } + } + return $item; + }, $orderedData); + $event->setData(array_values($orderedData)); }); } + public function getParent() { return CollectionType::class;