Cannot create an instance of DateTime from serialized data - symfony

I have a problem with the date.
Maybe I don't understand something in the process of serialization, but, when, I send a datetime to Api-Platform (Symfony) for example
dateEvaluation: "2017-12-05T11:52:00.000Z"
I obtain this message of error
Cannot create an instance of DateTime from serialized data because its constructor requires parameter "time" to be present.
This is my Entity
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* #ORM\Entity(repositoryClass="App\Repository\EvaluationRepository")
* #ORM\HasLifecycleCallbacks()
* #ApiResource(attributes={
* "normalization_context"={
* "groups"={"Evaluation"}
* }
* })
*/
class Evaluation
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
* #Groups({"NotesEvaluations", "Evaluation"})
*/
private $id;
/**
* #var \DateTime
* #ORM\Column(type="datetime")
* #Groups({"Evaluation"})
*/
private $created;
/**
* #var \DateTime
* #ORM\Column(type="datetime")
* #Groups({"Evaluation"})
*/
private $updated;
/**
* #var \DateTime
* #ORM\Column(type="datetime")
* #Groups({"Evaluation"})
*/
private $dateEvaluation;
/**
* #var string
*
* #ORM\Column(type="text")
* #Groups({"Evaluation"})
*/
private $commentaire;
/**
* #var
*
* #ORM\ManyToOne(targetEntity="App\Entity\Personnel")
* #Groups({"NotesEvaluations", "Evaluation"})
*/
private $auteur;
/**
* #var
*
* #ORM\ManyToMany(targetEntity="App\Entity\Personnel")
*/
private $autorises;
/**
* #var integer
*
* #ORM\Column(type="integer")
*/
private $annee;
/**
* #var
*
* #ORM\ManyToOne(targetEntity="App\Entity\Module", inversedBy="evaluations")
* #Groups({"Evaluation"})
*/
private $module;
/**
* #var Boolean
*
* #ORM\Column(type="boolean")
* #Groups({"NotesEvaluations"})
*/
private $visible;
/**
* #var Boolean
*
* #ORM\Column(type="boolean")
* #Groups({"NotesEvaluations"})
*/
private $modifiable;
/**
* #var
*
* #ORM\ManyToOne(targetEntity="App\Entity\TypeGroupe")
* #Groups({"Evaluation"})
*/
private $typegroupe;
/**
* #var float
*
* #ORM\Column(type="decimal")
* #Groups({"Evaluation"})
*/
private $coefficient;
/**
* #return float
*/
public function getCoefficient(): float
{
return $this->coefficient;
}
/**
* #return mixed
*/
public function getTypegroupe()
{
return $this->typegroupe;
}
/**
* #param mixed $typegroupe
*/
public function setTypegroupe($typegroupe): void
{
$this->typegroupe = $typegroupe;
}
/**
* #return \DateTime
*/
public function getDateEvaluation(): \DateTime
{
return $this->dateEvaluation;
}
/**
* #param \DateTime $dateEvaluation
*/
public function setDateEvaluation(\DateTime $dateEvaluation): void
{
$this->dateEvaluation = $dateEvaluation;
}
/**
* #return string
*/
public function getCommentaire(): string
{
return $this->commentaire;
}
/**
* #param string $commentaire
*/
public function setCommentaire(string $commentaire): void
{
$this->commentaire = $commentaire;
}
/**
* #param float $coefficient
*/
public function setCoefficient(float $coefficient): void
{
$this->coefficient = $coefficient;
}
/**
* #return mixed
*/
public function getId()
{
return $this->id;
}
/**
* #return \DateTime
*/
public function getCreated(): \DateTime
{
return $this->created;
}
/**
* #param \DateTime $created
*/
public function setCreated(\DateTime $created): void
{
$this->created = $created;
}
/**
* #return \DateTime
*/
public function getUpdated(): \DateTime
{
return $this->updated;
}
/**
* #param \DateTime $updated
*/
public function setUpdated(\DateTime $updated): void
{
$this->updated = $updated;
}
/**
* #return mixed
*/
public function getAuteur()
{
return $this->auteur;
}
/**
* #param mixed $auteur
*/
public function setAuteur($auteur): void
{
$this->auteur = $auteur;
}
/**
* #return mixed
*/
public function getAutorises()
{
return $this->autorises;
}
/**
* #param mixed $autorises
*/
public function setAutorises($autorises): void
{
$this->autorises = $autorises;
}
/**
* #return int
*/
public function getAnnee(): int
{
return $this->annee;
}
/**
* #param int $annee
*/
public function setAnnee(int $annee): void
{
$this->annee = $annee;
}
/**
* #return mixed
*/
public function getModule()
{
return $this->module;
}
/**
* #param mixed $module
*/
public function setModule($module): void
{
$this->module = $module;
}
/**
* #return bool
*/
public function isVisible(): bool
{
return $this->visible;
}
/**
* #param bool $visible
*/
public function setVisible(bool $visible): void
{
$this->visible = $visible;
}
/**
* #return bool
*/
public function isModifiable(): bool
{
return $this->modifiable;
}
/**
* #param bool $modifiable
*/
public function setModifiable(bool $modifiable): void
{
$this->modifiable = $modifiable;
}
/**
* #ORM\PreUpdate
*/
public function updateDate(): void
{
$this->setUpdated(new \Datetime());
}
public function __construct()
{
$this->setCreated(new \Datetime());
$this->setUpdated(new \Datetime());
}
}
I don't understand why "time" is missing. Maybe it is for created or updated fields ? Anyway, created and updated fields return with ApiPlatform an object with timezone ...
created:
{timezone: {name: "Europe/Paris",…}, offset: 561, timestamp: -62169984561}
offset:561
timestamp:-62169984561
timezone:{name: "Europe/Paris",…}
Thanks for your help.
David

I've found a way to manage this error that works for me. I declare the DateTimeNormalizer in my config.yml like that :
datetime_normalizer:
class: Symfony\Component\Serializer\Normalizer\DateTimeNormalizer
public: false
tags: [serializer.normalizer]
I hope that will help you !

In my case, I was using Symfony's Serializer Component without Symfony project and on the process of denormalization I had that issue so I had to add the DateTimeNormalizer before the ObjectNormalizer on the array of normalizers like this:
$serializer = new Serializer([new DateTimeNormalizer(), new ObjectNormalizer(null, new CamelCaseToSnakeCaseNameConverter())]);
Note that the order here is important.

In v1.1, using the class \DateTimeImmutable instead of \DateTime is what api-platform wait by default.
class Evaluation {
public function __construct()
{
$this->setCreated(new \DateTimeImmutable());
$this->setUpdated(new \DateTimeImmutable());
}
}

Change \DateTime in your entity to \DateTimeInterface. It should work.

Related

In Synfony 2 after adding #UniqueEntity("description") it takes duplicate value for description

//Events.php
<?php
namespace erp\GenerateBundle\Entity;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* Events
* #ORM\Entity
* #UniqueEntity(fields="description", message="Already Exists")
*/
class Events
{
/**
* #var string
* #Column(type = "string", unique = true)
* #Assert/Description()
*/
private $description;
/**
* #var \DateTime
*/
private $eventdate;
/**
* #var integer
*/
private $duration;
/**
* #var integer
*/
private $createdby;
/**
* #var \DateTime
*/
private $added;
/**
* #var \DateTime
*/
private $updated;
/**
* #var integer
*/
private $id;
/**
* #var \erp\GenerateBundle\Entity\User
*/
private $userid;
/**
* #var \erp\GenerateBundle\Entity\EventType
*/
private $eventtype;
/**
* Set description
*
* #param string $description
* #return Events
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set eventdate
*
* #param \DateTime $eventdate
* #return Events
*/
public function setEventdate($eventdate)
{
$this->eventdate = $eventdate;
return $this;
}
/**
* Get eventdate
*
* #return \DateTime
*/
public function getEventdate()
{
return $this->eventdate;
}
/**
* Set duration
*
* #param integer $duration
* #return Events
*/
public function setDuration($duration)
{
$this->duration = $duration;
return $this;
}
/**
* Get duration
*
* #return integer
*/
public function getDuration()
{
return $this->duration;
}
/**
* Set createdby
*
* #param integer $createdby
* #return Events
*/
public function setCreatedby($createdby)
{
$this->createdby = $createdby;
return $this;
}
/**
* Get createdby
*
* #return integer
*/
public function getCreatedby()
{
return $this->createdby;
}
/**
* Set added
*
* #param \DateTime $added
* #return Events
*/
public function setAdded($added)
{
$this->added = $added;
return $this;
}
/**
* Get added
*
* #return \DateTime
*/
public function getAdded()
{
return $this->added;
}
/**
* Set updated
*
* #param \DateTime $updated
* #return Events
*/
public function setUpdated($updated)
{
$this->updated = $updated;
return $this;
}
/**
* Get updated
*
* #return \DateTime
*/
public function getUpdated()
{
return $this->updated;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set userid
*
* #param \erp\GenerateBundle\Entity\User $userid
* #return Events
*/
public function setUserid(\erp\GenerateBundle\Entity\User $userid = null)
{
$this->userid = $userid;
return $this;
}
/**
* Get userid
*
* #return \erp\GenerateBundle\Entity\User
*/
public function getUserid()
{
return $this->userid;
}
/**
* Set eventtype
*
* #param \erp\GenerateBundle\Entity\EventType $eventtype
* #return Events
*/
public function setEventtype(\erp\GenerateBundle\Entity\EventType $eventtype = null)
{
$this->eventtype = $eventtype;
return $this;
}
/**
* Get eventtype
*
* #return \erp\GenerateBundle\Entity\EventType
*/
public function getEventtype()
{
return $this->eventtype;
}
}
Check Config.yml
framework:
validation: { enabled: true, enable_annotations: true}
In Controller
check isValid()
If it is not there then add. isValid() before submission of form .
I can hardly decipher your problem. Are there any error messages? Where is the problem in persisting to the db or submitting a form?
But I see some problems in the code you post it.
Annotation #Assert/Description() doesn't exist.
In the example you're missing use Doctrine\ORM\Mapping as ORM;
You should use #ORM\Column(type = "string", unique = true) if you use ORM alias instead of #Column

Extend Exisiting Entity to override getters and setters

I want to override an existing Entity's getters and setters. Is it possible to do this?
I want to add additional logic to the getters and setters.
Thanks
Jake He
for this you must make an entity that extend that entity you want to override
e.g
my base entity
abstract class AbstractEntity
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var \DateTime
*
* #ORM\Column(type="datetime")
* #Gedmo\Timestampable(on="create")
*/
protected $createdAt;
/**
* #var \DateTime
*
* #ORM\Column(type="datetime", nullable=true)
* #Gedmo\Timestampable(on="update")
*/
protected $updatedAt;
/**
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set createdAt
*
* #param \DateTime $createdAt
*
*/
public function setCreatedAt($createdAt)
{
$this->createdAt = $createdAt;
}
/**`enter code here`
* Get created
*
* #return \DateTime
*/
public function getCreatedAt()
{
return $this->createdAt;
}
/**
* Set updatedAt
*
* #param \DateTime $updatedAt
*
*/
public function setUpdatedAt($updatedAt)
{
$this->updatedAt = $updatedAt;
}
/**
* Get updatedAt
*
* #return \DateTime
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}
}
and then in my entity
class Group extends BaseEntity
{
public function __construct()
{
$this->children = [];
$this->users = [];
$this->accounts = [];
$this->isActive = true;
}
/**
* Set updatedAt
*
* #param \DateTime $updatedAt
*
*/
public function setCreatedAt($createdAt)
{
parent::setCreatedAt($createdAt); //
TODO: Override the implementation
}
}
hope it will help

Missing an assigned ID for field

I'm lost in a complexe relation (for me). I've a entity project for an entity client and you can attach users to a project. When i try to add a project without users, no problem. But, when i try to add a project and users Sf2 display this error :
Entity of type Intranet\IntranetBundle\Entity\ProjectUser is missing an assigned ID for field 'project'. The identifier generation strategy for this entity requires the ID field to be populated before EntityManager#persist() is called. If you want automatically generated identifiers instead you need to adjust the metadata mapping accordingly.
I'm understand it's angry because the project_id is null. But i don't know why it's null.
My Project.php
namespace Intranet\IntranetBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Project
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Intranet\IntranetBundle\Entity\ProjectRepository")
*/
class Project
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
* #Assert\NotBlank(
* message = "The field cannot be empty"
* )
*/
private $name;
/**
* #Gedmo\Slug(fields={"name"})
* #ORM\Column(length=255, unique=true)
*/
private $slug;
/**
* #var string
*
* #ORM\Column(name="contact_client", type="text", nullable=true)
*/
private $contactClient;
/**
* #var string
*
* #ORM\Column(name="technologies", type="string", length=255, nullable=true)
*/
private $technologies;
/**
* #var string
*
* #ORM\Column(name="languages", type="string", length=255, nullable=true)
*/
private $languages;
/**
* #var string
*
* #ORM\Column(name="extern", type="text", nullable=true)
*/
private $extern;
/**
* #var string
*
* #ORM\Column(name="url_prod", type="string", length=255, nullable=true)
*/
private $urlProd;
/**
* #var string
*
* #ORM\Column(name="url_staging", type="text", nullable=true)
*/
private $urlStaging;
/**
* #var string
*
* #ORM\Column(name="url_dev", type="text", nullable=true)
*/
private $urlDev;
/**
* #var string
*
* #ORM\Column(name="hosting_company", type="string", length=255, nullable=true)
*/
private $hostingCompany;
/**
* #var string
*
* #ORM\Column(name="hosting_type", type="string", length=255, nullable=true)
*/
private $hostingType;
/**
* #var string
*
* #ORM\Column(name="hosting_manager", type="text", nullable=true)
*/
private $hostingManager;
/**
* #var string
*
* #ORM\Column(name="ssh", type="text", nullable=true)
*/
private $ssh;
/**
* #var string
*
* #ORM\Column(name="ftp", type="text", nullable=true)
*/
private $ftp;
/**
* #var string
*
* #ORM\Column(name="db", type="text", nullable=true)
*/
private $db;
/**
* #var string
*
* #ORM\Column(name="emails", type="text", nullable=true)
*/
private $emails;
/**
* #var string
*
* #ORM\Column(name="cms", type="text", nullable=true)
*/
private $cms;
/**
* #var string
*
* #ORM\Column(name="web_services", type="text", nullable=true)
*/
private $webServices;
/**
* #var string
*
* #ORM\Column(name="comment", type="text", nullable=true)
*/
private $comment;
/**
* #ORM\ManyToOne(targetEntity="Intranet\IntranetBundle\Entity\Client", inversedBy="projects")
* #ORM\JoinColumn(nullable=false)
*/
private $client;
/**
* #ORM\OneToMany(targetEntity="Intranet\IntranetBundle\Entity\ProjectUser", mappedBy="project", cascade={"persist"})
*/
private $projectUsers;
public function __construct()
{
$this->projectUsers = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Project
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set slug
*
* #param string $slug
* #return Client
*/
public function setSlug($slug)
{
$this->slug = $slug;
return $this;
}
/**
* Get slug
*
* #return string
*/
public function getSlug()
{
return $this->slug;
}
/**
* Set contactClient
*
* #param string $contactClient
* #return Project
*/
public function setContactClient($contactClient)
{
$this->contactClient = $contactClient;
return $this;
}
/**
* Get contactClient
*
* #return string
*/
public function getContactClient()
{
return $this->contactClient;
}
/**
* Set technologies
*
* #param string $technologies
* #return Project
*/
public function setTechnologies($technologies)
{
$this->technologies = $technologies;
return $this;
}
/**
* Get technologies
*
* #return string
*/
public function getTechnologies()
{
return $this->technologies;
}
/**
* Set languages
*
* #param string $languages
* #return Project
*/
public function setLanguages($languages)
{
$this->languages = $languages;
return $this;
}
/**
* Get languages
*
* #return string
*/
public function getLanguages()
{
return $this->languages;
}
/**
* Set extern
*
* #param string $extern
* #return Project
*/
public function setExtern($extern)
{
$this->extern = $extern;
return $this;
}
/**
* Get extern
*
* #return string
*/
public function getExtern()
{
return $this->extern;
}
/**
* Set urlProd
*
* #param string $urlProd
* #return Project
*/
public function setUrlProd($urlProd)
{
$this->urlProd = $urlProd;
return $this;
}
/**
* Get urlProd
*
* #return string
*/
public function getUrlProd()
{
return $this->urlProd;
}
/**
* Set urlStaging
*
* #param string $urlStaging
* #return Project
*/
public function setUrlStaging($urlStaging)
{
$this->urlStaging = $urlStaging;
return $this;
}
/**
* Get urlStaging
*
* #return string
*/
public function getUrlStaging()
{
return $this->urlStaging;
}
/**
* Set urlDev
*
* #param string $urlDev
* #return Project
*/
public function setUrlDev($urlDev)
{
$this->urlDev = $urlDev;
return $this;
}
/**
* Get urlDev
*
* #return string
*/
public function getUrlDev()
{
return $this->urlDev;
}
/**
* Set hostingCompany
*
* #param string $hostingCompany
* #return Project
*/
public function setHostingCompany($hostingCompany)
{
$this->hostingCompany = $hostingCompany;
return $this;
}
/**
* Get hostingCompany
*
* #return string
*/
public function getHostingCompany()
{
return $this->hostingCompany;
}
/**
* Set hostingType
*
* #param string $hostingType
* #return Project
*/
public function setHostingType($hostingType)
{
$this->hostingType = $hostingType;
return $this;
}
/**
* Get hostingType
*
* #return string
*/
public function getHostingType()
{
return $this->hostingType;
}
/**
* Set hostingManager
*
* #param string $hostingManager
* #return Project
*/
public function setHostingManager($hostingManager)
{
$this->hostingManager = $hostingManager;
return $this;
}
/**
* Get hostingManager
*
* #return string
*/
public function getHostingManager()
{
return $this->hostingManager;
}
/**
* Set ssh
*
* #param string $ssh
* #return Project
*/
public function setSsh($ssh)
{
$this->ssh = $ssh;
return $this;
}
/**
* Get ssh
*
* #return string
*/
public function getSsh()
{
return $this->ssh;
}
/**
* Set ftp
*
* #param string $ftp
* #return Project
*/
public function setFtp($ftp)
{
$this->ftp = $ftp;
return $this;
}
/**
* Get ftp
*
* #return string
*/
public function getFtp()
{
return $this->ftp;
}
/**
* Set db
*
* #param string $db
* #return Project
*/
public function setDb($db)
{
$this->db = $db;
return $this;
}
/**
* Get db
*
* #return string
*/
public function getDb()
{
return $this->db;
}
/**
* Set emails
*
* #param string $emails
* #return Project
*/
public function setEmails($emails)
{
$this->emails = $emails;
return $this;
}
/**
* Get emails
*
* #return string
*/
public function getEmails()
{
return $this->emails;
}
/**
* Set cms
*
* #param string $cms
* #return Project
*/
public function setCms($cms)
{
$this->cms = $cms;
return $this;
}
/**
* Get cms
*
* #return string
*/
public function getCms()
{
return $this->cms;
}
/**
* Set webServices
*
* #param string $webServices
* #return Project
*/
public function setWebServices($webServices)
{
$this->webServices = $webServices;
return $this;
}
/**
* Get webServices
*
* #return string
*/
public function getWebServices()
{
return $this->webServices;
}
/**
* Set comment
*
* #param string $comment
* #return Project
*/
public function setComment($comment)
{
$this->comment = $comment;
return $this;
}
/**
* Get comment
*
* #return string
*/
public function getComment()
{
return $this->comment;
}
/**
* Set client
*
* #param \Intranet\IntranetBundle\Entity\Client $client
* #return Project
*/
public function setClient(\Intranet\IntranetBundle\Entity\Client $client)
{
$this->client = $client;
return $this;
}
/**
* Get client
*
* #return \Intranet\IntranetBundle\Entity\Client
*/
public function getClient()
{
return $this->client;
}
public function addProjectUser(\Intranet\IntranetBundle\Entity\ProjectUser $projectUser)
{
$this->projectUsers[] = $projectUser;
}
public function removeProjectUser(\Intranet\IntranetBundle\Entity\ProjectUser $projectUser)
{
$this->projectUsers->removeElement($projectUser);
}
public function getProjectUsers()
{
return $this->projectUsers;
}
}
My ProjectUser.php
namespace Intranet\IntranetBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
*/
class ProjectUser
{
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Intranet\IntranetBundle\Entity\Project", inversedBy="projectUsers")
*/
private $project;
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Intranet\UserBundle\Entity\User")
*/
private $user;
/**
* #ORM\Column(name="profil", type="smallint")
*/
private $profil;
public function setProject(\Intranet\IntranetBundle\Entity\Project $project)
{
$project->addProjectUser($this);
$this->project = $project;
}
public function getProject()
{
return $this->project;
}
public function setUser(\Intranet\UserBundle\Entity\User $user)
{
$this->user = $user;
}
public function getUser()
{
return $this->user;
}
public function setProfil($profil)
{
$this->profil = $profil;
}
public function getProfil()
{
return $this->profil;
}
}
profil = smallint for the job of the user (1=manager, 2=designer, ...)
My ProjectController (addAction)
public function addAction()
{
$project = new Project;
$form = $this->createForm(new ProjectType, $project);
$request = $this->get('request');
if ($request->getMethod() == 'POST') {
$form->bind($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($project);
$em->flush();
foreach ($form->get('projectUsers')->getData() as $u) {
$u->setProject($project);
$em->persist($u);
}
$em->flush();
$this->get('session')->getFlashBag()->add('success', 'The project : '. $project->getName() .' has been added');
return $this->redirect($this->generateUrl('clients_list'));
}
}
return $this->render('IntranetIntranetBundle:Project:add_project.html.twig', array(
'form' => $form->createView()
));
}
Thanks for your help
Well, first of all, you shouldn't specify #ORM\Id annotation on every foreign key in your ProjectUser entity - it is for primary keys.
Then you should declare column join on foreign key fields:
/**
* #ORM\ManyToOne(targetEntity="Intranet\IntranetBundle\Entity\Project", inversedBy="projectUsers")
* #ORM\JoinColumn(name="project_id", referencedColumnName="id")
*/
private $project;
/**
* #ORM\ManyToOne(targetEntity="Intranet\IntranetBundle\Entity\User", inversedBy="projects")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
private $user;
You also should have a field like
class User
{
// ...
/**
* #ORM\OneToMany(targetEntity="Intranet\IntranetBundle\Entity\ProjectUser", mappedBy="user")
*/
private $projects;
// ...
}
Finally, to add user to project, I suggest you embed a ProjectUserType form with user selection into ProjectType form. In your controller, you can have something like
public function addAction()
{
$project = new Project;
$projectUser = new ProjectUser();
$projectUser->setProject($project);
$project->addProjectUser($projectUser);
$form = $this->createForm(new ProjectType, $project);
// ...
And in form ProjectUserType
class ProjectUserType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('user', 'entity', array(
'class' => 'Intranet:IntranetBundle:User'
));
// ...
Hope this helps at least a little bit.
When you code : $em->persist($project);
$project is equal to $project = new Project; (don't you have forget '()' ?)
Actually the $projet is empty... To do this, I think you forget to code :
$project = $form->getData();

Symfony2 - Validation for form with multiple entities not working

I have a Form for Product with relation oneToMany with entity ProductLocale and the user can add many ProductLocale as he want.
The rendered form in html seems correct but when I receive the POST array and perform bind() the server response this error:
"ERROR: This value should be of type Wearplay\WearBundle\Entity\ProductLocale.
But I send two ProductLocale entities and validator doesn't recognize them.
It is obvious that the POST request contains a multi-dimensional array that contains the various entities ProductLocale, but the question is why
$form->bindRequest($request)
doesn't work correctly?
Edit #1:
Product Entity
<?php
namespace Wearplay\WearBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity
* #ORM\HasLifecycleCallbacks
* #ORM\Table(name="product")
*/
class Product
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
*#ORM\Column(type="string")
*/
private $name;
/**
* #ORM\ManyToOne(targetEntity="BrandOwner", cascade="persist")
*/
private $owner;
/**
* #ORM\Column(name="creation_date", type="datetime", nullable=false)
*/
private $creationDate;
/**
* #Assert\Type(type="Wearplay\WearBundle\Entity\ProductLocale")
*/
protected $productLocales;
/**
* #Assert\Type(type="Wearplay\WearBundle\Entity\ProductPic")
*/
protected $productPic;
public function __construct()
{
$this->productLocales = new ArrayCollection();
}
/**
* #ORM\PrePersist
*/
public function createTimestamps()
{
$this->creationDate = new \DateTime(date('Y-m-d H:i:s'));
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Product
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Get creationDate
*
* #return \DateTime
*/
public function getCreationDate()
{
return $this->creationDate;
}
/**
* Set owner
*
* #param \Wearplay\WearBundle\Entity\BrandOwner $owner
* #return Product
*/
public function setOwner(\Wearplay\WearBundle\Entity\BrandOwner $owner = null)
{
$this->owner = $owner;
return $this;
}
/**
* Get owner
*
* #return \Wearplay\WearBundle\Entity\BrandOwner
*/
public function getOwner()
{
return $this->owner;
}
/**
* Get ProductLocales
*
* #return \Wearplay\WearBundle\Entity\ProductLocale
*/
public function getProductLocales()
{
return $this->productLocales;
}
/**
* Set ProductLocale
*
* #param \Wearplay\WearBundle\Entity\ProductLocale $productLocale
* #return Product
*/
public function setProductLocales(ArrayCollection $productLocales = null)
{
$this->productLocales = $productLocales;
//return $this->productLocale;
}
/**
* Add ProductLocale
*
* #param ProductLocale $productLocale
*/
/*
public function addProductLocale(ProductLocale $productLocale)
{
$this->productLocales[] = $productLocale;
}
public function removeProductLocale(ProductLocale $productLocale)
{
$this->productLocale->removeElement($productLocale);
}*/
/**
* Get ProductPic
*
* #return \Wearplay\WearBundle\Entity\ProductPic
*/
public function getProductPic()
{
return $this->productPic;
}
/**
* Set ProductPic
*
* #param \Wearplay\WearBundle\Entity\ProductPic $productPic
* #return Product
*/
public function setProductPic(ProductPic $productPic = null)
{
$this->productPic = $productPic;
}
/**
* Add ProductPic
*
* #param ProductPic $productPic
*/
public function addProductPic(ProductPic $productPic)
{
$this->productPic[] = $productPic;
}
}
ProductLocale Entity
<?php
namespace Wearplay\WearBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\HasLifecycleCallbacks
* #ORM\Table(name="product_locale")
*/
class ProductLocale
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Product", cascade="persist")
*/
private $product;
/**
*#ORM\Column(name="market_nation", type="string")
*/
private $marketNation;
/**
* #ORM\Column(type="string")
*/
private $link;
/**
* #ORM\Column(type="decimal", precision=9, scale=2)
*/
private $price;
/**
* #ORM\Column(type="string", length=3)
*/
private $currency;
/**
* #ORM\Column(name="creation_date", type="datetime", nullable=false)
*/
private $creationDate;
/**
* #ORM\PrePersist
*/
/*
public function addProduct(Product $product)
{
if (!$this->product->contains($product)) {
$this->product->add($product);
}
}
*/
public function createTimestamps()
{
$this->creationDate = new \DateTime(date('Y-m-d H:i:s'));
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set marketNation
*
* #param string $marketNation
* #return ProductLocale
*/
public function setMarketNation($marketNation)
{
$this->marketNation = $marketNation;
return $this;
}
/**
* Get marketNation
*
* #return string
*/
public function getMarketNation()
{
return $this->marketNation;
}
/**
* Set link
*
* #param string $link
* #return ProductLocale
*/
public function setLink($link)
{
$this->link = $link;
return $this;
}
/**
* Get link
*
* #return string
*/
public function getLink()
{
return $this->link;
}
/**
* Set price
*
* #param float $price
* #return ProductLocale
*/
public function setPrice($price)
{
$this->price = $price;
return $this;
}
/**
* Get price
*
* #return float
*/
public function getPrice()
{
return $this->price;
}
/**
* Set currency
*
* #param string $currency
* #return ProductLocale
*/
public function setCurrency($currency)
{
$this->currency = $currency;
return $this;
}
/**
* Get currency
*
* #return string
*/
public function getCurrency()
{
return $this->currency;
}
/**
* Set creationDate
*
* #param \DateTime $creationDate
* #return ProductLocale
*/
public function setCreationDate($creationDate)
{
$this->creationDate = $creationDate;
return $this;
}
/**
* Get creationDate
*
* #return \DateTime
*/
public function getCreationDate()
{
return $this->creationDate;
}
/**
* Set product
*
* #param \Wearplay\WearBundle\Entity\Product $product
* #return ProductLocale
*/
public function setProduct(\Wearplay\WearBundle\Entity\Product $product = null)
{
$this->product = $product;
return $this;
}
/**
* Get product
*
* #return \Wearplay\WearBundle\Entity\Product
*/
public function getProduct()
{
return $this->product;
}
}
Solved
Yes #ihsan and #snyx, you're absolutely right, I removed this line:
#Assert\Type(type="Wearplay\WearBundle\Entity\ProductLocale and everything worked perfectly.
I'm sorry for the trivial question but I'm pretty new in Symfony2.

Form nulling a value when user doesn't supply it

Reading this page I've setup a form to handle PATCH requests.
I've a Player entity:
<?php
namespace Acme\PlayerBundle\Entity;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\ORM\Mapping as ORM;
/**
* Acme\PlayerBundle\Entity\Player
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Acme\PlayerBundle\Entity\PlayerRepository")
*/
class Player
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string $name
*
* #ORM\Column(name="name", type="string", length=255)
* #Assert\NotBlank()
*/
private $name;
/**
* #ORM\ManyToOne(targetEntity="Acme\UserBundle\Entity\User", inversedBy="players")
* #ORM\JoinColumn(nullable=false)
*/
private $owner;
/**
* #ORM\ManyToOne(targetEntity="Acme\TeamBundle\Entity\Team", inversedBy="players")
* #ORM\JoinColumn(nullable=false)
* #Assert\NotBlank()
*/
private $team;
/**
* #var integer $shirtNumber
*
* #ORM\Column(name="shirtNumber", type="smallint")
* #Assert\NotBlank()
*/
private $shirtNumber;
/**
* #var integer $vsid
*
* #ORM\Column(name="vsid", type="integer", nullable=true)
*/
private $vsid;
/**
* #var string $firstname
*
* #ORM\Column(name="firstname", type="string", length=255, nullable=true)
*/
private $firstname;
/**
* #var string $lastname
*
* #ORM\Column(name="lastname", type="string", length=255, nullable=true)
*/
private $lastname;
/**
* #var boolean $deleted
*
* #ORM\Column(name="deleted", type="boolean")
*/
private $deleted = false;
/**
* #var integer $role
*
* #ORM\Column(type="integer", nullable=true)
*/
private $role;
/**
* Create the user salt
*/
public function __construct()
{
//TODO: just for test
$this->uniqueId = substr(uniqid(), 0, 14);
}
/* MANAGED BY DOCTRINE, DON'T EDIT */
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Player
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set shirtNumber
*
* #param integer $shirtNumber
* #return Player
*/
public function setShirtNumber($shirtNumber)
{
$this->shirtNumber = $shirtNumber;
return $this;
}
/**
* Get shirtNumber
*
* #return integer
*/
public function getShirtNumber()
{
return $this->shirtNumber;
}
/**
* Set vsid
*
* #param integer $vsid
* #return Player
*/
public function setVsid($vsid)
{
$this->vsid = $vsid;
return $this;
}
/**
* Get vsid
*
* #return integer
*/
public function getVsid()
{
return $this->vsid;
}
/**
* Set firstname
*
* #param string $firstname
* #return Player
*/
public function setFirstname($firstname)
{
$this->firstname = $firstname;
return $this;
}
/**
* Get firstname
*
* #return string
*/
public function getFirstname()
{
return $this->firstname;
}
/**
* Set lastname
*
* #param string $lastname
* #return Player
*/
public function setLastname($lastname)
{
$this->lastname = $lastname;
return $this;
}
/**
* Get lastname
*
* #return string
*/
public function getLastname()
{
return $this->lastname;
}
/**
* Set deleted
*
* #param boolean $deleted
* #return Player
*/
public function setDeleted($deleted)
{
$this->deleted = $deleted;
return $this;
}
/**
* Get deleted
*
* #return boolean
*/
public function getDeleted()
{
return $this->deleted;
}
/**
* Set role
*
* #param integer $role
* #return Player
*/
public function setRole($role)
{
$this->role = $role;
return $this;
}
/**
* Get role
*
* #return integer
*/
public function getRole()
{
return $this->role;
}
/**
* Set owner
*
* #param Acme\UserBundle\Entity\User $owner
* #return Player
*/
public function setOwner(\Acme\UserBundle\Entity\User $owner)
{
$this->owner = $owner;
return $this;
}
/**
* Get owner
*
* #return Acme\UserBundle\Entity\User
*/
public function getOwner()
{
return $this->owner;
}
/**
* Set team
*
* #param Acme\TeamBundle\Entity\Team $team
* #return Player
*/
public function setTeam(\Acme\TeamBundle\Entity\Team $team)
{
$this->team = $team;
return $this;
}
/**
* Get team
*
* #return Acme\TeamBundle\Entity\Team
*/
public function getTeam()
{
return $this->team;
}
}
and a Team entity:
<?php
namespace Acme\TeamBundle\Entity;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* Acme\TeamBundle\Entity\Team
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Acme\TeamBundle\Entity\TeamRepository")
*/
class Team
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string $uniqueId
*
* #ORM\Column(name="uniqueId", type="string", length=15)
*/
private $uniqueId;
/**
* #ORM\ManyToOne(targetEntity="Acme\UserBundle\Entity\User", inversedBy="teams")
* #ORM\JoinColumn(nullable=false)
*/
private $owner;
/**
* #var string $name
*
* #ORM\Column(name="name", type="string", length=50)
* #Assert\NotBlank()
*/
private $name;
/**
* #var string $homeColor
*
* #ORM\Column(name="homeColor", type="string", length=7, nullable=true)
*/
private $homeColor;
/**
* #var string $awayColor
*
* #ORM\Column(name="awayColor", type="string", length=7, nullable=true)
*/
private $awayColor;
/**
* #var string $homeShirt
*
* #ORM\Column(name="homeShirt", type="string", length=50, nullable=true)
*/
private $homeShirt;
/**
* #var string $awayShirt
*
* #ORM\Column(name="awayShirt", type="string", length=50, nullable=true)
*/
private $awayShirt;
/**
* #var string $teamLogo
*
* #ORM\Column(name="teamLogo", type="string", length=50, nullable=true)
*/
private $teamLogo;
/**
* #var boolean $deleted
*
* #ORM\Column(name="deleted", type="boolean")
*/
private $deleted = false;
/**
* #ORM\OneToMany(targetEntity="Acme\PlayerBundle\Entity\Player", mappedBy="team", cascade={"persist", "remove"})
*/
private $players;
/**
* #ORM\OneToMany(targetEntity="Acme\MatchBundle\Entity\Match", mappedBy="homeTeam")
*/
private $homeMatches;
/**
* #ORM\OneToMany(targetEntity="Acme\MatchBundle\Entity\Match", mappedBy="awayTeam")
*/
private $awayMatches;
/**
* Create the user salt
*/
public function __construct()
{
$this->players = new ArrayCollection();
$this->homeMatches = new ArrayCollection();
$this->awayMatches = new ArrayCollection();
//TODO: just for test
$this->uniqueId = substr(uniqid(), 0, 14);
}
public function getMatches()
{
return array_merge($this->awayMatches->toArray(), $this->homeMatches->toArray());
}
/* MANAGED BY DOCTRINE, DON'T EDIT */
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set uniqueId
*
* #param string $uniqueId
* #return Team
*/
public function setUniqueId($uniqueId)
{
$this->uniqueId = $uniqueId;
return $this;
}
/**
* Get uniqueId
*
* #return string
*/
public function getUniqueId()
{
return $this->uniqueId;
}
/**
* Set name
*
* #param string $name
* #return Team
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set homeColor
*
* #param string $homeColor
* #return Team
*/
public function setHomeColor($homeColor)
{
$this->homeColor = $homeColor;
return $this;
}
/**
* Get homeColor
*
* #return string
*/
public function getHomeColor()
{
return $this->homeColor;
}
/**
* Set awayColor
*
* #param string $awayColor
* #return Team
*/
public function setAwayColor($awayColor)
{
$this->awayColor = $awayColor;
return $this;
}
/**
* Get awayColor
*
* #return string
*/
public function getAwayColor()
{
return $this->awayColor;
}
/**
* Set homeShirt
*
* #param string $homeShirt
* #return Team
*/
public function setHomeShirt($homeShirt)
{
$this->homeShirt = $homeShirt;
return $this;
}
/**
* Get homeShirt
*
* #return string
*/
public function getHomeShirt()
{
return $this->homeShirt;
}
/**
* Set awayShirt
*
* #param string $awayShirt
* #return Team
*/
public function setAwayShirt($awayShirt)
{
$this->awayShirt = $awayShirt;
return $this;
}
/**
* Get awayShirt
*
* #return string
*/
public function getAwayShirt()
{
return $this->awayShirt;
}
/**
* Set teamLogo
*
* #param string $teamLogo
* #return Team
*/
public function setTeamLogo($teamLogo)
{
$this->teamLogo = $teamLogo;
return $this;
}
/**
* Get teamLogo
*
* #return string
*/
public function getTeamLogo()
{
return $this->teamLogo;
}
/**
* Set deleted
*
* #param boolean $deleted
* #return Team
*/
public function setDeleted($deleted)
{
$this->deleted = $deleted;
return $this;
}
/**
* Get deleted
*
* #return boolean
*/
public function getDeleted()
{
return $this->deleted;
}
/**
* Add players
*
* #param Acme\PlayerBundle\Entity\Player $players
* #return Team
*/
public function addPlayer(\Acme\PlayerBundle\Entity\Player $players)
{
$this->players[] = $players;
return $this;
}
/**
* Remove players
*
* #param Acme\PlayerBundle\Entity\Player $players
*/
public function removePlayer(\Acme\PlayerBundle\Entity\Player $players)
{
$this->players->removeElement($players);
}
/**
* Get players
*
* #return Doctrine\Common\Collections\Collection
*/
public function getPlayers()
{
return $this->players;
}
/**
* Add homeMatches
*
* #param Acme\MatchBundle\Entity\Match $homeMatches
* #return Team
*/
public function addHomeMatche(\Acme\MatchBundle\Entity\Match $homeMatches)
{
$this->homeMatches[] = $homeMatches;
return $this;
}
/**
* Remove homeMatches
*
* #param Acme\MatchBundle\Entity\Match $homeMatches
*/
public function removeHomeMatche(\Acme\MatchBundle\Entity\Match $homeMatches)
{
$this->homeMatches->removeElement($homeMatches);
}
/**
* Get homeMatches
*
* #return Doctrine\Common\Collections\Collection
*/
public function getHomeMatches()
{
return $this->homeMatches;
}
/**
* Add awayMatches
*
* #param Acme\MatchBundle\Entity\Match $awayMatches
* #return Team
*/
public function addAwayMatche(\Acme\MatchBundle\Entity\Match $awayMatches)
{
$this->awayMatches[] = $awayMatches;
return $this;
}
/**
* Remove awayMatches
*
* #param Acme\MatchBundle\Entity\Match $awayMatches
*/
public function removeAwayMatche(\Acme\MatchBundle\Entity\Match $awayMatches)
{
$this->awayMatches->removeElement($awayMatches);
}
/**
* Get awayMatches
*
* #return Doctrine\Common\Collections\Collection
*/
public function getAwayMatches()
{
return $this->awayMatches;
}
/**
* Set owner
*
* #param Acme\UserBundle\Entity\User $owner
* #return Team
*/
public function setOwner(\Acme\UserBundle\Entity\User $owner)
{
$this->owner = $owner;
return $this;
}
/**
* Get owner
*
* #return Acme\UserBundle\Entity\User
*/
public function getOwner()
{
return $this->owner;
}
}
Now I've created a player form class with the app/console and I've edited the team field to be an instance of the Team entity, this way:
<?php
namespace Acme\PlayerBundle\Form;
use Acme\TeamBundle\Entity\TeamRepository;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class PlayerType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('shirtNumber')
->add('firstname')
->add('lastname')
->add('role')
->add('team', 'entity', array(
'class' => 'AcmeTeamBundle:Team',
'query_builder' => function(TeamRepository $er) {
$query = $er->createQueryBuilder('t');
return $query;
}
));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\PlayerBundle\Entity\Player',
'csrf_protection' => false
));
}
public function getName()
{
return 'player';
}
}
And this is the relevant part of my controller:
/**
* Create a new player
*
* #Route(".{_format}", name="api_player_create")
* #Method("POST")
* #ApiDoc(
* description="Create a new player",
* statusCodes={
* 201="Player created and informations are returned",
* 400="Missing informations",
* 403="The user isn't authorized"
* },
* input="Acme\PlayerBundle\Form\PlayerType",
* return="Acme\PlayerBundle\Entity\Player"
* )
*
* #return Renders the player just created
*/
public function createPlayerAction()
{
return $this->processForm(new Player());
}
/**
* Edit a player
*
* #param integer $id The id of the player to be created
*
* #Route("/{id}.{_format}", name="api_player_patch", requirements={ "id": "\d+" })
* #Method("PATCH")
* #ApiDoc(
* description="Edit a player",
* statusCodes={
* 200="Player is updated",
* 400="Missing informations",
* 403="The user isn't authorized"
* },
* input="Acme\PlayerBundle\Form\PlayerType",
* return="Acme\PlayerBundle\Entity\Player"
* )
*
* #return Renders the player just edited
*/
public function editPlayerAction(Player $player)
{
if ($player->getOwner() != $this->getUser()) {
throw new ApiException\PermissionDeniedException;
}
return $this->processForm($player);
}
/**
* Function to handle a form to create/edit a player
*
* #param Player $player The player to be created or edited
*
* #return Api Response
*/
private function processForm(Player $player)
{
/**
* Check if the player is new (to be created) or we're editing a player
*/
$statusCode = is_null($player->getId()) ? 201 : 200;
$form = $this->createForm(new PlayerType(), $player);
$form->bind($this->getRequest());
if ($form->isValid()) {
if($player->getTeam()->getOwner() != $this->getUser()) {
throw new ApiException\PermissionDeniedException;
}
$player->setOwner($this->getUser());
$this->entityManager->persist($player);
$this->entityManager->flush();
return $this->apiResponse->getResponse($player, $statusCode);
}
return $this->apiResponse->getResponse($form, 400, 'Missing arguments');
}
The player creation works fine, the player edit doesn't, when the user makes the api request, passing the ID in the url and the name of the player I get:
Catchable Fatal Error: Argument 1 passed to Acme\PlayerBundle\Entity\Player::setTeam() must be an instance of Acme\TeamBundle\Entity\Team, null given, called in /Volumes/Dati/Users/alessandro/Sites/acme-api/vendor/symfony/symfony/src/Symfony/Component/Form/Util/PropertyPath.php on line 538 and defined in /Volumes/Dati/Users/alessandro/Sites/acme-api/src/Acme/PlayerBundle/Entity/Player.php line 278
Seems that form is trying to set the Team to null, why?
I've tried both sending and not the team as the form parameters but it doesn't work.
Any clue?
Figured it out that null unsent fields in the form is the default behaviour in symfony.
There is an open request for partial form binding in symfony. For now a guy created a form event subscriber that adds the missing fields with the actual values:
https://gist.github.com/3720535
This is his code:
<?php
namespace Foo;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormEvent;
/**
* Changes Form->bind() behavior so that it treats not set values as if they
* were sent unchanged.
*
* Use when you don't want fields to be set to NULL when they are not displayed
* on the page (or to implement PUT/PATCH requests).
*/
class PatchSubscriber implements EventSubscriberInterface
{
public function onPreBind(FormEvent $event)
{
$form = $event->getForm();
$clientData = $event->getData();
$clientData = array_replace($this->unbind($form), $clientData ?: array());
$event->setData($clientData);
}
/**
* Returns the form's data like $form->bind() expects it
*/
protected function unbind($form)
{
if ($form->hasChildren()) {
$ary = array();
foreach ($form->getChildren() as $name => $child) {
$ary[$name] = $this->unbind($child);
}
return $ary;
} else {
return $form->getClientData();
}
}
static public function getSubscribedEvents()
{
return array(
FormEvents::PRE_BIND => 'onPreBind',
);
}
}
to add to the form you have to edit the buildForm method in the form class:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$subscriber = new PatchSubscriber();
$builder->addEventSubscriber($subscriber);
$builder->add('name');
....
}
In this case you're ok to use the PATCH REST requests to edit an entity just by the sent fields

Resources