Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
574 views
in Technique[技术] by (71.8m points)

php - Symfony 3 - Form model data loses property values which are not represented by fields

I have a controller action method which should handle a two-splitted form. Each form handles just a few properties of my Entity Workflow. After submitting the first form I can create and render the second form without problems. Now the problem:

After submitting the second form, the information of all values set in the first form are gone which means that when calling submit (or handleRequest does not make any difference here) the entity object only holds data of the properties set in the first form and it even can′t resolve some values properly.

Here is the Controller (with some comments):

public function createWorkflowAction(Request $request, Project $project, Workflow $workflow = null) {   

    if(!$workflow) {
        $workflow = new Workflow($project);
    }

    $firstFormPart = $this->createForm(WorkflowStatesType::class, $workflow);

    // $firstFormPart->handleRequest($request);
    $firstFormPart->submit($request->get($firstFormPart->getName()), false);

    $secondFormPart = $this->createForm(WorkflowTransitionsType::class, $workflow);
    // secondFormPart is created correct with all values after submitting $firstFormPart and calling submit

    if($firstFormPart->isSubmitted() && $firstFormPart->isValid()) {
        return $this->render('@MyBundle/Workflow/workflow_edit_create_second_part.html.twig', array(
            'form'   => $secondFormPart->createView(),
        ));
        // This will render correctly with all values submitted in the $firstFormPart
    }

    $secondFormPart->submit($request->get($secondFormPart->getName()), false);
    // $secondFormPart->handleRequest($request);
    // HERE IS THE PROBLEM -> After submitting the $secondFormPart all property values set in the $firstFormPart are gone

    if($secondFormPart->isSubmitted() && $secondFormPart->isValid()) {
        dump($workflow);
        die();
    }

    return $this->render('@MyBundle/Workflow/workflow_edit_create_first_part.html.twig', array(
        'form' => $firstFormPart->createView(),
    ));
}

WorkflowStatesType:

class WorkflowStatesType extends AbstractType {

        /**
         * @var DoctrineORMMappingClassMetadata
         */
        private $classMetadata;

        /**
         * WorkflowType constructor.
         * @param EntityManager $em
         */

        public function __construct(EntityManager $em) {
            $this->classMetadata = $em->getClassMetadata(Workflow::class);
        }

        public function buildForm(FormBuilderInterface $builder, array $options) {
            $builder
                ->setMethod('PATCH')
                ->add('name', TextType::class, array(
                    'label' => 'nameTrans',
                    'attr'  => array('maxLength' => $this->classMetadata->getFieldMapping('name')['length']),
                ))
                ->add('states',  CollectionType::class, array(
                    'entry_type'        => StateType::class,
                    'allow_add'         => true,
                    'error_bubbling'    => false,
                    'by_reference'      => false,
                    'label'             => 'workflowStatesTrans',
                ))
                ->add('next', SubmitType::class, array(
                    'label' => 'nextFormPartTrans',
                ));
        }

        public function configureOptions(OptionsResolver $resolver) {
            $resolver->setDefaults(array(
                'data_class'            => Workflow::class,
                'translation_domain'    => 'My_Bundle',
            ));
        }

    }

WorkflowTransitionsType:

class WorkflowTransitionsType extends AbstractType {

        /**
         * @var Workflow
         */
        private $workflow;

        /**
         * @var Session
         */
        private $session;

        /**
         * {@inheritdoc}
         */
        public function buildForm(FormBuilderInterface $builder, array $options) {

            /** @var Workflow $workflow */
            $this->workflow = $options['data'];

                $builder
                    ->setMethod('PATCH')
                    ->add('initialState', ChoiceType::class, array(
                        'choices'           => $this->workflow->getStates(),
                        'choice_label'      => function($state) {
                            return ($state && $state instanceof State) ? $state->getStatekey() : 'noVal';
                        },
                        'choice_value'      => function($state) {
                            return ($state && $state instanceof State) ? $state->getStatekey() : 'noVal';
                        },

                        // This combination of 'expanded' and 'multiple' implements a select box
                        'expanded'          => false,
                        'multiple'          => false,
                    ))
                    ->add('transitions', CollectionType::class, array(
                        'entry_type'        => TransitionType::class,
                        'allow_add'         => true,
                        'allow_delete'      => true,
                        'error_bubbling'    => false,
                        'by_reference'      => false,
                        'label'             => 'transitionsTrans',
                        'entry_options'     => array(
                            'states'    => $this->workflow->getStates(),
                        ),
                    ))
                    ->add('save', SubmitType::class, array(
                        'label'             => 'submitTrans',
                    ));
        }

        public function configureOptions(OptionsResolver $resolver) {
            $resolver->setDefaults(array(
                'data_class'            => Workflow::class,
                'translation_domain'    => 'My_Bundle',
            ));
            $resolver->setRequired(array(
                'session'
            ));
        }
    }

How can I hold the property values of the $workflow submitted in the $firstFormPart when submitting the $secondFormPart?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Because the form is submitted again with only the secondForm data, you are losing the firstForm data.

You have 3 ways to keep them:

1) Set the data from the firstForm into the query

// Insert that instead of the `return $this->render` for the second form
$url = $this->generateUrl(
    $request->attributes->get('_route'),
    array_merge(
        $request->query->all(),
        array('secondForm' => true, 'name' => $workflow->getName(), 'states' => $workflow->getStates()) // change the param
    )
);
return $this->redirect($url);

Before $secondFormPart = $this->createForm(WorkflowTransitionsType::class, $workflow);

Set back the name and states into the $workflow entity, in this example you can check the query variable secondForm to know if the first form was submitted or not

2) Set the data from the firstForm into the next PATCH request with some hidden field

You have to modify the secondForm to handle the data from the firstForm with some hidden form type

3) Set the data in the session before returning the second form

First of all, your entity will have to implement the interface Serializable and declare the method serialize and unserialize

like that

$this->get('session')->set('workflow', $workflow);

The method serialize will be used to store it.

You can set in back with the method unserialize

$session = $this->get('session');
$workflow = new Workflow();
$workflow->unserialize($session->get('workflow'));

Because you are storing the whole entity into the session, this solution will decrease a lot the performance of your application


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...