在symfony表单集合上验证失败后,保持表单中的良好数据

时间:2015-11-19 13:45:45

标签: php forms symfony

我有一个带有动态表单集合的表单。关键是我不想让用户删除特定条目(在应用程序的其他部分修改)。所以我添加了一个有效的特定验证约束:如果我删除了一个不是" deletable"的元素,那么表单无效。

问题在于,当用户提交的元素被删除时,该元素不再在表单中,并且在提交表单数据后被锁定。

以下是显示问题的示例:

class AppointmentController extends Controller
{

    public function editAppointment(Request $request, Appointment $appointment)
    {
        // Here
        // count($appointment->getSlot()) === 3

        $form = $this->createForm('appointment', $appointment, [
            'questionnaire' => $questionnaire
        ]);
        $form->handleRequest($request);

        if ($form->isValid()) {
            // Persisting
        }

        // Here on failing validation, there is
        // count($appointment->getSlot()) === 2
        // Because we removed one slot from "dynamically" in the form, but the user can't do that,
        // so we need to reset the slots but it's not possible because form data is locked after "submit".
        return $this->render('App:Appointment:edit.html.twig', ['form' => $form->createView()]);
    }
}

class AppointmentType extends AbstractTYpe
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('slots', 'collection', [
                'type' => new SlotType(),
                'allow_add' => true,
                'prototype' => true,
                'allow_delete' => true,
                'error_bubbling' => false,
                'by_reference' => false,
                'constraints' => [
                    new WrongSlotRemoval($builder->getData()->getSlots())
                ]
            ])
        ;
    }
}

class WrongSlotRemoval extends Constraint
{
    public $message = 'Impossible to delete slog.';

    /**
     * @var null|\App\Entity\AppointmentSlot[]
     */
    private $slots;

    /**
     * @param \App\Entity\AppointmentSlot[]|null $slots
     */
    public function __construct($slots = null)
    {
        // Clone the collection because it can be modified by reference
        // in order to add or delete items.
        if ($slots !== null) {
            $this->slots = clone $slots;
        }
    }

    /**
     * @return \App\Entity\AppointmentSlot[]
     */
    public function getSlots()
    {
        return $this->slots;
    }

    /**
     * @param \App\Entity\AppointmentSlot[] $slots
     * @return self
     */
    public function setSlots($slots)
    {
        $this->slots = $slots;

        return $this;
    }
}

class WrongSlotRemovalValidator extends ConstraintValidator
{
    /**
     * @param \App\Entity\AppointmentSlot[] $object
     * @param WrongSlotRemoval $constraint
     */
    public function validate($object, Constraint $constraint)
    {
        foreach($constraint->getSlots() as $slot) {
            if (!$object->contains($slot) && !$slot->isDeletable()) {

                $this->context
                    ->buildViolation($constraint->message)
                    ->addViolation()
                ;

                return;
            }
        }
    }
}

有关如何在提交后修改表单数据的想法吗?

以下是问题的屏幕:http://file.nekland.fr/dev/pb_form_collection.jpeg

1 个答案:

答案 0 :(得分:0)

这是一个Symfony限制:https://github.com/symfony/symfony/issues/5480

存在一种解决方法:重新创建表单并将表单的每个节点的错误复制到新表单(包含良好数据)。

我的解决方案是在验证程序中抛出错误,因为用户无法删除项目(交叉被禁用),因此他攻击了系统。显示错误不是问题。