Skip to content

Commit

Permalink
Merge pull request #202 from sherlockode/fix/repeater_position
Browse files Browse the repository at this point in the history
Fix repeater position for non compound children
  • Loading branch information
Vowow authored Nov 10, 2022
2 parents b4b9b30 + b9a542a commit c3c490c
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 2 deletions.
50 changes: 50 additions & 0 deletions Form/Type/RepeatedChildWrappedType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace Sherlockode\AdvancedContentBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;

/**
* FormType wrapper for non-compound forms inside RepeaterType
* Used in order to be able to add the "position" field
*/
class RepeatedChildWrappedType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->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;
});
}
}
34 changes: 32 additions & 2 deletions Form/Type/RepeaterType.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,37 @@ 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());
}
}

// add the position field to all collection children
$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);

Expand All @@ -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;
Expand Down

0 comments on commit c3c490c

Please sign in to comment.