Symfony:继承类的表单

3

我正在尝试使用Symfony(2.8.6)中的继承类类型处理表单。

下面是我的一个非常简单的例子,虽然其中存在问题,但只是为了说明我的问题。

  1. 我应该如何提供只有一个表单来从控制器传递到Twig模板,以便有一个选择“类型”(鉴别器)的字段?我应该简单地创建另一个变量,例如“type”,在每个类中硬编码吗?
  2. 一旦提交了表单,如何在控制器中确定应该使用哪个类,在“新建”或“编辑”操作中?我已经尝试从ParameterBag中获取它,创建一个合适的实体和表单,然后使用$ form->handleRequest($request); …但当其他类型可能拥有额外字段时,似乎不起作用。

如果有人能指向 Github 存储库或其他展示此类情况发生的内容,我会非常感激。感谢你的时间。

如果这些是我的类:

 /**
 * @ORM\Entity
 * @ORM\InheritanceType("SINGLE_TABLE")
 * @ORM\DiscriminatorColumn(name="discr", type="string")
 * @ORM\DiscriminatorMap("truck" = "Truck", "Car" = "Car", "suv" = "SUV")
 */
abstract class Vechicle {
    private $make;
    private $model;
    private $numberOfDoors;

    // getters and setters //
}

class Truck extends Vehicle {
    private $offRoadPackage;
    private $bedSize;

    // getters and setters //
}

class Car extends Vehicle {
    private $bodyType;
}

class SUV extends Vehicle {
    // no additional fields //
}

那么这些可能是我的表单类型:

class VehicleType extends AbstractType {
    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder
            ->add('make')
            ->add('model')
            ->add('numberOfDoors');
    }

    public function configureOptions(OptionsResolver $resolver) {
        $resolver->setDefaults(array(
            'data_class' => 'MyBundle\Entity\Vehicle'
        ));
    }
}

class TruckType extends VehicleType {
    public function buildForm(FormBuilderInterface $builder, array $options) {
        parent::buildForm($builder, $options);
        $builder
            ->add('offRoadPackage')
            ->add('bedSize');
    }

    public function configureOptions(OptionsResolver $resolver) {
        $resolver->setDefaults(array(
            'data_class' => 'MyBundle\Entity\Truck'
        ));
    }
}

class CarType extends VehicleType {
    public function buildForm(FormBuilderInterface $builder, array $options) {
        parent::buildForm($builder, $options);
        $builder
            ->add('bodyType')
    }

    public function configureOptions(OptionsResolver $resolver) {
        $resolver->setDefaults(array(
            'data_class' => 'MyBundle\Entity\Car'
        ));
    }
}

class SUVType extends VehicleType {
    public function buildForm(FormBuilderInterface $builder, array $options) {
        parent::buildForm($builder, $options);
    }

    public function configureOptions(OptionsResolver $resolver) {
        $resolver->setDefaults(array(
            'data_class' => 'MyBundle\Entity\SUV'
        ));
    }
}
1个回答

4
这可能有点长,但请耐心看完。这个想法的要点是将表单处理为数组。您创建一个类型列表,然后迭代该列表以构建实际的表单对象。这样,如果您希望添加更多表单,唯一需要编辑的就是表单类型列表。
在模板中,您可以迭代所有表单以呈现它们,并将它们包装在一个您可以隐藏的div中。接下来,您可以添加一个选择元素,该元素控制一个javascript代码块,用于显示/隐藏用户所选类型的表单。
提交后,您可以测试操作是否已经进行了POST,并重新迭代表单以检查它们中的哪个已被提交并适当地处理它。
下面是一个粗略的未经测试代码片段:
控制器/操作:

class SomeController
{
    public function addAction()
    {
        $types = [
            'Form1' => Form1::class,
            'Form2' => Form2::class,
            'Form3' => Form3::class,
        ];

        // create the forms based on the types indicated in the types arary
        $forms = [];
        foreach ($types as $type) {
            $forms[] = $this->createForm($type);
        }

        if ($request->isMethod('POST')) {
            foreach ($forms as $form) {
                $form->handleRequest($request);

                if (!$form->isSubmitted()) continue; // no need to validate a form that isn't submitted

                if ($form->isValid()) {
                    // handle the form of your type

                    break; // stop processing as we found the form we have to deal with
                } 
            }
        }

        $views = [];
        foreach ($forms as $form) {
            $views = $form->createView();
        }

        $this->render('template.html.twig', ['forms' => $views, 'types' => $types]);
    }

}

The template:

<select id="types">
    {% for type in types|keys %}
        <option value="vehicle_type_{{ loop.index }}">{{ type }}</option>
    {% endfor %}
</select>
{% for form in forms %}
    <div class="form hidden" id="vehicle_type_{{ loop.index }}">
        {{ form_start(form) }}
        {{ form_widget(form) }}
        {{ form_end(form) }}
    </div>
{% endfor %}

And finally the piece of javascript controlling what form is shown/hidden:

<script>
    // On select change hide all forms except for the on that was just selected
    $('#types').on('change', function () {
        $('.form').addClass('hidden');
        $('#' + $(this).val()).removeClass('hidden');
    });
</script>


太棒了!我按照你的指导成功地解决了问题。谢谢! - Telexen
没问题,很高兴能帮到你 :) @Telexen - Berry Ligtermoet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接