Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic form (switch entity) symfony2

I'm making a page for adverts. An advert can be of different types and therefore have different data. For instance, a vehicle would have the make and the model as extra data.

Right now, I've got one base doctrine entity Advert which contains the data that every advert requires. Different adverts in turn innherits this data (doctrine2 discriminatormap)

I need to populate the form dynamically (with ajax and symfony2 forms) if the user choose to create a vehicle ad I want to display the options for a vehicle advert. But I also need to change the entity to be of the form AdvertVehicle.

Is this possible? I did read the cookbook entry at the symfony2 homepage

"How to Dynamically Modify Forms Using Form Events": This should be handled by making an AJAX call back to your application. In that controller, you can submit your form, but instead of processing it, simply use the submitted form to render the updated fields. The response from the AJAX call can then be used to update the view.

I understand how to make an ajax call back to my controller, and i understand how to use the form-events but how do I get the response of a rendered select-box (containing vehicle models for instance) back? With a new AbstractType? or formbuilder?

And then when the user actually submits the form I need to use the entity of the selected advert type. Can I change the entity according to the users choice in the form dynamically?

Edit I checked the form innheritance out that's great, thank you. I extend the AdvertType and override the buildForm() method and before I add the items I need for the AdvertVehicleType I call the parent method.

Futher Explanation Every advert entity contains price, description, title and category. Some adverts contains more, such as make and model. They are differentiated by the discriminatormap (doctrine2)

Example:

// -- Entity
class CarAdvert extends Advert {

    protected $model;
    protected $make;

}

// -- Entity
// -- This uses discriminator mapping
class Advert {
    protected $title;
    protected $description;
    protected $price;
    protected $category;
}

if the user selects the category cars I want to use the CarAdvert entity (for validation and persistance) if the user selects the house hold itemcategory I just want to use the normal Advert entity.

One major problem is still that I cannot figure out how to render the extended form via ajax. Any tips on this part? When the user selects car as a category, I want the form to be updated (via jQuery/ajax) but how do I make a controller that retrieves just the extended part of the form and sends the html back as a response (without using twig and rendering it in a view, is this possible)?

Solution:

See answer below!

like image 962
Asbestos Avatar asked Oct 28 '13 07:10

Asbestos


1 Answers

Solution:

The solution to my problem was to create a few extra functions in the controller to solve the issue where I want to be able to change the entity and form "on the fly" from a selection by the user..

public function indexAction(Request $request)
{
    $form = $this->getForm($request);
    $form->handleRequest($request);

    return array(
           'form' => $form->createView(),
           'request' => $request->request,
    );
}

Where getForm retrieves the form, (e.g AdvertVehicleType for vehicles or AdvertType for a "default" advert).

The getForm method looks like this:

 private function getForm(Request $request)
{
    $categoryTitle = 'NONE';
    $categoryId = $request->request->get('advert', false)['category'];

    if ($categoryId) {
        $categoryTitle = $this->getDoctrine()->getRepository('Bundle:Category')->find($categoryId)->getTitle();
    }

    return $this->createForm($this->getFormType($categoryTitle), $this->getEntity($categoryTitle));

}

here I retrieve the categoryID (that is selected in the form in the request) and retreives the formType with getFormTypeand the entity with getEntity.

private function getEntity($categoryTitle)
{
    $entity = new Advert();
    switch ($categoryTitle) {
        case Category::CARS:
            $entity = new AdvertCar();
    }

    return $entity;
}

private function getFormType($categoryTitle)
{
    switch ($categoryTitle) {
        case Category::CARS:
            return new AdvertCarType();
        default:
            return new AdvertType();
    }
}

To be able to update this "on the fly" with ajax (but it also works if the user tries to submit the form) I created another action in the controller.

This action renders the parts of the form that I want to update (on ajax call), I do this by actually picking out what I don't need in the form with twig setting the form objects to rendered like so:

{% do form.title.setRendered %}

(this is just an example I actually do this for all the form objects that I don't want to render.

I then simply just call:

{{ form_rest(form) }}

which will retrieve the "rest" of the form which is different for different categories.

Now let's say you have state and than town to select. First select the state then you render the towns for that state in twig (but then you can actually just render the part you need, e.g {{ form_row(form.towns) }} and you return this rendered template as a json-response and just put it in the div you want with jquery.

$html = $this->renderView('@Bundle/NewAddPage/filter_area.twig', array('form' => $form->createView()));

and then returning the $html variable in the response.

I hope this helps, and that the explanation is good enough, if not just make a comment and I'll update this with my answer!

like image 97
Asbestos Avatar answered Nov 01 '22 13:11

Asbestos