3

I have a strange problem with Symfony (v 2.3.2) form. It's very simple form without relations. I should also noted that this form is used in REST API only.

So I have a published field (boolean). On the entity it's set to false by default.

On update, the REST API client sends PUT request which is correct aka ...&[entity]published=0&.... This value is also shown in Symfony profiler in the form parameters.

However I've noticed that the actual value in database is set to true (or 1 as it's tinyint).

So, to find out what's the problem, I added throw statement after $form->submit($request);

throw new \Exception(sprintf('Request: %s, form: %s', $request->get('entity')['published'], $form->get('published')->getData()));

or

throw new \Exception(sprintf('Request: %s, form: %s', $request->get('entity')['published'], $form->getData()->getPublished()));

The exception message says: Request: 0, form: 1. It means that somewhere in submit method the string value '0' is converted to 1.

The field is constructed with $builder->add('published', 'checkbox', [ 'required' => false ])

Also I've noticed strange thing, which may be related. On the Symfony profiler, panel request, I'm getting error: Warning: json_encode(): Invalid UTF-8 sequence in classes.php line 3758, I'm not sending any strange characters - just word "test".

3 Answers 3

5

You shouldn't use a checkbox form type in your API, 0 doesn't mean false.

You should implement a new boolean form type which transform 1, '1' and true to true, and everything else to false (for example).

Here is an example: https://gist.github.com/fsevestre/abfefe0b66e5f5b24c60

Sign up to request clarification or add additional context in comments.

Comments

2

Further investigation revealed that typical HTML form checkbox is only sent to server when it's checked. So I presume that sending value set to 0|false|off would make it work as if it would be set to true.

Therefore, if you set your form widget to type checkbox, do not send checkbox in your request if you want it to be set to false. In my case it would look like this:

Array
(
    [entity] => Array
    (
        [id] => 73
        [_token] => d63dad39ea458f7d3c7ae5dbea10c325cb9ee93d
    )
)

otherwise send anything, 0, false, off will work too

Array
(
    [entity] => Array
    (
        [id] => 73
        [published] => 1|0|false|on|off
        [_token] => d63dad39ea458f7d3c7ae5dbea10c325cb9ee93d
    )
)

Comments

0

When using PUT this happened to be a bit problematic... I solved it by adding a subscriber to all of my forms that solve this issue(this code is also solving the issue of using PUT without filling all the data):

class RestFormSubscriber implements EventSubscriberInterface {

    /**
     * {@inheritdoc}
     */
    public static function getSubscribedEvents()
    {
        return array(FormEvents::PRE_SUBMIT => "preSubmit");
    }

    /**
     * Remove null fields on update
     * Fixes boolean value
     * @param FormEvent $event
     */
    public function preSubmit(FormEvent $event)
    {
        $form = $event->getForm();
        $data = $event->getData();

        $isPUT = strtoupper($form->getConfig()->getMethod()) == "PUT";

        $accessor = PropertyAccess::createPropertyAccessor();
        foreach ($form->all() as $name => $child) {
            if ($isPUT && !isset($data[$name])) {
                $form->remove($name);
                continue;
            }
            if(is_bool($accessor->getValue($form->getData(), $name))) {
                $val = $data[$name];
                $data[$name] = ($val=="true")||($val=="1")||($val=="on");
            }
        }
        $event->setData($data);
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.