Home > OS >  POST request with value FALSE turns to TRUE in db
POST request with value FALSE turns to TRUE in db

Time:11-30

Good mornings all, I make a POST request with the Type field (tinyint) in my unit tests. I give it the value FALSE. When I check in the database, the Type field is 1 so TRUE. I don't know how this is possible and it happens to me several times on my unit tests.

The POST request with the column type :

 "title" => "Une fausse formation"
  "number" => "faux-numer0"
  "organism" => "Un faux organisme"
  "type" => false
  "status" => 0
  "costs" => array:2 [
    0 => array:4 [
      "title" => "Frais pédagogiques"
      "type" => 0
      "amount" => 102.5
      "isCollective" => true
    ]
    1 => array:4 [
      "title" => "Frais de transport"
      "type" => 0
      "amount" => 10
      "isCollective" => true
    ]
  ]
  "sessions" => []
  "visibility" => 2
]

the row that was inserted into the table :

 "title" => "Une fausse formation"
  "number" => "faux-numer0"
  "type" => true
  "status" => 0
  "organism" => "Un faux organisme"
  "visibility" => array:2 [
    "establishment" => []
    "employees" => array:1 [
      0 => []
    ]
  ]
  "costs" => array:2 [
    0 => array:4 [
      "title" => "Frais pédagogiques"
      "type" => 0
      "amount" => "102.50"
      "is_collective" => true
    ]
    1 => array:4 [
      "title" => "Frais de transport"
      "type" => 0
      "amount" => "10.00"
      "is_collective" => true
    ]
  ]
]

Here is my field declaration in the Entity:

/**
 * @var bool
 *
 * @ORM\Column(name="`type`", type="boolean")
 * @Serializer\Groups({"get_employee", "get_training", "get_trainings", "get_training_user", "get_training_session"})
 */
private $type;

This is my POST TEST request :

 public function testPostTraining($user, $data, $result)
    {
               
        $this->authUser($user[0], $user[1], $user[2]);

        // Retrieve created visibility id
        $visibilityData = array(
            'establishment' => 1
        );
        $this->apiCall('POST', '/api/secure/trainings/visibilities.json', $visibilityData);
        // Check status code (visibility created)
        $this->assertEquals(201, $this->client->getResponse()->getStatusCode());
        $data['visibility'] = json_decode($this->client->getResponse()->getContent(), true)['id'];
        $this->apiCall('POST', '/api/secure/trainings.json', $data);

       // Check status code (created)
        $this->assertEquals(201, $this->client->getResponse()->getStatusCode());
        // Check if id is returned
        $response = json_decode($this->client->getResponse()->getContent(), true);
        
        $this->assertArrayHasKey('id', $response);
        //$this->assertInternalType('integer', $response['id']);
        $this->assertEquals('integer', gettype($response['id']));
        
        // Check data
        $this->apiCall('GET', '/api/secure/trainings/'.$response['id'].'.json');
        $training = json_decode($this->client->getResponse()->getContent(), true);
        // Remove ids
        $this->recursive_unset($training, 'id');
        $this->recursive_unset($training, 'created_at');
        $this->recursive_unset($training, 'updated_at');
        $this->recursive_unset($training['visibility']['establishment'], 'roles');

        // Check content
        $this->assertEquals($training, $result);
    }

The data of the post request :

$data_two= array(
    'title'             =>  'Une vrai formation',
    'number'            =>  'vrai-numer0',
    'organism'          =>  'Un vrai organisme',
    'type'              =>  false,
    'status'            =>  1,
    'costs'             =>  array(
        array(
            'title'     =>  'Frais pédagogiques',
            'type'      =>  1,
            'amount'    =>  10.25,
            'isCollective' => true
        ),
    ),
    'sessions'          =>  array()
);

This is the POST controller :

   public function postAction(Request $request)
    {
        try {
            if (($employee = $this->getEmployee()) == null)
                return FOSView::create(null, Response::HTTP_FORBIDDEN);

            $manager = $this->getTrainingManager();
            $training = $manager->createTraining();
            $form = $this->createForm(TrainingType::class, $training, array(
                'method' => $request->getMethod()
            ));
            $this->removeExtraFields($request, $form);
            $form->handleRequest($request);

            if ($form->isSubmitted() && $form->isValid()) {
                $this->denyAccessUnlessGranted('create', $training);
                $manager->save($training);

                $dispatcher = $this->eventDisptacher;
                $event = new TrainingActionEvent($training, $this->getEmployee(), $request->getMethod());
                $dispatcher->dispatch($event,TrainingActionEvent::TRAINING_ACTION);

                return $training;
            }
        } catch(\Exception $e) {
            return FOSView::create($e->getMessage(), Response::HTTP_INTERNAL_SERVER_ERROR);
        }

        return FOSView::create($form, Response::HTTP_BAD_REQUEST);
    }

CodePudding user response:

I assume you are using CheckboxType for the boolean field in your form definition. If you take a look at the class, you can see that a BooleanToStringTransformer is used to convert the submitted value to a real boolean. Only the configured value (default: '1') is converted to true, and the configured false_values (default: [null]) are converted to false.

Going through the documentation in the FOSRestBundle, this issue has been resolved already: https://github.com/FriendsOfSymfony/FOSRestBundle/pull/883

See: https://fosrestbundle.readthedocs.io/en/3.x/body_listener.html#decoders

If you want to be able to use a checkbox within a form and have true and false values (without any issue) you have to use: fos_rest.decoder.jsontoform

CodePudding user response:

I finally found the solution. The POST requests in my unit tests were incorrectly formatted.

Before :

private function apiCall($method, $endpoint, $parameters=array())
{

$this->client->request($method, $endpoint, $parameters);
return json_decode($this->client->getResponse()->getContent(), true);

}

After :

private function apiPostCall($method, $endpoint, $parameters=array())
    {           
            $this->client->request(
                $method,
                $endpoint,
                [],
                [],
                ['CONTENT_TYPE' => 'application/json'],
                json_encode($parameters)
            );    
    return json_decode($this->client->getResponse()->getContent(),true);
    }
  • Related