根据Symfony 3.3中的url参数动态设置表单字段

时间:2017-12-14 09:02:09

标签: php symfony symfony-forms

我正在使用Symfony 3.3。我有一个表单需要根据url中的参数动态显示一些字段。

最初会向用户显示仅包含主题字段的表单。之后,他选择一个主题,表格中的一些字段要么隐藏,要么显示。有些字段可以为空,因此不必完成。

我创建了Form,看起来像这样。

就我而言,感觉和看起来像一团糟。我对symfony非常陌生,关于这个特定场景的文档要么不存在,要么我似乎无法找到它。

const CONTACT_CHOICE_BLANK = 'blank';
const CONTACT_CHOICE_REGISTER = 'register';
const CONTACT_CHOICE_COMPANY = 'company';
const CONTACT_CHOICE_CONTACT = 'contact';

....

/**
 * @return string
 */
private function getChoice() {
    if($this->requestStack->getCurrentRequest()->query->has('subject')) {
        $subject = $this->requestStack->getCurrentRequest()->query->get('subject');
        switch($subject){
            case self::CONTACT_CHOICE_REGISTER:
                $default_choice = 'contact.form.select.option.' . self::CONTACT_CHOICE_REGISTER;
                break;
            case self::CONTACT_CHOICE_COMPANY:
                $default_choice = 'contact.form.select.option.' . self::CONTACT_CHOICE_COMPANY;
                break;
            case self::CONTACT_CHOICE_CONTACT:
                $default_choice = 'contact.form.select.option.' . self::CONTACT_CHOICE_CONTACT;
                break;

            case self::CONTACT_CHOICE_BLANK:
            default:
                $default_choice = 'contact.form.select.option.' . self::CONTACT_CHOICE_BLANK;
                break;
        }
        return $default_choice;
    }

    return self::CONTACT_CHOICE_BLANK;
}

/**
 * {@inheritdoc}
 */
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $default_choice = $this->getChoice();

    $this->session->set('show_message', false);
    $this->session->set('show_email', false);
    $this->session->set('show_company', false);
    $this->session->set('show_email_pro', false);
    $this->session->set('show_company_spouse', false);

    $builder
        ->add('subject', ChoiceType::class, array(
            'choices' => array(
                'contact.form.select.option.' . self::CONTACT_CHOICE_BLANK    => self::CONTACT_CHOICE_BLANK,
                'contact.form.select.option.' . self::CONTACT_CHOICE_REGISTER => self::CONTACT_CHOICE_REGISTER,
                'contact.form.select.option.' . self::CONTACT_CHOICE_COMPANY  => self::CONTACT_CHOICE_COMPANY,
                'contact.form.select.option.' . self::CONTACT_CHOICE_CONTACT  => self::CONTACT_CHOICE_CONTACT,
            ),
            'label' => 'contact.form.select.subject',
            'required' => true,
            'data' => $default_choice,
        ))

        ->add('firstName', TextType::class, array('label' => 'contact.form.input.firstname'))
        ->add('familyName', TextType::class, array('label' => 'contact.form.input.familyname'))
        ->add('phoneNumber', TextType::class, array('label' => 'contact.form.input.phone'))
        ->add('contactReason', ChoiceType::class, array(
                'choices' => array(
                    'contact.form.select.option.advertising' => 'contact.form.select.option.advertising',
                    'contact.form.select.option.internet' => 'contact.form.select.option.internet',
                    'contact.form.select.option.member' => 'contact.form.select.option.member',
                    'contact.form.select.option.word' => 'contact.form.select.option.word',
                    'contact.form.select.option.other' => 'contact.form.select.option.other'),
                'label' => 'contact.form.select.reason'
            ))
        ->add('send', SubmitType::class, array('label' => 'contact.form.textarea.send'));


    $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($default_choice) {
        $form = $event->getForm();

        if($default_choice == 'contact.form.select.option.information_request') {
            $form->add('email', TextType::class, array(
                'label' => 'contact.form.input.email',
            ));
            $this->session->set('show_email', true);
        }

        if($default_choice == 'contact.form.select.option.business_membership_application') {
            $form->add('emailPro', TextType::class, array(
                'label' => 'contact.form.input.emailPro',
            ));
            $form->add('company', TextType::class, array(
                'label' => 'contact.form.input.company',
            ));
            $this->session->set('show_email_pro', true);
            $this->session->set('show_company', true);
        }

        if($default_choice == 'contact.form.select.option.registration_request') {
            $form->add('companySpouse', TextType::class, array(
                'label' => 'contact.form.input.companyspouse',
            ));
            $this->session->set('show_company_spouse', true);
        }

        if($default_choice == 'contact.form.select.option.registration_request' || $default_choice == 'contact.form.select.option.information_request') {
            $form->add('message', TextareaType::class, array(
                'label' => 'contact.form.textarea.message',
            ));
            $this->session->set('show_message', true);
        }
    });
}

在控制器中,处理此表单的函数如下所示:

public function contactAction(Request $request, Mailer $mailer) {

    $contact = new Contact();
    $form = $this->createForm(ContactType::class, $contact, ['allow_extra_fields' => true]);
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {
        $mailer->sendContactMail($form);

        $em = $this->getDoctrine()->getManager();
        $em->persist($contact);
        $em->flush();
    }

    return $this->render('WIVCoreBundle:Core:contact.html.twig', array(
        'form' => $form->createView(),
        'routes' => [
            'blank' => $this->generateUrl('wiv_core_contact', ['subject' => ContactType::CONTACT_CHOICE_BLANK]),
            'register' => $this->generateUrl('wiv_core_contact', ['subject' => ContactType::CONTACT_CHOICE_REGISTER]),
            'company' => $this->generateUrl('wiv_core_contact', ['subject' => ContactType::CONTACT_CHOICE_COMPANY]),
            'contact' => $this->generateUrl('wiv_core_contact', ['subject' => ContactType::CONTACT_CHOICE_CONTACT]),
        ],
        'default_route' =>  $this->generateUrl('wiv_core_contact'),
    ));
}

我的问题:是否有更好的方法来显示/隐藏字段?也许某些事情并不像一团糟?

我不需要握手,只有一些指向正确的方向。也许我错过了文档的某些部分。

3 个答案:

答案 0 :(得分:0)

是的,有更好的方法可以做到这一点。您可以使用表单事件来修改表单的元素。还有一个菜谱条目,其中描述了此功能:http://symfony.com/doc/current/form/dynamic_form_modification.html

我还强烈推荐Bernhard Schussek(该组件的创建者)的幻灯片:

https://speakerdeck.com/webmozart/symfony2-form-tricks

答案 1 :(得分:0)

我不确定我是否收到您的问题,如果我弄错了,我会提供答案并随意发表评论。

为什么不在控制器中的contact实体中设置主题:

public function contactAction(Request $request, Mailer $mailer) {

    $contact = new Contact();
    $contact->setSubject($request->query->get('subject');
    ..... 
}

contact实体传递给表单时,它已经包含主题字段,然后在PRE_SET_DATA事件中检查subject实体的contact字段:< / p>

 $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($default_choice) {
    $form = $event->getForm();
    $contact = $event->getData();
    if ($contact && $contact->getSubject() == 'value1' ) {
       $form->add(...)
     // do your magic here 
    }));
    }

来源:http://symfony.com/doc/2.8/form/dynamic_form_modification.html

答案 2 :(得分:0)

您可以使用您的实体(或DTO)来执行工作,而不是设置“表单”字段。为了使其变得更加简单,您可以使用Symfony的PropertyAccess组件。

类似这样的东西:

public function contactAction(Request $request, Mailer $mailer)
{
    $contact = new Contact();
    $contact->fromArray($request->query->all());

    $form = $this->createForm(ContactType::class, $contact, ['allow_extra_fields' => true]);

    //...
}


class Contact
{
    public function fromArray(array $properties) : void
    {
        $propertyAccessor = PropertyAccess::createPropertyAccessor();

        foreach ($properties as $key => $value) {
            if (! $propertyAccessor->isWritable($this, $key)) {
                continue;
            }

            $propertyAccessor->setValue($this, $key, $value);
        }
    }
}