FOSRestBundle
FOSRestBundle copied to clipboard
PUT Controller - ConstraintViolationList as parameter detect the constraint uniqueEntity - No Form
PUT Controller - ConstraintViolationList as parameter detect the constraint uniqueEntity
Hi, I'm trying update an object without form, I have defined a constraint unique for mail field. When I use this in PostController it's working.
#config.yml
fos_rest:
...
body_converter:
enabled: true
validate: true
validation_errors_argument: validation
//AppBundle\Entity\Sample.php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Hateoas\Configuration\Annotation as Hateoas;
use Symfony\Component\Validator\Constraints as Assert;
use JMS\Serializer\Annotation as Serial;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* Sample
* ...
* @UniqueEntity("mail")
*/
class Sample
{
....
/**
* @var string
*
* @ORM\Column(name="mail", type="string", length=255, unique=true)
*
* @Assert\Email(
* message = "The email '{{ value }}' is not a valid email.",
* checkMX = true
* )
*/
private $mail;
....
//PUT CONTROLLER
/**
* @Rest\Put(path = "/samples/{id}", name = "api_put_samples")
* @ParamConverter("sample", class="AppBundle\Entity\Sample")
* @ParamConverter("sampleUpdate", converter="fos_rest.request_body")
*
* @Rest\View(StatusCode = Response::HTTP_NO_CONTENT)
*/
public function putSampleAction(Sample $sample, Sample $sampleUpdate, ConstraintViolationList $validation)
{
if($validation->count()) {
return $this->view($validation, Response::HTTP_BAD_REQUEST);
}
$em = $this->getDoctrine()->getManager();
//setter update object
$update = $this->setSample($sample, $sampleUpdate)
$em->persist($update);
$em->flush();
return $this->view($sample, Response::HTTP_NO_CONTENT,
[
'Location' => $this->generateUrl('api_sample', ['id' => $sample->getId()])
]
);
}
When i send by PUT a json body object for update with the mail field equal (without update), the ConstraintViolationList $validation detected a constraint.
public function putSampleAction(Sample $sample, Sample $sampleUpdate, ConstraintViolationList $validation)
{
dump($validation); die;
....
ConstraintViolationList {#1088
-violations: array:1 [
0 => ConstraintViolation {#1061
-message: "This value is already used."
-messageTemplate: "This value is already used."
-parameters: array:1 [
"{{ value }}" => ""[email protected]""
]
NOTE: friendsofsymfony/rest-bundle": "^2.2 symfony/symfony": "3.3.*
Any idea? Thanks
Any alternative or example? thanks!
Not sure I completely understand. You mean that you don't get any violation when issuing POST requests, but it's emitted when using PUT instead?
Hi @xabbuh Yes, when I use POST the Constraint @UniqueEntity("mail") it's works, but when using PUT jumps the constraint because it says that the email already exists (it exists because I am editing all the properties of that object and I have not modified it).
All this without using form.
This looks weird. Can you create a small example project that allows to reproduce your issue?
Ok! I go to create a small example project and I notify you Thanks
Hi, I had the same issue with UniqueEntity constrainst for POST and PUT requests. My hypothesis : For PUT request :
- the constrainst violations checks your first Entity\Sample -> Ok it is the one from the database,
- the constrainst violations checks your second Entity\Sample from body -> It is a new one (not saved in DB) and failed because email already exists in DB.
For POST request, there is no probleme because on each checks the mail doesn't exist in database. To bypass that you can use a form or a specific object to catch data from body : Example https://github.com/jfx/ci-report/blob/master/src/AppBundle/Controller/ProjectApiController.php (method : putProjectAction)
@xabbuh here has the small example project with error
@jfx I go to try your solution and then i notify you
Thanks!
@jfx I'm trying with your solution, but in my $personUpdate ($projectDTO in your project) always there is an error. My code
/**
* @Rest\Put(path = "/people/{id}", name = "api_put")
* @ParamConverter("person", class="AppBundle\Entity\Person")
* @ParamConverter("personUpdate", converter="fos_rest.request_body")
*
* @Rest\View(StatusCode = Response::HTTP_NO_CONTENT)
*/
public function putPersonAction(Person $person, Person $personUpdate, Request $request)
{
$validator = $this->get('validator');
$validationUpdate = $validator->validate($person);
if($validationUpdate->count()) {
return $this->view($validationUpdate, Response::HTTP_BAD_REQUEST);
}
...
your code:
/**
* @ParamConverter("projectDB", options={"mapping": {"prefid": "refid"}})
* @ParamConverter("projectDTO", converter="fos_rest.request_body"
*/
public function putProjectAction(ProjectDTO $projectDTO, Project $projectDB, Request $request)
{
if ($this->isInvalidToken($request, $projectDB->getToken())) {
return $this->getInvalidTokenView();
}
$validator = $this->get('validator');
$violationsDTO = $validator->validate($projectDTO);
if (count($violationsDTO) > 0) {
return $this->view($violationsDTO, Response::HTTP_BAD_REQUEST);
}
...
@JuanLuisGarciaBorrego : sure, $projectDTO is an instance of ProjectDTO class that is more or less identical to Project class except there is no constraint on unique field. This constrainst will be check on the second validation on Project class object.
Hello, I have the same problem, you have to find a solution? if so, thank you for sharing it. thank you