craue / CraueFormFlowBundle

Multi-step forms for your Symfony project.
MIT License
736 stars 118 forks source link

FormFlow with EntityType #327

Open ralitsavladimirova opened 6 years ago

ralitsavladimirova commented 6 years ago

Guys, I went into a trouble I'm not sure how to get out of.

My flow data type is Order entity, which has ManyToOne relation with PaymentMethod entity.

One of my steps is a simple selection from an EntityType (Symfony\Bridge\Doctrine\Form\Type\EntityType). It's all right until I decide to get back to that step after having it submitted earlier. Then I receive the following error: Entity of type "SharedBundle\Entity\PaymentMethod" passed to the choice field must be managed. Maybe you forget to persist it in the entity manager?.

As far as I understand, when the flow data is retrieved from the session and unserialized, the entity is not merged back to the entity manager and thus I'm receiving the error. The problem is that I was unable to find the right place to merge it manually - it's either too early and I don't have the data yet (FormFlowEvents::PRE_BIND), or too late (FormFlowEvents::POST_BIND_SAVED_DATA), or it somehow remains unnoticed (FormFlowEvents::GET_STEPS).

I also have trouble with the Symfony form events. Seems like FormEvents::PRE_SET_DATA is the right place - before the error occur and having all needed data, but apparently changing the data there doesn't help a lot and remains unnoticed. This is my listener code:

$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
            /** @var Order $order */
            $order = $event->getData();

            if ($order->getPaymentMethod() !== null && !$this->entityManager->contains($order->getPaymentMethod())){
                $paymentMethod = $this->entityManager->merge($order->getPaymentMethod());
                $order->setPaymentMethod($paymentMethod);
            }
        });

Can someone give me a clue is there some bug, missing functionality or I am doing something terribly wrong? The only way I can imagine getting around this is having some custom DataModel and several view transformers for the different form types, which seems like an overkill. Anyway, is that approach acceptable?

Thank you!

ryanm352 commented 6 years ago

You need to call the setData() method with the newly set data:

$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
            /** @var Order $order */
            $order = $event->getData();

            if ($order->getPaymentMethod() !== null && !$this->entityManager->contains($order->getPaymentMethod())){
                $paymentMethod = $this->entityManager->merge($order->getPaymentMethod());
                $order->setPaymentMethod($paymentMethod);
            }
            $event->setData($order);
        });