Symfony:具有继承类的表单

时间:2016-05-27 16:56:16

标签: php symfony discriminator

我试图弄清楚在使用Symfony(2.8.6)的继承类类型时如何处理表单。

我创建了一个[非常]简单的示例,说明了我在下面尝试做的事情。它有问题,但它只是为了说明我的问题。

  1. 我如何只提供从控制器到树枝模板的一个表单,以便有一个字段可以选择" type" (鉴别师)应该使用?我应该简单地创建另一个变量,例如" type"在每个班级都是硬编码的?
  2. 提交表单后,如何在" new"中找出应该在控制器中使用哪个类?或"编辑"行动?我尝试将其从ParameterBag中删除,创建一个合适的实体和表单,然后使用$ form-> handleRequest($ request); ...但是当有额外的字段可能属于另一种类型时,它似乎不起作用。
  3. 如果有人甚至可以指向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 个答案:

答案 0 :(得分:2)

这将是一个漫长的一个但是忍受我。这个想法的要点是你在一个数组中处理你的表单。您可以创建一个类型列表,您可以迭代这些类型来构建实际的表单对象。这样,如果您想添加更多内容,您编辑的唯一内容就是表单类型列表。

在模板中,您遍历所有表单以呈现它们并将它们包装在您可以隐藏的div中。接下来,您可以添加一个select元素来控制显示/隐藏用户所选类型的表单的javascript。

在sbumission之后,您可以测试该动作是否已被张贴并重复表格以检查其中哪一个已被提交并正确处理。

以下是粗略的未经测试的代码段:

控制器/动作:

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]);
    }

}

模板:

<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 %}

最后,javascript控制显示/隐藏的形式:

<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>