Symfony persists fail with relation cascade - symfony

Hello i have this error when i try to persist my entity :
An exception occurred while executing 'INSERT INTO item_details (item_id, item_type, name, start_date, end_date, description, pre_requisites, picture, acquired_knowledges, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)' with params [null, null, "ertret", "09\/01\/2014", "17\/01\/2014", "ter", "trtre", {}, "trtre", null]:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'item_id' cannot be null
Course entity code :
<?php
namespace Mooc\AdminBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Course
*
* #ORM\Table(name="course")
* #ORM\Entity
*/
class Course
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var integer
*
* #ORM\Column(name="language_id", type="integer", nullable=false)
*/
private $languageId;
/**
* #var integer
*
* #ORM\Column(name="category_id", type="integer", nullable=false)
*/
private $categoryId;
/**
* #ORM\OneToMany(targetEntity="ItemDetails", mappedBy="course",cascade={"all"})
**/
private $details;
/**
* Constructor
*/
public function __construct()
{
$this->details = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set languageId
*
* #param integer $languageId
* #return Course
*/
public function setLanguageId($languageId)
{
$this->languageId = $languageId;
return $this;
}
/**
* Get languageId
*
* #return integer
*/
public function getLanguageId()
{
return $this->languageId;
}
/**
* Set categoryId
*
* #param integer $categoryId
* #return Course
*/
public function setCategoryId($categoryId)
{
$this->categoryId = $categoryId;
return $this;
}
/**
* Get categoryId
*
* #return integer
*/
public function getCategoryId()
{
return $this->categoryId;
}
/**
* Add details
*
* #param \Mooc\TeacherBundle\Entity\ItemDetails $details
* #return Course
*/
public function addDetail(\Mooc\AdminBundle\Entity\ItemDetails $details)
{
$this->details[] = $details;
return $this;
}
/**
* Add details
*
* #param \Mooc\TeacherBundle\Entity\ItemDetails $details
* #return Course
*/
public function setDetails(\Mooc\AdminBundle\Entity\ItemDetails $details)
{
$this->details[] = $details;
return $this;
}
/**
* Remove details
*
* #param \Mooc\TeacherBundle\Entity\ItemDetails $details
*/
public function removeDetail(\Mooc\AdminBundle\Entity\ItemDetails $details)
{
$this->details->removeElement($details);
}
/**
* Get details
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getDetails()
{
return $this->details;
}
}
Item details entity code :
namespace Mooc\AdminBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* ItemDetails
*
* #ORM\Table(name="item_details")
* #ORM\Entity
*/
class ItemDetails
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var integer
*
* #ORM\Column(name="item_id", type="integer", nullable=false)
*/
private $itemId;
/**
* #var integer
*
* #ORM\Column(name="item_type", type="integer", nullable=false)
*/
private $itemType;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255, nullable=false)
*/
private $name;
/**
* #var string
*
* #ORM\Column(name="start_date", type="string", length=60, nullable=false)
*/
private $startDate;
/**
* #var string
*
* #ORM\Column(name="end_date", type="string", length=60, nullable=false)
*/
private $endDate;
/**
* #var string
*
* #ORM\Column(name="description", type="text", nullable=false)
*/
private $description;
/**
* #var string
*
* #ORM\Column(name="pre_requisites", type="text", nullable=false)
*/
private $preRequisites;
/**
* #var string
*
* #ORM\Column(name="picture", type="string", length=255, nullable=false)
*/
private $picture;
/**
* #var string
*
* #ORM\Column(name="acquired_knowledges", type="text", nullable=false)
*/
private $acquiredKnowledges;
/**
* #var integer
*
* #ORM\Column(name="status", type="integer", nullable=false)
*/
private $status;
/**
* #ORM\ManyToOne(targetEntity="Course", inversedBy="details")
* #ORM\JoinColumn(name="item_id", referencedColumnName="id")
**/
private $course;
/**
* #ORM\OneToMany(targetEntity="Video", mappedBy="itemDetails",cascade={"all"})
**/
private $video;
/**
* Constructor
*/
public function __construct()
{
$this->video = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set itemId
*
* #param integer $itemId
* #return ItemDetails
*/
public function setItemId($itemId)
{
$this->itemId = $itemId;
return $this;
}
/**
* Get itemId
*
* #return integer
*/
public function getItemId()
{
return $this->itemId;
}
/**
* Set itemType
*
* #param integer $itemType
* #return ItemDetails
*/
public function setItemType($itemType)
{
$this->itemType = $itemType;
return $this;
}
/**
* Get itemType
*
* #return integer
*/
public function getItemType()
{
return $this->itemType;
}
/**
* Set name
*
* #param string $name
* #return ItemDetails
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set startDate
*
* #param string $startDate
* #return ItemDetails
*/
public function setStartDate($startDate)
{
$this->startDate = $startDate;
return $this;
}
/**
* Get startDate
*
* #return string
*/
public function getStartDate()
{
return $this->startDate;
}
/**
* Set endDate
*
* #param string $endDate
* #return ItemDetails
*/
public function setEndDate($endDate)
{
$this->endDate = $endDate;
return $this;
}
/**
* Get endDate
*
* #return string
*/
public function getEndDate()
{
return $this->endDate;
}
/**
* Set description
*
* #param string $description
* #return ItemDetails
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set preRequisites
*
* #param string $preRequisites
* #return ItemDetails
*/
public function setPreRequisites($preRequisites)
{
$this->preRequisites = $preRequisites;
return $this;
}
/**
* Get preRequisites
*
* #return string
*/
public function getPreRequisites()
{
return $this->preRequisites;
}
/**
* Set picture
*
* #param string $picture
* #return ItemDetails
*/
public function setPicture($picture)
{
$this->picture = $picture;
return $this;
}
/**
* Get picture
*
* #return string
*/
public function getPicture()
{
return $this->picture;
}
/**
* Set acquiredKnowledges
*
* #param string $acquiredKnowledges
* #return ItemDetails
*/
public function setAcquiredKnowledges($acquiredKnowledges)
{
$this->acquiredKnowledges = $acquiredKnowledges;
return $this;
}
/**
* Get acquiredKnowledges
*
* #return string
*/
public function getAcquiredKnowledges()
{
return $this->acquiredKnowledges;
}
/**
* Set status
*
* #param integer $status
* #return ItemDetails
*/
public function setStatus($status)
{
$this->status = $status;
return $this;
}
/**
* Get status
*
* #return integer
*/
public function getStatus()
{
return $this->status;
}
/**
* Set course
*
* #param \Mooc\AdminBundle\Entity\Course $course
* #return ItemDetails
*/
public function setCourse(\Mooc\AdminBundle\Entity\Course $course = null)
{
$this->course = $course;
return $this;
}
/**
* Get course
*
* #return \Mooc\AdminBundle\Entity\Course
*/
public function getCourse()
{
return $this->course;
}
/**
* Add details
*
* #param \Mooc\TeacherBundle\Entity\ItemDetails $video
* #return Course
*/
public function addVideo(\Mooc\AdminBundle\Entity\Video $video)
{
$this->details[] = $video;
return $this;
}
/**
* Add details
*
* #param \Mooc\TeacherBundle\Entity\ItemDetails $video
* #return Course
*/
public function setVideo(\Mooc\AdminBundle\Entity\Video $video)
{
$this->video[] = $video;
return $this;
}
/**
* Remove details
*
* #param \Mooc\TeacherBundle\Entity\ItemDetails $video
*/
public function removeVideo(\Mooc\AdminBundle\Entity\Video $video)
{
$this->video->removeElement($video);
}
/**
* Get details
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getVideo()
{
return $this->video;
}
}
Video entity code :
namespace Mooc\AdminBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Video
*
* #ORM\Table(name="video")
* #ORM\Entity
*/
class Video
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var integer
*
* #ORM\Column(name="course_id", type="integer", nullable=false)
*/
private $courseId;
/**
* #var string
*
* #ORM\Column(name="video", type="string", length=255, nullable=false)
*/
private $video;
/**
* #var string
*
* #ORM\Column(name="description", type="text", nullable=false)
*/
private $description;
/**
* #ORM\ManyToOne(targetEntity="ItemDetails")
* #ORM\JoinColumn(name="course_id", referencedColumnName="id")
**/
private $itemDetails;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set courseId
*
* #param integer $courseId
* #return Video
*/
public function setCourseId($courseId)
{
$this->courseId = $courseId;
return $this;
}
/**
* Get courseId
*
* #return integer
*/
public function getCourseId()
{
return $this->courseId;
}
/**
* Set video
*
* #param string $video
* #return Video
*/
public function setVideo($video)
{
$this->video = $video;
return $this;
}
/**
* Get video
*
* #return string
*/
public function getVideo()
{
return $this->video;
}
/**
* Set description
*
* #param string $description
* #return Video
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set itemDetails
*
* #param \Mooc\AdminBundle\Entity\ItemDetails $itemDetails
* #return Video
*/
public function setItemDetails(\Mooc\AdminBundle\Entity\ItemDetails $itemDetails = null)
{
$this->itemDetails = $itemDetails;
return $this;
}
/**
* Get itemDetails
*
* #return \Mooc\AdminBundle\Entity\ItemDetails
*/
public function getItemDetails()
{
return $this->itemDetails;
}
}
Course form code :
namespace Mooc\AdminBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\HttpFoundation\Session\Session;
use Doctrine\ORM\EntityRepository;
class CourseType extends AbstractType
{
private $languageId;
public function __construct($languageId) {
$this->languageId=$languageId;
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$session = new Session();
$languageId=$session->get('languageId');
$builder
->add('languageId', 'entity', array(
'class' => 'MoocAdminBundle:Language',
'property' => 'name',
'preferred_choices' => array((object)$languageId),
))
->add('categoryId', 'entity', array(
'class' => 'MoocAdminBundle:CourseCategory',
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('u')
->where('u.languageId ='.$this->languageId);
},
))
->add('details', new ItemDetailsType())
->add('submit', 'submit', array('attr' => array('class' => 'btn btn-success btn-large')));
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Mooc\AdminBundle\Entity\Course'
));
}
/**
* #return string
*/
public function getName()
{
return 'mooc_adminbundle_course';
}
}
ItemDetails form :
namespace Mooc\AdminBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class ItemDetailsType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('startDate')
->add('endDate')
->add('description')
->add('preRequisites')
->add('picture','file')
->add('acquiredKnowledges')
->add('status')
->add('video', new VideoType())
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Mooc\AdminBundle\Entity\ItemDetails'
));
}
/**
* #return string
*/
public function getName()
{
return 'mooc_adminbundle_itemdetails';
}
}
video Form :
<?php
namespace Mooc\AdminBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class VideoType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('courseId')
->add('video','file')
->add('description','textarea')
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Mooc\AdminBundle\Entity\Video'
));
}
/**
* #return string
*/
public function getName()
{
return 'mooc_adminbundle_video';
}
}
Code in controller :
public function courseaddAction() {
$locale=$this->get('session')->get('_locale');
$language=$this->get('doctrine.orm.entity_manager')->getRepository('MoocAdminBundle:Language')->findBy(array('locale'=>$locale));
$languageId=$language[0]->getId();
$form=$this->createForm(new CourseType($languageId));
if ($this->getRequest()->isMethod("POST")) {
$form->HandleRequest($this->getRequest());
//if ($form->isValid()) {
$course = $form->getData();
$this->get('mooc.course')->addCourse($course);
//}
}
return $this->render('MoocTeacherBundle:Default:courseadd.html.twig', array('form'=>$form->createView(),'languageId'=>$languageId));
}
Code in service :
public function addCourse($course) {
$details=$course->getDetails();
$this->em->persist($course);
/*
foreach($course->getDetails() as $details) {
$details->setItemType('course');
$this->em->persist($details);
foreach($details->getVideo() as $video) {
$this->em->persist($video);
}
}
*/
$this->em->flush();
}

You need to set ItemId, in example from form:
$builder
->add('name')
->add('startDate')
->add('itemId') //add this line
->add('endDate')
->add('description')
->add('preRequisites')
->add('picture','file')
->add('acquiredKnowledges')
->add('status')
->add('video', new VideoType())
;
or change nullable value to true
/**
* #var integer
*
* #ORM\Column(name="item_id", type="integer", nullable=true) //here nullable to true
*/
private $itemId;

Related

Symfony relation OneToMany

I'm stuck with this problem. I try to upload one or more picture for one entity with a collection but when I submit my form I've got this error :
Symfony\Component\Validator\ConstraintViolation
Object(Symfony\Component\Form\Form).data.imagearticle[0].Article = null
It's because in my entity ImageArticle I put this :
namespace AD\PlatformBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\Validator\Constraints as Assert;
use AD\PlatformBundle\Entity\Article;
/**
* ImageArticle
*
* #ORM\Table()
* #ORM\Entity()
* #ORM\HasLifecycleCallbacks
*/
class ImageArticle
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="url", type="string", length=255)
*/
private $url;
/**
* #var string
*
* #ORM\Column(name="alt", type="string", length=255)
*/
private $alt;
/**
* #var File
*
* #Assert\File(
* maxSize = "1M",
* mimeTypes = {
* "image/jpeg",
* "image/gif",
* "image/png",
* },
* maxSizeMessage = "La taille maximum du fichier doit etre inférieur ou égale à 1MB. Pour reduire sa taille vous pouvez utiliser le site : compressjpeg.com",
* mimeTypesMessage = "Seulement les fichiers .jpeg / .gif /.png sont acceptés"
* )
*/
private $file;
private $tempFileName;
/**
* #var Article
* #ORM\ManyToOne(targetEntity="AD\PlatformBundle\Entity\Article", inversedBy="imagearticle")
* #ORM\JoinColumn(nullable=false)
* #Assert\NotNull()
*/
private $Article;
public function getFile()
{
return $this->file;
}
public function setFile(UploadedFile $file)
{
$this->file = $file;
if (null !== $this->url)
{
$this->tempFileName = $this->url;
$this->url=null;
$this->alt=null;
}
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set url
*
* #param string $url
*
* #return ImageArticle
*/
public function setUrl($url)
{
$this->url = $url;
return $this;
}
/**
* Get url
*
* #return string
*/
public function getUrl()
{
return $this->url;
}
/**
* Set alt
*
* #param string $alt
*
* #return ImageArticle
*/
public function setAlt($alt)
{
$this->alt = $alt;
return $this;
}
/**
* Get alt
*
* #return string
*/
public function getAlt()
{
return $this->alt;
}
/**
* #ORM\PrePersist()
* #ORM\PreUpdate()
*/
public function preUpload()
{
if (null === $this->file)
{
return;
}
//On add un extension pour le fichier.
$this->url = $this->file->guessExtension();
//Le alt est le nom du fichier du client.
$this->alt= $this->file->getClientOriginalName();
}
/**
*
* #ORM\PostPersist()
* #ORM\PostUpdate()
*
*/
public function upload()
{
if(null=== $this->file)
{
return;
}
//Si ancien fichier on supprime
if(null !== $this->tempFileName)
{
$oldFile = $this->getUploadRootDir().'/'.$this->id.'.'.$this->tempFileName;
if (file_exists($oldFile))
{
unlink($oldFile);
}
}
//On deplace
$this->file->move
(
$this->getUploadRootDir(),
$this->id.'.'.$this->url
);
// chmod($this->getUploadRootDir().'/'.$this->id.'.'.$this->url,644);
}
/**
*#ORM\PreRemove()
*/
public function preRemoveUpload()
{
$this->tempFileName = $this->getUploadRootDir().'/'.$this->id.'.'.$this->url;
}
/**
*
* #ORM\PostRemove()
*/
public function removeUpload()
{
if(file_exists($this->tempFileName))
{
unlink($this->tempFileName);
}
}
public function getUploadDir()
{
return 'upload/img/blog/';
}
protected function getUploadRootDir()
{
return __DIR__.'/../../../../web/'.$this->getUploadDir();
}
public function __toString()
{
return $this->getUploadDir().$this->id.'.'.$this->getUrl();
}
/**
* Set source
*
* #param string $source
*
* #return Image
*/
/**
* Set article
*
* #param \AD\PlatformBundle\Entity\Article $article
*
* #return ImageArticle
*/
public function setArticle(\AD\PlatformBundle\Entity\Article $article = null)
{
$this->article = $article;
return $this;
}
/**
* Get article
*
* #return \AD\PlatformBundle\Entity\Article
*/
public function getArticle()
{
dump($this->article);
return $this->article;
}
But when I remove this Assert\NotNull my error is "Column article_id cannot be null"
This is my Article entity :
<?php
namespace AD\PlatformBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Article
*
* #ORM\Table()
* #ORM\Entity
*/
class Article
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="titre1", type="string", length=255)
*/
private $titre1;
/**
* #var string
*
* #ORM\Column(name="titre2", type="string", length=255)
*/
private $titre2;
/**
* #var string
*
* #ORM\Column(name="description", type="text")
*/
private $description;
/**
* #ORM\ManyToMany(targetEntity="AD\UserBundle\Entity\User")
* #ORM\JoinColumn(nullable=false)
*/
private $user;
/**
*
* #ORM\OneToMany(targetEntity="AD\PlatformBundle\Entity\ImageArticle", mappedBy="article", cascade="all", orphanRemoval=true)
* #Assert\Valid()
* #ORM\OrderBy({"position" = "ASC"})
*
*/
private $imagearticle;
/**
* #Gedmo\Slug(fields={"titre1"})
* #ORM\Column(length=128, unique=true)
*/
private $slugurl;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set titre1
*
* #param string $titre1
*
* #return Article
*/
public function setTitre1($titre1)
{
$this->titre1 = $titre1;
return $this;
}
/**
* Get titre1
*
* #return string
*/
public function getTitre1()
{
return $this->titre1;
}
/**
* Set titre2
*
* #param string $titre2
*
* #return Article
*/
public function setTitre2($titre2)
{
$this->titre2 = $titre2;
return $this;
}
/**
* Get titre2
*
* #return string
*/
public function getTitre2()
{
return $this->titre2;
}
/**
* Set description
*
* #param string $description
*
* #return Article
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set user
*
* #param \AD\UserBundle\Entity\User $user
*
* #return Article
*/
public function setUser(\AD\UserBundle\Entity\User $user)
{
$this->user = $user;
return $this;
}
/**
* Get user
*
* #return \AD\UserBundle\Entity\User
*/
public function getUser()
{
return $this->user;
}
/**
* Set imagearticle
*
* #param \AD\PlatformBundle\Entity\ImageArticle $imagearticle
*
* #return Article
*/
public function setImagearticle(\AD\PlatformBundle\Entity\ImageArticle $imagearticle = null)
{
$this->imagearticle = $imagearticle;
return $this;
}
/**
* Get imagearticle
*
* #return \AD\PlatformBundle\Entity\ImageArticle
*/
public function getImagearticle()
{
return $this->imagearticle;
}
/**
* Constructor
*/
public function __construct()
{
$this->user = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Set slugurl
*
* #param string $slugurl
*
* #return Article
*/
public function setSlugurl($slugurl)
{
$this->slugurl = $slugurl;
return $this;
}
/**
* Get slugurl
*
* #return string
*/
public function getSlugurl()
{
return $this->slugurl;
}
/**
* Add user
*
* #param \AD\UserBundle\Entity\User $user
*
* #return Article
*/
public function addUser(\AD\UserBundle\Entity\User $user)
{
$this->user[] = $user;
return $this;
}
/**
* Remove user
*
* #param \AD\UserBundle\Entity\User $user
*/
public function removeUser(\AD\UserBundle\Entity\User $user)
{
$this->user->removeElement($user);
}
/**
* Add imagearticle
*
* #param \AD\PlatformBundle\Entity\ImageArticle $imagearticle
*
* #return Article
*/
public function addImagearticle(\AD\PlatformBundle\Entity\ImageArticle $imagearticle)
{
$this->imagearticle[] = $imagearticle;
return $this;
}
/**
* Remove imagearticle
*
* #param \AD\PlatformBundle\Entity\ImageArticle $imagearticle
*/
public function removeImagearticle(\AD\PlatformBundle\Entity\ImageArticle $imagearticle)
{
$this->imagearticle->removeElement($imagearticle);
}
}
Thx for your help!
My controller :
public function newArticleAction(Request $request)
{
$article= new Article();
$form = $this->get('form.factory')->create(new \AD\PlatformBundle\Form\ArticleType(), $article);
if($form->handleRequest($request)->isValid())
{
$em = $this->getDoctrine()->getManager();
$em->persist($article);
$em->flush();
$request->getSession()->getFlashBag()->add('notice', 'Annonce enregistrée ! :)');
return $this->redirect($this->generateUrl('va_platform_blog'));
}
return $this->render('ADPlatformBundle:Cars:newarticle.html.twig', array(
'form' =>$form->createView(),
));
}
And my form ArticleType :
class ArticleType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('titre1')
->add('titre2')
->add('description', 'textarea', array('required' => false))
->add('imagearticle', 'collection', array(
'type' => new ImageArticleType(),
'allow_add' => true,
'allow_delete' => true,
'required' => true,
'by_reference' => false,
))
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AD\PlatformBundle\Entity\Article'
));
}
/**
* #return string
*/
public function getName()
{
return 'ad_platformbundle_article';
}
}
ImageArticleType
namespace AD\PlatformBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class ImageArticleType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('file', 'file', array('label' => 'Choisir mon images'))
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AD\PlatformBundle\Entity\ImageArticle'
));
}
/**
* #return string
*/
public function getName()
{
return 'ad_platformbundle_imagearticle';
}
Here is the solution.
In ImageArticle.php:
/**
* #var Article
* #ORM\ManyToOne(targetEntity="AD\PlatformBundle\Entity\Article", inversedBy="imagearticle")
* #ORM\JoinColumn(nullable=false)
* #Assert\NotNull()
*/
private $article; //previously $Article
In Article.php:
/**
*
* #ORM\OneToMany(targetEntity="AD\PlatformBundle\Entity\ImageArticle", mappedBy="article", cascade="all", orphanRemoval=true)
* #Assert\Valid()
*
*/
private $imagearticle; // remove #ORM\OrderBy({"position" = "ASC"}) since there is no position property
public function __construct()
{
$this->user = new \Doctrine\Common\Collections\ArrayCollection();
$this->imagearticle = new \Doctrine\Common\Collections\ArrayCollection(); //instanciate as an ArrayCollection when a new instance of Article is created
}
/**
* Add imagearticle
*
* #param \AD\PlatformBundle\Entity\ImageArticle $imagearticle
*
* #return Article
*/
public function addImagearticle(\AD\PlatformBundle\Entity\ImageArticle $imagearticle)
{
$imagearticle->setArticle($this); //since doctrine only checks owning side you need to do this to keep data in sync
$this->imagearticle[] = $imagearticle;
return $this;
}
/**
* Remove imagearticle
*
* #param \AD\PlatformBundle\Entity\ImageArticle $imagearticle
*/
public function removeImagearticle(\AD\PlatformBundle\Entity\ImageArticle $imagearticle)
{
$imagearticle->setArticle(); //same reason than above
$this->imagearticle->removeElement($imagearticle);
return $this;
}
I also recommend you to remove method setImagearticle() since image article is a collection and not an object, you should not have to use it.
Use camelCase to name your variable and method (so it should be $imageArticle and not imagearticle) this is a good practice to make your code more readable by others.
Finally use plural when you are working with collections (i.e. users instead of user) so you immediatly know what you are working with (another good practice).

Expected value of type "SourcingBundle\Entity\RequestForEstimate" for association field

I get the following error:
Expected value of type "SourcingBundle\Entity\RequestForEstimate" for
association field
"SourcingBundle\Entity\RequestForEstimateDetail#$detail", got
"Doctrine\Common\Collections\ArrayCollection" instead.
I'm trying to create a structure where there is a RequestForEstimate entity that may have multiple RequestForEstimateDetails nodes. Simply each row in the RequestForEstimateDetails will have a request for a different product and its details when RequestForEstimate only the common information. I'm new to Symfony and I struggle at the point where I want to save the parent element together with the children in the DB. I have been following this Symfony tutorial: How to Embed a Collection of Forms
Here is my code:
SourcingBundle\Entity\RequestForEstimate:
<?php
namespace SourcingBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* RequestForEstimate
*
* #ORM\Table(name="request_for_estimate")
* #ORM\Entity(repositoryClass="SourcingBundle\Repository\RequestForEstimateRepository")
*/
class RequestForEstimate
{
/**
* #var int
*
* #ORM\Column(name="request_id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var int
*
* #ORM\Column(name="status", type="integer")
*/
private $status;
/**
* #var \DateTime
*
* #ORM\Column(name="create_time", type="datetime")
*/
private $createTime;
/**
* #var \DateTime
*
* #ORM\Column(name="update_time", type="datetime")
*/
private $updateTime;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #ORM\OneToMany(targetEntity="RequestForEstimateDetail", mappedBy="detail", cascade={"persist", "remove"}, orphanRemoval=true)
*/
private $details;
/**
* Get id
*
* #return int
*/
/**
* Constructor
*/
public function __construct()
{
$this->details = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set status
*
* #param integer $status
*
* #return RequestForEstimate
*/
public function setStatus($status)
{
$this->status = $status;
return $this;
}
/**
* Get status
*
* #return integer
*/
public function getStatus()
{
return $this->status;
}
/**
* Set createTime
*
* #param \DateTime $createTime
*
* #return RequestForEstimate
*/
public function setCreateTime($createTime)
{
$this->createTime = $createTime;
return $this;
}
/**
* Get createTime
*
* #return \DateTime
*/
public function getCreateTime()
{
return $this->createTime;
}
/**
* Set updateTime
*
* #param \DateTime $updateTime
*
* #return RequestForEstimate
*/
public function setUpdateTime($updateTime)
{
$this->updateTime = $updateTime;
return $this;
}
/**
* Get updateTime
*
* #return \DateTime
*/
public function getUpdateTime()
{
return $this->updateTime;
}
/**
* Set name
*
* #param string $name
*
* #return RequestForEstimate
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Add detail
*
* #param \SourcingBundle\Entity\RequestForEstimateDetail $detail
*
* #return RequestForEstimate
*/
public function addDetail(\SourcingBundle\Entity\RequestForEstimateDetail $detail)
{
$this->details[] = $detail;
return $this;
}
/**
* Remove detail
*
* #param \SourcingBundle\Entity\RequestForEstimateDetail $detail
*/
public function removeDetail(\SourcingBundle\Entity\RequestForEstimateDetail $detail)
{
$this->details->removeElement($detail);
}
/**
* Get details
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getDetails()
{
return $this->details;
}
}
SourcingBundle\Entity\RequestForEstimateDetail:
<?php
namespace SourcingBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* RequestForEstimateDetail
*
* #ORM\Table(name="request_for_estimate_detail")
* #ORM\Entity(repositoryClass="SourcingBundle\Repository\RequestForEstimateDetailRepository")
*/
class RequestForEstimateDetail
{
/**
* #var int
*
* #ORM\Column(name="request_detail_id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="RequestForEstimate", inversedBy="details")
* #ORM\JoinColumn(name="request_id", referencedColumnName="request_id")
*/
private $detail;
/**
* #var int
*
* #ORM\Column(name="product_id", type="integer")
*/
private $productId;
/**
* #var int
*
* #ORM\Column(name="quantity", type="integer")
*/
private $quantity;
/**
* #var string
*
* #ORM\Column(name="price_per_unit", type="decimal", precision=2, scale=0)
*/
private $pricePerUnit;
/**
* #var string
*
* #ORM\Column(name="shipping_cost", type="decimal", precision=2, scale=0)
*/
private $shippingCost;
/**
* #var string
*
* #ORM\Column(name="other_fees", type="decimal", precision=2, scale=0)
*/
private $otherFees;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set product
*
* #param integer $product
*
* #return RequestForEstimateDetail
*/
public function setProduct($product)
{
$this->product = $product;
return $this;
}
/**
* Get product
*
* #return int
*/
public function getProduct()
{
return $this->product;
}
/**
* Set quantity
*
* #param integer $quantity
*
* #return RequestForEstimateDetail
*/
public function setQuantity($quantity)
{
$this->quantity = $quantity;
return $this;
}
/**
* Get quantity
*
* #return int
*/
public function getQuantity()
{
return $this->quantity;
}
/**
* Set pricePerUnit
*
* #param string $pricePerUnit
*
* #return RequestForEstimateDetail
*/
public function setPricePerUnit($pricePerUnit)
{
$this->pricePerUnit = $pricePerUnit;
return $this;
}
/**
* Get pricePerUnit
*
* #return string
*/
public function getPricePerUnit()
{
return $this->pricePerUnit;
}
/**
* Set shippingCost
*
* #param string $shippingCost
*
* #return RequestForEstimateDetail
*/
public function setShippingCost($shippingCost)
{
$this->shippingCost = $shippingCost;
return $this;
}
/**
* Get shippingCost
*
* #return string
*/
public function getShippingCost()
{
return $this->shippingCost;
}
/**
* Set otherFees
*
* #param string $otherFees
*
* #return RequestForEstimateDetail
*/
public function setOtherFees($otherFees)
{
$this->otherFees = $otherFees;
return $this;
}
/**
* Get otherFees
*
* #return string
*/
public function getOtherFees()
{
return $this->otherFees;
}
/**
* Set requestId
*
* #param \SourcingBundle\Entity\RequestForEstimate $requestId
*
* #return RequestForEstimateDetail
*/
public function setRequestId(\SourcingBundle\Entity\RequestForEstimate $requestId = null)
{
$this->requestId = $requestId;
return $this;
}
/**
* Get requestId
*
* #return \SourcingBundle\Entity\RequestForEstimate
*/
public function getRequestId()
{
return $this->requestId;
}
/**
* Set productId
*
* #param \SourcingBundle\Entity\Product $productId
*
* #return RequestForEstimateDetail
*/
public function setProductId(\SourcingBundle\Entity\Product $productId = null)
{
$this->productId = $productId;
return $this;
}
/**
* Get productId
*
* #return \SourcingBundle\Entity\Product
*/
public function getProductId()
{
return $this->productId;
}
/**
* Set detail
*
* #param \SourcingBundle\Entity\RequestForEstimate $detail
*
* #return RequestForEstimateDetail
*/
public function setDetail(\SourcingBundle\Entity\RequestForEstimate $detail = null)
{
$this->detail = $detail;
return $this;
}
/**
* Get detail
*
* #return \SourcingBundle\Entity\RequestForEstimate
*/
public function getDetail()
{
return $this->detail;
}
/**
* Constructor
*/
public function __construct()
{
$this->detail = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add detail
*
* #param \SourcingBundle\Entity\RequestForEstimate $detail
*
* #return RequestForEstimateDetail
*/
public function addDetail(\SourcingBundle\Entity\RequestForEstimate $detail)
{
$this->detail[] = $detail;
return $this;
}
/**
* Remove detail
*
* #param \SourcingBundle\Entity\RequestForEstimate $detail
*/
public function removeDetail(\SourcingBundle\Entity\RequestForEstimate $detail)
{
$this->detail->removeElement($detail);
}
}
My controller:
<?php
namespace SourcingBundle\Controller;
use SourcingBundle\Entity\RequestForEstimate;
use SourcingBundle\Entity\RequestForEstimateDetail;
use SourcingBundle\Form\Type\RequestForEstimateType;
use SourcingBundle\Form\Type\RequestForEstimateDetailType;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
class RequestForEstimateController extends Controller
{
/**
* #Route("sourcing/request-for-estimate", name="request_for_estimate")
*/
public function addRequest(Request $request)
{
$RequestForEstimate = new RequestForEstimate();
$form = $this->createForm(RequestForEstimateType::class, $RequestForEstimate);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$request = $form->getData();
foreach($form->get('details')->getData() as $detail)
{
$request->addDetail($detail);
}
print_r($form->get('details')->getData());
$request->setStatus(0);
$request->setupdateTime(new \DateTime());
$request->setcreateTime(new \DateTime());
$em = $this->getDoctrine()->getManager();
$em->persist($request);
$em->flush();
return $this->redirectToRoute('RequestsForEstimate');
}
return $this->render('sourcing/requestforestimate/create.html.twig', array(
'form' => $form->createView(),
));
}
}
My forms:
<?php
namespace SourcingBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
class RequestForEstimateType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name');
$builder->add('details', CollectionType::class, array(
'entry_type' => RequestForEstimateDetailType::class,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
));
$builder->add('save', SubmitType::class, array('label' => 'Create Request'));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'SourcingBundle\Entity\RequestForEstimate',
));
}
}
<?php
namespace SourcingBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class RequestForEstimateDetailType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('quantity');
$builder->add('pricePerUnit');
$builder->add('shippingCost');
$builder->add('otherFees');
// $builder->add('product');
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'SourcingBundle\Entity\RequestForEstimateDetail',
));
}
}
In the RequestForEstimateDetail the getter/setter method of the field detail are for manage the collection itself (the add/remove methods are for the single element of the collection), so modify the getter/setter method to handle an ArrayCollection object.
As Example:
RequestForEstimateDetail
/**
* Set detail
*
* #param \Doctrine\Common\Collections\ArrayCollection an array of $detail
*
* #return RequestForEstimateDetail
*/
public function setDetail(\Doctrine\Common\Collections\ArrayCollection $detail = null)
{
$this->detail = $detail;
return $this;
}
/**
* Get detail
*
* #return \Doctrine\Common\Collections\ArrayCollection
*/
public function getDetail()
{
return $this->detail;
}
Hope this help
Well, the existing addDetail method in the RequestForEstimate entity did the trick:
public function addDetail(\SourcingBundle\Entity\RequestForEstimateDetail $detail)
{
$this->details->add($detail);
$detail->setDetail($this);
return $this;
}

symfony2: one-to-many relationship and embeded forms

I have these 3 entities below. Keep in mind that Pedido is like Order/Cart, and Subitem is like Product.
Pedido:
namespace Project\FrontendBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
//use Gedmo\Mapping\Annotation as Gedmo;
/**
* Project\FrontendBundle\Entity\Pedido
*
* #ORM\Table
* #ORM\Entity
* #ORM\HasLifecycleCallbacks
*/
class Pedido
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="pedidos")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=false)
**/
private $user;
/**
* #ORM\OneToMany(targetEntity="PedidoSubitem", mappedBy="pedido", cascade={"persist", "remove"})
**/
private $pedidoSubitems;
/**
* #ORM\Column(type="float", name="subtotal")
*/
private $subtotal;
/**
* #ORM\Column(type="float", name="iva")
*/
private $iva;
/**
* #ORM\Column(type="float", name="total")
*/
private $total;
/**
* #ORM\Column(type="text", length=5000, name="notas", nullable=true)
*
* #var text $notas
*/
private $notas;
/**
* #var \DateTime $created
*
* #ORM\Column(type="datetime")
*/
private $created;
/**
* #var \DateTime $updated
*
* #ORM\Column(type="datetime", nullable=true)
*/
private $updated;
/**
* #var \DateTime $contentChanged
*
* #ORM\Column(name="content_changed", type="datetime", nullable=true)
*/
private $contentChanged;
public function __construct() {
$this->pedidoSubitems = new ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set cliente
*
* #param \Project\FrontendBundle\Entity\Cliente $cliente
* #return Pedido
*/
public function setCliente(\Project\FrontendBundle\Entity\Cliente $cliente = null)
{
$this->cliente = $cliente;
return $this;
}
/**
* Get cliente
*
* #return \Project\FrontendBundle\Entity\Cliente
*/
public function getCliente()
{
return $this->cliente;
}
/**
* Add pedidoSubitems
*
* #param \Project\FrontendBundle\Entity\PedidoSubitem $pedidoSubitems
* #return Pedido
*/
public function addPedidoSubitem(\Project\FrontendBundle\Entity\PedidoSubitem $pedidoSubitems)
{
$this->pedidoSubitems[] = $pedidoSubitems;
return $this;
}
public function addPedido(\Project\FrontendBundle\Entity\Pedido $pedido)
{
$this->pedidoSubitems[] = $pedido;
}
/**
* Remove pedidoSubitems
*
* #param \Project\FrontendBundle\Entity\PedidoSubitem $pedidoSubitems
*/
public function removePedidoSubitem(\Project\FrontendBundle\Entity\PedidoSubitem $pedidoSubitems)
{
$this->pedidoSubitems->removeElement($pedidoSubitems);
}
/**
* Get pedidoSubitems
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getPedidoSubitems()
{
return $this->pedidoSubitems;
}
/**
* Set user
*
* #param \Project\FrontendBundle\Entity\User $user
* #return Pedido
*/
public function setUser(\Project\FrontendBundle\Entity\User $user)
{
$this->user = $user;
return $this;
}
/**
* Get user
*
* #return \Project\FrontendBundle\Entity\User
*/
public function getUser()
{
return $this->user;
}
/**
* Set notas
*
* #param string $notas
* #return Pedido
*/
public function setNotas($notas)
{
$this->notas = $notas;
return $this;
}
/**
* Get notas
*
* #return string
*/
public function getNotas()
{
return $this->notas;
}
/**
* Set created
*
* #param \DateTime $created
* #return Pedido
*/
public function setCreated($created)
{
$this->created = $created;
return $this;
}
/**
* Get created
*
* #return \DateTime
*/
public function getCreated()
{
return $this->created;
}
/**
* Set updated
*
* #param \DateTime $updated
* #return Pedido
*/
public function setUpdated($updated)
{
$this->updated = $updated;
return $this;
}
/**
* Get updated
*
* #return \DateTime
*/
public function getUpdated()
{
return $this->updated;
}
/**
* Set contentChanged
*
* #param \DateTime $contentChanged
* #return Pedido
*/
public function setContentChanged($contentChanged)
{
$this->contentChanged = $contentChanged;
return $this;
}
/**
* Get contentChanged
*
* #return \DateTime
*/
public function getContentChanged()
{
return $this->contentChanged;
}
/**
* #ORM\PrePersist
*/
public function doStuffOnPrePersist()
{
$this->created = new \DateTime("now");
}
/**
* #ORM\PreUpdate
*/
public function doStuffOnPreUpdate()
{
$this->updated = new \DateTime("now");
}
/**
* Set subtotal
*
* #param float $subtotal
* #return Pedido
*/
public function setSubtotal($subtotal)
{
$this->subtotal = $subtotal;
return $this;
}
/**
* Get subtotal
*
* #return float
*/
public function getSubtotal()
{
return $this->subtotal;
}
/**
* Set iva
*
* #param float $iva
* #return Pedido
*/
public function setIva($iva)
{
$this->iva = $iva;
return $this;
}
/**
* Get iva
*
* #return float
*/
public function getIva()
{
return $this->iva;
}
/**
* Set total
*
* #param float $total
* #return Pedido
*/
public function setTotal($total)
{
$this->total = $total;
return $this;
}
/**
* Get total
*
* #return float
*/
public function getTotal()
{
return $this->total;
}
}
PedidoSubitem:
namespace Project\FrontendBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Project\FrontendBundle\Entity\PedidoSubitem
*
* #ORM\Table
* #ORM\Entity(repositoryClass="Gedmo\Sortable\Entity\Repository\SortableRepository")
*/
class PedidoSubitem
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="Pedido", inversedBy="PedidoSubitems", cascade={"persist"})
* #ORM\JoinColumn(name="pedido_id", referencedColumnName="id")
**/
private $pedido;
/**
* #ORM\ManyToOne(targetEntity="Subitem", inversedBy="PedidoSubitems", cascade={"persist"})
* #ORM\JoinColumn(name="subitem_id", referencedColumnName="id")
**/
private $subitem;
/**
* #ORM\Column(type="integer", name="number", nullable=false)
*
* #var integer $number
*/
protected $number;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set pedido
*
* #param \Project\FrontendBundle\Entity\Pedido $pedido
* #return PedidoSubitem
*/
public function setPedido(\Project\FrontendBundle\Entity\Pedido $pedido = null)
{
$this->pedido = $pedido;
return $this;
}
/**
* Get pedido
*
* #return \Project\FrontendBundle\Entity\Pedido
*/
public function getPedido()
{
return $this->pedido;
}
/**
* Set subitem
*
* #param \Project\FrontendBundle\Entity\Subitem $subitem
* #return PedidoSubitem
*/
public function setSubitem(\Project\FrontendBundle\Entity\Subitem $subitem = null)
{
$this->subitem = $subitem;
return $this;
}
/**
* Get subitem
*
* #return \Project\FrontendBundle\Entity\Subitem
*/
public function getSubitem()
{
return $this->subitem;
}
/**
* Set integer
*
* #param integer $integer
* #return PedidoSubitem
*/
public function setInteger($integer)
{
$this->integer = $integer;
return $this;
}
/**
* Get integer
*
* #return integer
*/
public function getInteger()
{
return $this->integer;
}
/**
* Set number
*
* #param integer $number
* #return PedidoSubitem
*/
public function setNumber($number)
{
$this->number = $number;
return $this;
}
/**
* Get number
*
* #return integer
*/
public function getNumber()
{
return $this->number;
}
}
Subitem:
namespace Project\FrontendBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\Validator\Constraints as Assert;
//use Vich\UploaderBundle\Mapping\Annotation as Vich;
//use Gedmo\Mapping\Annotation as Gedmo;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Project\FrontendBundle\Entity\Subitem
*
* #ORM\Table
* #ORM\Entity
*/
class Subitem
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length=255, name="nombre")
*/
protected $nombre;
/**
* #ORM\OneToMany(targetEntity="PedidoSubitem", mappedBy="subitem")
**/
private $pedidoSubitems;
/**
* #var integer $position
*
* #ORM\Column(name="position", type="integer")
*/
private $position;
/**
* #ORM\Column(type="string", length=255, name="image_name", nullable=true)
*
* #var string $imageName
*/
protected $imageName;
/**
* #ORM\Column(type="boolean", name="activado", nullable=true)
*
* #var boolean $activado
*/
protected $activado = true;
/**
* #ORM\Column(type="datetime", nullable=true)
*
* #var \DateTime $updatedAt
*/
protected $updatedAt;
/**
* #ORM\Column(type="float", scale=2, name="precio", nullable=true)
*
* #var string $precio
*/
protected $precio;
/**
* #ORM\Column(length=128, unique=true)
*/
private $slug;
public function __construct() {
$this->products = new ArrayCollection();
$this->pedidoSubitems = new ArrayCollection();
}
public function __toString()
{
return $this->nombre;
}
public function getSlug()
{
return $this->slug;
}
/**
* Set position
*
* #param integer $position
* #return Subitem
*/
public function setPosition($position)
{
$this->position = $position;
return $this;
}
/**
* Get position
*
* #return integer
*/
public function getPosition()
{
return $this->position;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set tipo
*
* #param boolean $tipo
* #return Product
*/
public function setTipo($tipo)
{
$this->tipo = $tipo;
return $this;
}
/**
* Set imageName
*
* #param string $imageName
* #return Subitem
*/
public function setImageName($imageName)
{
$this->imageName = $imageName;
return $this;
}
/**
* Get imageName
*
* #return string
*/
public function getImageName()
{
return $this->imageName;
}
public function getImage()
{
return $this->image;
}
public function setImage($image)
{
$this->image = $image;
if($this->image) {
$this->updatedAt = new \DateTime('now');
}
}
/**
* Set updatedAt
*
* #param \DateTime $updatedAt
* #return Product
*/
public function setUpdatedAt($updatedAt)
{
$this->updatedAt = $updatedAt;
return $this;
}
/**
* Get updatedAt
*
* #return \DateTime
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}
/**
* Set nombre
*
* #param string $nombre
* #return Subitem
*/
public function setNombre($nombre)
{
$this->nombre = $nombre;
return $this;
}
/**
* Get nombre
*
* #return string
*/
public function getNombre()
{
return $this->nombre;
}
/**
* Set slug
*
* #param string $slug
* #return Subitem
*/
public function setSlug($slug)
{
$this->slug = $slug;
return $this;
}
/**
* Set activado
*
* #param boolean $activado
* #return Subitem
*/
public function setActivado($activado)
{
$this->activado = $activado;
return $this;
}
/**
* Get activado
*
* #return boolean
*/
public function getActivado()
{
return $this->activado;
}
/**
* Set item
*
* #param \Project\FrontendBundle\Entity\Item $item
* #return Subitem
*/
public function setItem(\Project\FrontendBundle\Entity\Item $item)
{
$this->item = $item;
return $this;
}
/**
* Get item
*
* #return \Project\FrontendBundle\Entity\Item
*/
public function getItem()
{
return $this->item;
}
/**
* Add pedidos
*
* #param \Project\FrontendBundle\Entity\Pedido $pedidos
* #return Subitem
*/
public function addPedido(\Project\FrontendBundle\Entity\Pedido $pedidos)
{
$this->pedidos[] = $pedidos;
return $this;
}
/**
* Remove pedidos
*
* #param \Project\FrontendBundle\Entity\Pedido $pedidos
*/
public function removePedido(\Project\FrontendBundle\Entity\Pedido $pedidos)
{
$this->pedidos->removeElement($pedidos);
}
/**
* Get pedidos
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getPedidos()
{
return $this->pedidos;
}
/**
* Set precio
*
* #param float $precio
* #return Subitem
*/
public function setPrecio($precio)
{
$this->precio = $precio;
return $this;
}
/**
* Get precio
*
* #return float
*/
public function getPrecio()
{
return $this->precio;
}
/**
* Add subitems
*
* #param \Project\FrontendBundle\Entity\PedidoSubitem $subitems
* #return Subitem
*/
public function addSubitem(\Project\FrontendBundle\Entity\PedidoSubitem $subitems)
{
$this->subitems[] = $subitems;
return $this;
}
/**
* Remove subitems
*
* #param \Project\FrontendBundle\Entity\PedidoSubitem $subitems
*/
public function removeSubitem(\Project\FrontendBundle\Entity\PedidoSubitem $subitems)
{
$this->subitems->removeElement($subitems);
}
/**
* Get subitems
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getSubitems()
{
return $this->subitems;
}
/**
* Add pedidoSubitems
*
* #param \Project\FrontendBundle\Entity\PedidoSubitem $pedidoSubitems
* #return Subitem
*/
public function addPedidoSubitem(\Project\FrontendBundle\Entity\PedidoSubitem $pedidoSubitems)
{
$this->pedidoSubitems[] = $pedidoSubitems;
return $this;
}
/**
* Remove pedidoSubitems
*
* #param \Project\FrontendBundle\Entity\PedidoSubitem $pedidoSubitems
*/
public function removePedidoSubitem(\Project\FrontendBundle\Entity\PedidoSubitem $pedidoSubitems)
{
$this->pedidoSubitems->removeElement($pedidoSubitems);
}
/**
* Get pedidoSubitems
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getPedidoSubitems()
{
return $this->pedidoSubitems;
}
}
And this type clases:
PedidoType:
namespace Project\FrontendBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Project\FrontendBundle\Form\PedidoSubitemType;
class PedidoType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('user')
//->add('pedidoSubitem', 'collection', array('type' => new PedidoSubitemType()))
->add('pedidoSubitems', new PedidoSubitemType())
->add('subtotal')
->add('iva')
->add('total')
->add('notas')
//->add('created')
//->add('updated')
//->add('contentChanged')
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Project\FrontendBundle\Entity\Pedido'
));
}
/**
* #return string
*/
public function getName()
{
return 'project_frontendbundle_pedido';
}
}
PedidoSubitemType:
namespace Project\FrontendBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class PedidoSubitemType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('number', 'text')
//->add('pedido')
->add('subitem', 'entity', array('class' => 'ProjectFrontendBundle:Subitem'))
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Project\FrontendBundle\Entity\PedidoSubitem'
));
}
/**
* #return string
*/
public function getName()
{
return 'project_frontendbundle_pedidosubitem';
}
}
I would like to show a form that creates a Pedido form with PedidoSubitem forms embeded.
As you can see in PedidoSubitem I have tried these two codes:
Case A
$builder
->add('user')
->add('pedidoSubitems', new PedidoSubitemType())
The fields related to PedidoSubitemType are shown correctly, but after submitting the form, I get:
Neither the property pedidoSubitems nor one of the methods
addPedidoSubitem(), removePedidoSubitem(), setPedidoSubitems(),
pedidoSubitems(), __set() or __call() exist and have public access in
class "Project\FrontendBundle\Entity\Pedido". (500 Internal
Server Error)
Case B
$builder
->add('user')
->add('pedidoSubitem', 'collection', array('type' => new PedidoSubitemType()))
But when rendering the form ({{ form(form) }}), the fields of PedidoSubitemType are not shown, but just this:
<div>
<label class="required">Pedido subitem</label>
<div id="project_frontendbundle_pedido_pedidoSubitem"></div>
</div>
You need to use Case A, that you've described above but rename field to pedidoSubitem. I mean:
$builder->add('pedidoSubitem', new PedidoSubitemType());
And probably you should rename entity's method addPedido() to addPedidoSubitem().

Why Symfony and Doctrine uses __toString instead of getId when inserting/updateing record

I have a form with 4 realtionships but have a problem with 2 of them.
Here is code for my form:
<?php
namespace Psw\AdminBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class MeatType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name_pl')
->add('name_en')
->add('jm')
->add('vat')
->add('net_price')
->add('min')
->add('new')
->add('promotion', 'entity', array(
'class' => 'PswAdminBundle:Promotions',
'empty_value' => 'No promotion',
'required' => false
))
->add('promotion_price')
->add('producer', 'entity', array(
'class' => 'PswAdminBundle:MeatProducers'
))
->add('animals')
->add('categories')
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Psw\AdminBundle\Entity\Meat'
));
}
public function getName()
{
return 'psw_adminbundle_meattype';
}
}
And entities
Meat:
<?php
namespace Psw\AdminBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Meat
*
* #ORM\Table()
* #ORM\Entity
*/
class Meat
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name_pl", type="string", length=255)
*/
private $name_pl;
/**
* #var string
*
* #ORM\Column(name="name_en", type="string", length=255)
*/
private $name_en;
/**
* #var string
*
* #ORM\Column(name="jm", type="string", length=10)
*/
private $jm;
/**
* #var integer
*
* #ORM\Column(name="vat", type="integer")
*/
private $vat;
/**
* #var float
*
* #ORM\Column(name="net_price", type="float")
*/
private $net_price;
/**
* #var float
*
* #ORM\Column(name="min", type="float")
*/
private $min;
/**
* #var boolean
*
* #ORM\Column(name="new", type="boolean")
*/
private $new;
/**
* #var integer
*
* #ORM\Column(name="promotion", type="integer", nullable=true)
* #ORM\ManyToOne(targetEntity="Promotions")
*/
private $promotion;
/**
* #var float
*
* #ORM\Column(name="promotion_price", type="float")
*
*/
private $promotion_price;
/**
* #ORM\ManyToMany(targetEntity="Animals")
* #ORM\JoinTable(name="meat_animals",
* joinColumns={#ORM\JoinColumn(name="meat_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="animal_id", referencedColumnName="id")}
* )
**/
private $animals;
/**
* #ORM\ManyToMany(targetEntity="MeatCategories")
* #ORM\JoinTable(name="meat_meat_categories",
* joinColumns={#ORM\JoinColumn(name="meat_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="category_id", referencedColumnName="id")}
* )
**/
private $categories;
/**
* #ORM\Column(name="producer", type="integer")
*
* #ORM\ManyToOne(targetEntity="MeatProducers", inversedBy="products")
* #ORM\JoinColumn(name="producer", referencedColumnName="id")
**/
private $producer;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name_pl
*
* #param string $namePl
* #return Meat
*/
public function setNamePl($namePl)
{
$this->name_pl = $namePl;
return $this;
}
/**
* Get name_pl
*
* #return string
*/
public function getNamePl()
{
return $this->name_pl;
}
/**
* Set name_en
*
* #param string $nameEn
* #return Meat
*/
public function setNameEn($nameEn)
{
$this->name_en = $nameEn;
return $this;
}
/**
* Get name_en
*
* #return string
*/
public function getNameEn()
{
return $this->name_en;
}
/**
* Set jm
*
* #param string $jm
* #return Meat
*/
public function setJm($jm)
{
$this->jm = $jm;
return $this;
}
/**
* Get jm
*
* #return string
*/
public function getJm()
{
return $this->jm;
}
/**
* Set vat
*
* #param integer $vat
* #return Meat
*/
public function setVat($vat)
{
$this->vat = $vat;
return $this;
}
/**
* Get vat
*
* #return integer
*/
public function getVat()
{
return $this->vat;
}
/**
* Set net_price
*
* #param float $netPrice
* #return Meat
*/
public function setNetPrice($netPrice)
{
$this->net_price = $netPrice;
return $this;
}
/**
* Get net_price
*
* #return float
*/
public function getNetPrice()
{
return $this->net_price;
}
/**
* Set min
*
* #param float $min
* #return Meat
*/
public function setMin($min)
{
$this->min = $min;
return $this;
}
/**
* Get min
*
* #return float
*/
public function getMin()
{
return $this->min;
}
/**
* Set new
*
* #param boolean $new
* #return Meat
*/
public function setNew($new)
{
$this->new = $new;
return $this;
}
/**
* Get new
*
* #return boolean
*/
public function getNew()
{
return $this->new;
}
/**
* Set promotion
*
* #param integer $promotion
* #return Meat
*/
public function setPromotion($promotion)
{
$this->promotion = $promotion;
return $this;
}
/**
* Get promotion
*
* #return integer
*/
public function getPromotion()
{
return $this->promotion;
}
/**
* Constructor
*/
public function __construct()
{
$this->animals = new ArrayCollection();
$this->categories = new ArrayCollection();
}
/**
* Add animals
*
* #param \Psw\AdminBundle\Entity\Animals $animals
* #return Meat
*/
public function addAnimal(\Psw\AdminBundle\Entity\Animals $animals)
{
$this->animals[] = $animals;
return $this;
}
/**
* Remove animals
*
* #param \Psw\AdminBundle\Entity\Animals $animals
*/
public function removeAnimal(\Psw\AdminBundle\Entity\Animals $animals)
{
$this->animals->removeElement($animals);
}
/**
* Get animals
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getAnimals()
{
return $this->animals;
}
/**
* Add categories
*
* #param \Psw\AdminBundle\Entity\Meat_categories $categories
* #return Meat
*/
public function addCategorie(\Psw\AdminBundle\Entity\Meat_categories $categories)
{
$this->categories[] = $categories;
return $this;
}
/**
* Remove categories
*
* #param \Psw\AdminBundle\Entity\Meat_categories $categories
*/
public function removeCategorie(\Psw\AdminBundle\Entity\Meat_categories $categories)
{
$this->categories->removeElement($categories);
}
/**
* Get categories
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getCategories()
{
return $this->categories;
}
/**
* Set producer
*
* #param \Psw\AdminBundle\Entity\MeatProducers $producer
* #return Meat
*/
public function setProducer(\Psw\AdminBundle\Entity\MeatProducers $producer = null)
{
$this->producer = $producer;
return $this;
}
/**
* Get producer
*
* #return \Psw\AdminBundle\Entity\MeatProducers
*/
public function getProducer()
{
return $this->producer;
}
/**
* Set promotion_price
*
* #param float $promotionPrice
* #return Meat
*/
public function setPromotionPrice($promotionPrice)
{
$this->promotion_price = $promotionPrice;
return $this;
}
/**
* Get promotion_price
*
* #return float
*/
public function getPromotionPrice()
{
return $this->promotion_price;
}
}
MeatProducers:
<?php
namespace Psw\AdminBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* MeatProducers
*
* #ORM\Table()
* #ORM\Entity
*/
class MeatProducers
{
/**
* #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)
*/
private $name;
/**
* #ORM\OneToMany(targetEntity="Meat", mappedBy="producer")
**/
private $products;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return MeatProducers
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
public function __toString()
{
return $this->name;
}
/**
* Constructor
*/
public function __construct()
{
$this->products = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add products
*
* #param \Psw\AdminBundle\Entity\Meat $products
* #return MeatProducers
*/
public function addProduct(\Psw\AdminBundle\Entity\Meat $products)
{
$this->products[] = $products;
return $this;
}
/**
* Remove products
*
* #param \Psw\AdminBundle\Entity\Meat $products
*/
public function removeProduct(\Psw\AdminBundle\Entity\Meat $products)
{
$this->products->removeElement($products);
}
/**
* Get products
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getProducts()
{
return $this->products;
}
}
There are no problems with many to many raltions on Animals and Categories.
But Promotions and Producers where i have many to one cause some issues.
Problem is that when trying to insert/update record doctrine calls __toString method instead of getId to obtain value to put into database.
I have working example like this with other entities, they are almost the same but in this case it just does not want to work.
Controller code is from crud generator, I didn't change anything there if necessary I may post it.
Question is how to make it use getId method?
The issue here is not with the __toString, it lies in your mapping annotation. You should not use #Column for association mappings. Instead, use #JoinColumn:
/**
* #ORM\ManyToOne(targetEntity="Promotions")
* #ORM\JoinColumn(name="promotion_id", referencedColumnName="id")
*/
private $promotion;

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