Ali Bahsisoglu
Ali Bahsisoglu

Reputation: 83

Symfony2 Update Specific Field in Form Collection

I have an interesting problem. I couldn't find any solution in stackoverflow and also google. I have an Entity User and User have some metas. So I created a UserMeta Entity and also UserMetaValue. In user form there is lots of tabs. And I used these metas in the tabs. Some of them in first tabs, some of them in other tabs. And all tabs have their own form. When I bind a form on active tab, active tab metas update, others changed to NULL.

StudentPersonalType.php

namespace ATL\UserBundle\Form\Type;

use ATL\CommonBundle\Utils\Shortcut;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\FormBuilderInterface;

class StudentPersonalType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options){
        $builder->add("first_name", null, array(
                "label" => "İsim",
                "required" => true,
                "attr" => array(
                    "class" => "span10"
                )
            ))->add("last_name", null, array(
                "label" => "Soyisim",
                "required" => true,
                "attr" => array(
                    "class" => "span10"
                )
            ))->add("username", null, array(
                "label" => "Öğrenci Numarası",
                "required" => true,
                "attr" => array(
                    "class" => "span10"
                )
            ))->add("email", null, array(
                "label" => "Email",
                "required" => true,
                "attr" => array(
                    "class" => "span10"
                )
            ))->add('metas', 'collection', array(
                'label' => "Metas",
                'type' => new UserMetaType()
            ));
    }

    public function getName(){
        return "personal";
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver){
        $resolver->setDefaults(array(
            "data_class" => "ATL\UserBundle\Entity\User"
        ));
    }
}

StudentEducationType.php

namespace ATL\UserBundle\Form\Type;

use ATL\CommonBundle\Utils\Shortcut;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\FormBuilderInterface;

class StudentEducationType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options){
        $builder->add('metas', 'collection', array(
                'label' => "Metas",
                'type' => new UserMetaType(),
                'by_reference' => false
            ));
    }

    public function getName(){
        return "education";
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver){
        $resolver->setDefaults(array(
            "data_class" => "ATL\UserBundle\Entity\User"
        ));
    }
}

And twig

    <div id="personal-info" class="tab-pane row-fluid active">
       <form style="margin:20px 0 0 0;" class="ajaxForm form-horizontal form-row-seperated" action="{{ formAction }}">
            {{ form_row(form.first_name) }}
            {{ form_row(form.last_name) }}
            {{ form_row(form.email) }}
            {{ form_row(form.username) }}
            {% for meta in form.metas %}
                {% if meta.value.vars.label in formValues.personal %}
                    {{ form_widget(meta) }}
                {% endif %}
            {% endfor %}
            {{ form_row(form._token) }}
            <div class="form-actions" style="margin-bottom:0;">
                <button class="btn blue" type="submit"><i class="icon-ok"></i> Kaydet</button>
            </div>
        </form>
    </div>
    <div id="education-info" class="tab-pane row-fluid">
        <form style="margin:20px 0 0 0;" class="ajaxForm form-horizontal form-row-seperated" action="{{ formAction }}">
            {% for meta in educationForm.metas %}
                {% if meta.value.vars.label in formValues.education %}
                    {{ form_widget(meta) }}
                {% endif %}
            {% endfor %}
            {{ form_row(educationForm._token) }}
            <div class="form-actions" style="margin-bottom:0;">
                <button class="btn blue" type="submit"><i class="icon-ok"></i> Kaydet</button>
            </div>
        </form>
    </div>

I filter collection fields by check it in twig file with IF statement.

I ask my question again, How could I use metas in different form in same page without affecting the others?

Upvotes: 1

Views: 2261

Answers (1)

Ryan
Ryan

Reputation: 5026

You have done half the job of filtering out the irrelevant fields for rendering. But you also need to filter out the irrelevant fields for form binding.

When you bind the request to the form it is expecting values for every UserMeta entity because there is a field for all of them in the UserMetaType collection. You'll need to remove all the UserMetaType forms which don't correspond to one of your submitted values. It's probably best to this with a FormEvents::PRE_BIND listener.

You can see a simpler example of this at Form: Avoid setting null to non submitted field. It will be slightly more complex for you, because you'll have to iterate through the collection of UserMetaType forms and remove the ones which you don't want bound.

Upvotes: 1

Related Questions