简体   繁体   English

对symfony表单集合进行验证失败后,将良好的数据保留在表单中

[英]Keep good data in form after failed validation on symfony form collection

I have a form with a dynamic form collection. 我有一个带有动态表单集合的表单。 The point is that I don't want to allow the user to remove specific entries (that are modified in another part of the app). 关键是我不想允许用户删除特定条目(在应用程序的另一部分中进行了修改)。 So I added a specific validation constraint that works: the form is not valid if I remove an element that is not "deletable". 因此,我添加了一个有效的特定验证约束:如果我删除了一个不可删除的元素,则该表单无效。

The problem is that, as the element was removed in what the user submitted, the element is not in the form anymore, and after submit form data is locked. 问题在于,由于在用户提交的内容中删除了该元素,因此该元素不再处于表单中,并且在提交表单数据之后被锁定。

Here is an example to show the problem: 这是显示问题的示例:

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;
            }
        }
    }
}

Any idea about how to modify form data after submit ? 关于提交后如何修改表单数据的任何想法吗?

Here is a screen of the problem: http://file.nekland.fr/dev/pb_form_collection.jpeg 这是问题的屏幕: http : //file.nekland.fr/dev/pb_form_collection.jpeg

This is a Symfony limitation: https://github.com/symfony/symfony/issues/5480 这是Symfony的限制: https : //github.com/symfony/symfony/issues/5480

A workaround exists: re-creating the form and copy errors of each node of the form to the new form (that contains good data). 存在一种解决方法:重新创建表单并将表单中每个节点的错误复制到新表单(包含良好数据)中。

My solution will be to throw an error in the validator because the user is not able to remove an item (the cross is disabled), so he hacked the system. 我的解决方案是在验证器中引发错误,因为用户无法删除项目(十字被禁用),因此他对系统进行了黑客攻击。 Showing an error is not a problem. 显示错误不是问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM