BartBiczBoży
BartBiczBoży

Reputation: 2672

How to process nested json with FOSRestBundle and symfony forms

By nested json I mean something that keeps address data in its own "address" array:

{
  "user": {
    "id": 999,
    "username": "xxxx",
    "email": "[email protected]",
    "address": {
      "street": "13th avenue",
      "place": 12
    }
  }
}

instead of flat one

{
  "user": {
    "id": 999,
    "username": "xxxx",
    "email": "[email protected]",
    "street": "13th avenue",
    "place": 12
  }
}

Flat one is processed fine there using User entity and it's properties: "id", "username" and "email". It is nicely validated using symfony form feature:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('username');
    $builder->add('email', 'email');
    $builder->add('password', 'password');
    $builder->add('street');
    $builder->add('place');
}

I want to have both "street" and "place" as properties in User entity, to store it all in one user table in the database, using doctrine. But the json I get comes from third party, so I can not modify it.

Is there any way of constructing the form so it can validate the json with "address" field correctly, still being able to keep all the user data in one table?

Upvotes: 4

Views: 1187

Answers (1)

Igor Pantović
Igor Pantović

Reputation: 9246

This is a pretty good question. One solution that comes to mind is making an unmapped form and binding data manually using a form event, for example:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    // Make a "nested" address form to resemble JSON structure
    $addressBuilder = $builder->create('address', 'form')
        ->add('place')
        ->add('street');

    $builder->add('username');
    $builder->add('email', 'email');
    $builder->add('password', 'password');
    // add that subform to main form, and make it unmapped
    // this will tell symfony not to bind any data to user object
    $builder->add($addressBuilder, null, ['mapped' => false]);

    // Once form is submitted, get data from address form
    // and set it on user object manually
    $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
        $user = $event->getData();
        $addressData = $event->getForm()->get('address')->getData();

        $user->setStreet($addressData['street']);
        $user->setPlace($addressData['place']);
    })
}

Upvotes: 3

Related Questions