Update one/few fields with patch action ?
I have made a PatchAction without using forms and I am trying to ignore null/default value
Currently my action look like this
/*
* @ParamConverter("updatedServer", converter="fos_rest.request_body")
*
* @return View
*/
public function patchAction(Server $server, Server $updatedServer, ConstraintViolationListInterface $validationErrors)
{
if ($validationErrors->count() > 0) {
return $this->handleBodyValidationErrorsView($validationErrors);
}
$server->setAlias($updatedServer->getAlias())
->setMac($updatedServer->getMac())
->setSshUser($updatedServer->getSshUser())
->setSshPort($updatedServer->getSshPort())
->setIpmiAddress($updatedServer->getIpmiAddress())
->setIpmiLogin($updatedServer->getIpmiLogin())
->setIpmiPassword($updatedServer->getIpmiPassword())
->setMysqlHost($updatedServer->getMysqlHost())
->setMysqlRoot($updatedServer->getMysqlRoot())
->setWebServer($updatedServer->getWebServer())
->setWebServerSslListen($updatedServer->getWebServerSslListen())
->setWebServerSslPort($updatedServer->getWebServerSslPort())
->setMysqlServer($updatedServer->getMysqlServer())
->setSuphp($updatedServer->getSuphp())
->setFastcgi($updatedServer->getFastcgi())
->setNadminCompliant($updatedServer->getNadminCompliant())
->setEmailCompliant($updatedServer->getEmailCompliant())
->setAvailable($updatedServer->getAvailable())
->setEnvironment($updatedServer->getEnvironment())
->setInstalledAt($updatedServer->getInstalledAt());
$em = $this->getDoctrine()->getManager();
$em->persist($server);
$em->flush();
return $this->view($server);
}
I set manually all fields I can update. But this method don't working because if I send a request to update only one or few fields with a JSON body like this
{
"mac": "ff:ff:ff:ff:ff:ff"
}
The JSON body will look like this after I send the request
// This is what $updatedServer get in my controller
{
"id": null,
"name": null,
"alias": null,
"notes": null,
"hosted_domain": null,
"mac": "ff:ff:ff:ff:ff:ff",
// ...
}
As you can see above in my controller I have set every updatable fields
$server->setAlias($updatedServer->getAlias())
->setMac($updatedServer->getMac())
->setSshUser($updatedServer->getSshUser())
// ...
So if a value is null inside the body request the controller will set it to null, it will do the same with the default values set inside the entity
I don't know if this really a FOSRestBundle
How can I update only one or few field with a patch action without this problem ?
Is this possible / the right way ?
I searched on the Internet few hours + asking a question on Stackoverflow without success...
Am I obligated to use forms ?
Thanks
Imo if you handle the patch request manually, you will need to check on your own if any of the methods of the $updatedServer object returns null before calling the setter of the $server instance.
@xabbuh Yes I had this idea too, but I must write >15 condition. This is not really what I want... This can be handled automatiquely ?
Using the Form component is one way to do that. Otherwise you will have to write some custom code that does that in a more elegant way than writing a lot of if statements.
Old issue, I have the same problem. Maybe there is a better solution after some years...
This is using the ObjectNormalizer and PropertyAccessorInterface services from Symfony:
public function update(Zone $oldZone, Zone $newZone, array $context = [])
{
$data = $this->objectNormalizer->normalize($newZone, null, $context);
foreach ($data as $property => $value) {
$this->propertyAccessor->setValue($oldZone, $property, $value);
}
}
Context could be retrieved from the controller using:
$context = [];
$config = $request->attributes->get('_template');
if ($config instanceof ViewAnnotation) {
$context['groups'] = $config ->getSerializerGroups();
}