Symfony2 动态表单生成

3

我有两个MySQL表格:user_profile_fielduser_profile_data,它们具有以下列:

user_profile_field:

-id (integer)
-field (string)
-category(string) 

用户资料数据:
-id (integer)
-user_id (integer)
-field_id (integer) references user_profile_field(id)
-data (string)

我还定义了2个Doctrine实体来映射这个关系。我需要动态创建一个更新user_profile_data的表单。每行user_profile_field的表单输入类型取决于user_profile_field:category列(3个可能的值对应不同的输入类型:文本、文本区域和选择字段)...
我不确定如何通过'Symfony2'方式创建表单和表单类型实体?
任何帮助或建议都将不胜感激...
2个回答

7
我以前使用的解决方案是将定义表格配置的数组传递给表单类型的构造方法,并在buildForm方法中构建这些表单字段。
我不知道您如何设置用户,因此有一些空白需要填写。
首先,我认为这将在控制器中发生,但更好的方法是将尽可能多的逻辑移动到类似于FOS用户包的表单处理程序中:https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Form/Handler/RegistrationFormHandler.php 您需要获取所有用户配置文件字段并准备好添加到表单类型构造函数中的数组(请参见ProfileType的示例)。
$form_config = array(
    'fields' => array()
);

// get all user_profile_field entities add them to $form_config['fields']
// foreach $user_profile_fields as $user_profile_field...
// $form_config['fields'][] = $user_profile_field;

然后,您需要根据已收集的用户资料创建一个基于User的数组表示。稍后将使用此数据绑定到表单。

我不确定您是否可以直接将此数组版本传递给表单。如果表单期望实体,则可能需要先将基本用户实体传递给表单,然后再绑定包含动态数据的数组版本(以设置动态字段值)。

这是您将要使用的Profile表单类:

class ProfileType extends AbstractType
{
    // stores the forms configuration
    // preferably map defaults here or in a getDefaultConfig method
    private $formConfig = array();

    // new constructor method to accept a form configuration
    public function __construct($form_config = array())
    {
        // merge the incoming config with the defaults
        // set the merged array to $this->formConfig
        $this->formConfig = $form_config;
    }

    public function buildForm(FormBuilder $builder, array $options)
    {
        // add any compulsory member fields here 
        // $builder->add( ... );

        // iterate over the form fields that were passed to the constructor
        // assuming that fields are an array of user_profile_field entities
        foreach ($this->formConfig['fields'] as $field) {
            // as form is not a straight entity form we need to set this
            // otherwise validation might have problems
            $options = array('property_path' => false);
            // if its a choice fields add some extra settings to the $options

            $builder->add($field->getField(), $field->getCategory(), $options);
        }

    }

这涵盖了表单的输出。

在控制器中创建表单。

$profileForm = $this->createForm(new ProfileType($form_config), $user);

总之,控制器方法的结构应该像这样(填写空白部分):

// get the user
// get user data
// create array version of user with its data as a copy

// get profile fields
// add them to the form config
// create form and pass form config to constructor and the user entity to createForm
// bind the array version of user data to form to fill in dynamic field's values


// check if form is valid
// do what is needed to set the posted form data to the user's data
// update user and redirect

我认为表单事件可能是Symfony2的更好方法,但这可能会帮助您入门。然后在重构阶段可以考虑使用表单事件。


1
你好Lain,非常感谢您提供的好例子!!我会尝试这种方法...希望我能做对:)..谢谢! - StPiere

3

这种方法唯一的问题是,由于某些原因(我不知道为什么),您必须使用表单工厂而不是表单构建器。这使得添加成员有点困难(例如,您失去了类型猜测)。我仍在尝试找到一种使用构建器和表单事件的方法。 - Jens
我理解在表单生成期间使用事件的好处,但似乎为了简单地绘制某些字段而涉及了过多的复杂性。 - Pierre de LESPINAY

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