Search code examples
symfonysymfony4fosrestbundle

Symfony + FOSRestBundle - How to allow NULL value to a field configured with a custom form type?


I have a simple Symfony API which uses FOSRestBundle. I have an Exercise entity which contains a field sentences. This field is of type json @ORM\Column(type="json") and is stuffed with some nested json. The entity is persisted in a MySQL database.

I use Symfony forms to validate incoming data from a SPA. Here's the data the SPA sends on the endpoint /exercise:

{
    "name": "HEP9H",
    "sentences": [
        {
            "name": "Sentence",
            "tirettes": [
                {
                    "chain": null
                },
                {
                    "chain": {
                        "name": "Chain 1"
                    }
                }
            ]
        }
    ]
}

Once persisted, the API then returns the entity as JSON. It should look exactly the same, except that it has an ID. The issue is that I get this piece of JSON in return:

{
  "id": 21,
  "name": "HEP9H",
  "sentences": [
    {
      "name":  "Sentence",
      "tirettes": [
        {
          "chain": {
            "name": null
          }
        },
        {
          "chain": {
            "name": "Chaîne 1"
          }
        }
      ]
    }
  ]
}

As you can see, the problem is that my property "chain": null becomes "chain": {"name": null}. I guess this is due to a bad form type configuration. The data structure changes right after I validate my form and before I persist the entity for the first time.

Here's TiretteType:

class TiretteType extends AbstractType {

    public function buildForm ( FormBuilderInterface $builder, array $options ) {
        $builder
            ->add ( 'chain', ChainType::class, [
                "required" => false
            ] );
    }
}

And here's ChainType:

class ChainType extends AbstractType {

    public function buildForm ( FormBuilderInterface $builder, array $options ) {
        $builder->add ( 'name', TextType::class );
    }
}

I have no underlying data class and no underlying entity (except the root entity Exercise).

What I've tried so far:

  • adding "required" => false to the 'chain' field, it doesn't change anything
  • setting "empty_data" => NULL to the 'chain' field, this also doesn't work and overrides any data to NULL

Am I completely missing something?

Thanks!


Solution

  • I found the answer to my issue. Since my field chain had no underlying data class, the form would simply give me an array with default values if it had a null value as input.

    The solution is to use a data transformer (https://symfony.com/doc/current/form/data_transformers.html). I had to check for such an empty structure and if found, return back null instead of the given value.

    $builder->get ( 'chain' )->addModelTransformer ( new CallbackTransformer(
        function ( $originalInput ) {
            return $originalInput;
        },
        function ( $submittedValue ) {
            return $submittedValue["name"] === null ? $submittedValue : null;
        }
    ) );
    

    I don't think checking for null properties is the cleanest way to do this but my case is very simple so I won't spend more time on this one.

    Hope this helps someone.