【问题标题】:Symfony2: dynamic form using Form EventsSymfony2:使用表单事件的动态表单
【发布时间】:2015-05-05 09:01:58
【问题描述】:

在我的 Symfony2 项目中制作动态表单时遇到一些问题。我尝试关注文档here,但很难理解如何真正进行。我尝试在page 上创建这样的表格。

确实,我需要创建一个动态表单当之前从下拉列表中选择一个值时,下拉列表会动态更改其值

此动态表单涉及 4 个实体:

Parcsimmobilier.php ManyToOne Ensembles.php ManyToOne Batiments.php ManyToOne Zonestechnique.php

1- first 下拉列表涉及 parc,当我在此下拉列表中选择一个值时,会出现整体下拉列表。 ensembles 下拉列表的值必须属于我首先选择的 parcs。

2- 第二个带有集合值的下拉列表:当我选择一个值时,第三个下拉列表出现,它涉及我的区域的类别(实体 Zonestechnique)。

3- 区域类别下拉列表有 多个 选择,但是当我选择值“outside”时,会出现最后一个带有 batiments 值的下拉列表,但值为“无”不可避免。但是,如果我选择 other values 而不是“outside”,则 batiments 下拉列表会显示所有 batiments(属于我之前选择的集合)

4- 当我完成所有这些步骤时,会出现表格的其余部分(区域技术实体的表格)

当我想在我的数据库中添加/创建新的 Zones 技术时,我必须填写此表单。

这里是我的entities的代码:

//Parcsimmobilier entity
class Parcsimmobilier
{
/**
 * @var integer
 *
 * @ORM\Column(name="id", type="integer", nullable=false)
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="IDENTITY")
 */
private $id;

/**
 * @var string
 *
 * @ORM\Column(name="nom", type="string", length=150, nullable=false)
 */
private $nom;

 /**
 * @var \Doctrine\Common\Collections\Collection
 *
 * @ORM\OneToMany(targetEntity="Ensembles", mappedBy="parcsimmobilier")
 */
private $ensembles;
//end of Parcsimmobilier entity


//Ensembles entity
class Ensembles
{
/**
 * @var integer
 *
 * @ORM\Column(name="id", type="integer", nullable=false)
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="IDENTITY")
 */
private $id;

 /**
 * @var string
 *
 * @ORM\Column(name="nom", type="string", length=150, nullable=false)
 */
private $nom;

 /**
 * @var \Parcsimmobilier
 *
 * @ORM\ManyToOne(targetEntity="Parcsimmobilier")
 * @ORM\JoinColumns({
 *   @ORM\JoinColumn(name="parcsimmobilier_id", referencedColumnName="id")
 * })
 */
private $parcsimmobilier;
//end of Ensembles entity


//Batiments entity
class Batiments
{
/**
 * @var integer
 *
 * @ORM\Column(name="id", type="integer", nullable=false)
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="IDENTITY")
 */
private $id;

/**
 * @var string
 *
 * @ORM\Column(name="nom", type="string", length=150, nullable=true)
 */
private $nom;

/**
 * @var \Ensembles
 *
 * @ORM\ManyToOne(targetEntity="Ensembles")
 * @ORM\JoinColumns({
 *   @ORM\JoinColumn(name="ensembles_id", referencedColumnName="id")
 * })
 */
private $ensembles;
//end of Batiments entity


//Zonestechnique entity
class Zonestechnique
{
/**
 * @var integer
 *
 * @ORM\Column(name="id", type="integer", nullable=false)
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="IDENTITY")
 */
private $id;

/**
 * @var string
 *
 * @ORM\Column(name="nom", type="string", length=150, nullable=false)
 */
private $nom;

/**
 * @var \Batiments
 *
 * @ORM\ManyToOne(targetEntity="Batiments")
 * @ORM\JoinColumns({
 *   @ORM\JoinColumn(name="batiments_id", referencedColumnName="id")
 * })
 */
private $batiments;

/**
 * @var \Doctrine\Common\Collections\Collection
 *
 * @ORM\ManyToMany(targetEntity="Categorieszonestechnique")
 * @ORM\JoinTable(name="zonestechnique_categorieszonestechnique",
 *   joinColumns={
 *     @ORM\JoinColumn(name="zonestechnique_id", referencedColumnName="id")
 *   },
 *   inverseJoinColumns={
 *     @ORM\JoinColumn(name="categorieszonestechnique_id", referencedColumnName="id")
 *   }
 * )
 */

 private $categorieszonestechnique;

按照文档,这是我的表单类型,ZonesTechniqueType.php:

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;

class ZonestechniqueType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('parcsimmobilier', 'entity', array(
                                            'class'    => 'EnexgirDatabaseBundle:Parcsimmobilier',
                                            'property' => 'nom',
                                            'multiple' => false,
                                            'required' => true,
                                            'mapped' => false,
                                            'empty_value' => '-- sélectionner un parc --',
                                            'label'    => 'Choisir le parc immobilier : ',
                                            'attr' => array('class' => 'col-xs-3 form-control')))
            ->add('nom')
            ->add('localisation')
            ->add('commentaire')
            ->add('categorieszonestechnique')
            ->add('batiments');

            $formModifier = function (FormInterface $form, Parcsimmobilier $parc = null) {
                $ensembles = null === $parc ? array() : $parc->getEnsembles();

                $form->add('ensembles', 'entity', array(
                                                'class'       => 'EnexgirDatabaseBundle:Ensembles',
                                                'property' => 'nom',
                                                'multiple' => false,
                                                'required' => true,
                                                'mapped' => true,
                                                'empty_value' => '-- sélectionner un ensemble --',
                                                'label'    => 'Choisir l\'ensemble : ',
                                                'query_builder' => function(EntityRepository $er) use ($parc) {
                                                                    return $er->createQueryBuilder('e')
                                                                        ->where("e.parcsimmobilier = :parcsimmobilier_id")
                                                                        ->orderBy('e.nom', 'ASC')
                                                                        ->setParameter(':parcsimmobilier_id', $parc);
                                                                    },
                ));
            };

            $builder->addEventListener(
                FormEvents::PRE_SET_DATA,
                function (FormEvent $event) use ($formModifier) {
                    // this would be your entity
                    $data = $event->getData();

                    $formModifier($event->getForm(), $data->getEnsembles());
                }
            );

            $builder->get('parcsimmobilier')->addEventListener(
                FormEvents::POST_SUBMIT,

这是我使用的控制器方法:

public function addZonesConformitesAction(Request $request) {

        $em=$this->getDoctrine()->getManager();
        $zoneConformite = $em->getRepository('EnexgirDatabaseBundle:Zonestechnique');

        $zoneConformite = new Zonestechnique;
        $form=$this->createForm(new ZonestechniqueType(), $zoneConformite);

        $form->handleRequest($request);

            //instruction if à plusieurs conditions: ici si la method est POST et si le formulaire est valide
            if ($request->isMethod('POST') | ($form->isValid())) {

                    $form->bind($request);
                    $zoneConformite = $form->getData();

                    $em->persist($zoneConformite);
                    $em->flush();

                    return $this->redirect($this->generateUrl('indexRechercheZones'));
                }

            //retourner le formulaire d'ajout si c'est invalide
            else {
                    return $this->render('EnexgirGestionEquipementsTechniquesBundle:ZonesTechnique:ajouterZonesTechniqueConformites.html.twig', array('form' => $form->createView() ));
                }
    }

最后,我的树枝的块内容:

{% block content %}
    <div class="panel-heading">
      <h3 class="panel-title"> Gestion Des Zones techniques -<small>&nbsp;&nbsp;(ajout)</small></h3>
    </div>
    {# Panel Body #}
    <div class="panel-body">
      {# Menu #}
      <div class="panel-body">
        <ul class="nav nav-tabs">
            <li role="presentation">
                <a href="{{ path('indexRechercheZones') }}">Visualisation des Zones techniques</a>
            </li>
          <li role="presentation" class="active">
            <a>Ajouter une Zone technique et ses Conformités</a>
          </li>
        </ul>
      </div>
      {# Formulaire #}
      <div class="page-header">
        <h4><b><u>Ajouter une zone technique et ses conformites</u></b><small>&nbsp;&nbsp;(créer une zone technique qui n'existe pas encore, ainsi que ses conformités respectives)</small></h4>
        <br>
        <form action="{{ path('ajouterZonesConformites_process') }}" method="POST" {{ form_enctype(form) }}>
          <div>
            {{ form_start(form) }}
              {{ form_row(form.parcsimmobilier) }}    {# <select id="meetup_sport" ... #}
              {{ form_row(form.ensembles) }} {# <select id="meetup_position" ... #}
            {{ form_end(form) }}
          {# validation #}
            <input type="submit" value="Ajouter" class="btn btn-success"/>
          </div>
          <br>
        </form>
      </div>
    </div>
  {% endblock %}

目前,我还没有在我的树枝中引入 Ajax 代码,因为我有这个错误

试图在类上调用方法“getEnsembles” “Enexgir\DatabaseBundle\Entity\Zonestechnique”在 C:\wamp\www\MyPathToMyProject\src\Enexgir\DatabaseBundle\Form\ZonestechniqueType.php 第 65 行。

这是第 65 行的代码:

$formModifier($event-&gt;getForm(), $data-&gt;getEnsembles());

我了解Ensembles.phpParcsimmobilier.phpZonestechnique.php 没有任何关系,但我遵循文档,但我并不真正了解它是如何工作的。有人可以帮我理解和制作这个表格吗?

提前谢谢你。

【问题讨论】:

  • 考虑使用不那么粗体的格式并将代码缩小到相应的行,这真是一团糟......
  • 当用 var_dump() 转储 $data 时,你得到了什么?您是否还省略了实体的 getter/setter?

标签: php ajax forms symfony addeventlistener


【解决方案1】:

@Chausser 提出了一个很好的观点,因为在$formModifier($event-&gt;getForm(), $data-&gt;getEnsembles()); 部分的代码中,您传递了Ensembles 的一个实例,因此不需要再次调用$data-&gt;getEnsembles()。 希望对你有帮助

【讨论】:

    【解决方案2】:

    symfony 表单事件系统当然可以使用一些精简。话虽如此,这是可以实现的。对于将出现的每个下拉菜单,您将需要 2 个表单事件(PRE_SET_DATA/POST_SUBMIT)。您应该能够将所有 PRE_SET_DATA 事件合并到 1 个函数中,但您必须在单独的函数中处理 POST_SUBMIT 事件,因为它们绑定到表单

    您需要将 if 语句更改为:

    if($request->isMethod('POST') && !$request->isXmlHttpRequest() && $form->isValid())
    

    你也不需要打电话:

    $form->bind($request);
    

    如果你已经打过电话:

    $form->handleRequest($request);
    

    后者是前者的替代品。

    通过仅“处理”非 AJAX 请求的表单,这将允许您的表单获取更新的数据并触发表单事件并返回它。

    【讨论】:

    • 如果我真的明白:在您的回答中,您建议我将所有数据仅调用一个PRE_SET_DATA,然后在单独的函数中为每个数据使用POST_SUBMIT?正如您在我的问题中看到的那样,我有这个错误:尝试在 C:\wamp\www\MyPathToMyProject\src\Enexgir\DatabaseBundle\ 类“En​​exgir\DatabaseBundle\Entity\Zonestechnique”上调用方法“getEnsembles” Form\ZonestechniqueType.php 第 65 行。 这意味着我还没有管理如何继续以获得一个事件,这里是 ensembles 下拉列表
    • 在你当前的 PRE_SET_DATA 事件中将 $formModifier($event-&gt;getForm(), $data-&gt;getEnsembles()); 更改为 $formModifier($event-&gt;getForm(), $data); 然后在函数处理程序中进行事件检查 if($data-&gt;getEnsembles()) 然后添加该字段,否则什么也不做
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-02
    • 2012-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多