StPiere
StPiere

Reputation: 4263

Symfony2 dynamic form generation

I have mysql 2 tables: user_profile_field and user_profile_data with following columns:

user_profile_field:

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

user_profile_data:

-id (integer)
-user_id (integer)
-field_id (integer) references user_profile_field(id)
-data (string)

I also have defined 2 Doctrine entities that map this relation. I need dynamicaly to create a form for updating user_profile_data. The form input type for each row of user_profile_field depends on user_profile_field:category column (3 possible values correspond to different input types: text, textarea and choice field) ...

Im not sure how to create the form and form type entity via 'Symfony2' way ?

Any help or suggestion appreciated ...

Upvotes: 3

Views: 7919

Answers (2)

Iain
Iain

Reputation: 2177

An earlier solution I've used was to pass an array defining the form's configuration to the form type's constructor method and build these form fields during the buildForm method.

I don't know how you've set up your users so there will be some blanks that you need to fill in.

As a start I think this would happen in the controller but a better way would be to move as much logic to a Form Handler like the FOS User Bundle does: https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Form/Handler/RegistrationFormHandler.php

You will need to get all of your user profile fields and prepare them in an array ready to be added to the form type constructor (see example for 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;

Then you need to create an array representation of your User based on the user_profile_data you've collected. This data is then bound to the form later on.

I'm not sure if you can pass this array version straight to the form. If the form is expecting an Entity you may need to pass the base user entity to the form first then bind the array version (containing the dynamic data) afterwards to set the dynamic field values.

Here's the Profile form class that you'll use:

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

    }

This covers the output of the form.

In the controller create the form.

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

In summary the controller method should be structured something like this (filling in the blanks):

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

I do feel that the Form Events are probably a better Symfony2 approach but this may hopefully help you get started. Then you can consider Form Events during the refactoring phase.

Upvotes: 7

Iain
Iain

Reputation: 2177

The Symfony 2 user documentation suggests the use of form events to generate a dynamic form: http://symfony.com/doc/current/cookbook/form/dynamic_form_generation.html

Upvotes: 3

Related Questions