如何从Symfony3中提交的表单中获取数据?

如何从Symfony3中提交的表单中获取数据?

问题描述:

I faced up with some non-ordinary situation for me.

1) I have a dependent list that rendering by Symfony FormType like this: enter image description here

2) Location and Instruction fields are depend from Company field.

3) When I change Company field (onchange event js) then goes ajax request that retrieves data from the database and build a dropdown list.

4) But when form is submitted I have an error: enter image description here

Please help me to resolve this. Thanks in advance.

My formType:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('hours')
        ->add('messageText', null, ['required' => false])
        ->add('company', null, [
            'choice_label' => 'name',
            'placeholder' => 'Please select company',
            'required' => true
        ])
        ->add('procedure', TextType::class, ['attr' => ['placeholder' => 'Please type code or description'] ])
        ->add('instruction', ChoiceType::class, ['mapped' => false])
        ->add('location', ChoiceType::class, ['mapped' => false])

    ;
}

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

Action from controller:

/**
 * @Route("/admin/api/instructions", name="admin_api_instructions")
 * @param Request $request
 * @return JsonResponse
 */
public function getInstructionsByCompanyId(Request $request)
{
    $id = $request->get('id');
    if (!$id) {
        return new JsonResponse('No data', 404);
    }

    $instructions = $this->getDoctrine()->getRepository('OctaneBundle:Instruction')->findInstructionsByCompanyId($id);

    return new JsonResponse($instructions);
}

findInstructionsByCompanyId($id):

public function findInstructionsByCompanyId($id)
{
    $qb = $this->createQueryBuilder('i');
    if ($id) {
        $qb
            ->where('i.company = :id')
            ->setParameter('id', $id);
    }

    return $qb->getQuery()->getResult();
}

response from api (i.e.: admin/api/instructions?id=1):

[{"id":2,"label":"First instruction"},{"id":3,"label":"First instruction"}]

If you need any additional information please leave comments below. Thanks

Thanks for the answer but I found out more elegant solution for my case. So,

my formType now:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ...
        ->add('instruction', FormattedSelectType::class, ['class' => Instruction::class])
        ->add('location', FormattedSelectType::class, ['class' => Location::class])
    ;
}

FormattedSelectType:

class FormattedSelectType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'choice_label' => function (FormattedLabelInterface $entity) {
                return $entity->getFormattedLabel();
            }
        ));
    }

    /**
     * {@inheritdoc}
     */
    public function getParent()
    {
        return EntityType::class;
    }
}

Etities Location and Instruction entities implement JsonSerializable and custom FormattedLabelInterface interface and have the next methods:

/**
 * @return string
 */
public function getFormattedLabel()
{
    return sprintf(self::LABEL_FORMATTED, $this->zip, $this->city, $this->name, $this->address, $this->phone);
}

/**
 * @return array|mixed
 */
public function jsonSerialize()
{
    return [
        'id' => $this->id,
        'label' => $this->getFormattedLabel()
    ];
}

Symfony's Validator expects that your submitted form will have a submitted instruction and location value that exists in the list you provided when creating your form in form type class. Since you are not providing any options for instructions and locations, you are getting a validation error.

In order to bypass this error you should use Symfony's Form Events in your buildForm function in your form type like this:

$builder->get('company')->addEventListener(
        FormEvents::POST_SUBMIT,
        function (FormEvent $event) {
            $company = $event->getForm()->getData();
            $form = $event->getForm()->getParent();
            $form->add('location', EntityType::class, array(
                'class' => Location::class,
                'query_builder' => function (EntityRepository $repo) use ($company) {
                    return $repo->createQueryBuilder('location')
                        ->where('location.company = :company')
                        ->setParameter('company', $company->getId());
                }
            ));
            $form->add('instruction', EntityType::class, array(
                'class' => Instruction::class,
                'query_builder' => function (EntityRepository $repo) use ($company) {
                    return $repo->createQueryBuilder('instruction')
                        ->where('instruction.company = :company')
                        ->setParameter('company', $company->getId());
                }
            ));
        }
    );