Symfony2 Form Mapping Issue - php

Im having issues with data mapping to an entity after it is submitted
The Entity:
<?php
namespace Site\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\EntityManager;
use JMS\Serializer\Annotation as Serializer;
use JMS\Serializer\Annotation\Groups;
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\Common\Collections\ArrayCollection;
/**
* UserAddress
*
* #ORM\Table(name="user_address")
* #ORM\Entity
*
* #Serializer\ExclusionPolicy("all")
* ---------- SERIALIZER GROUPS -----
* all -- All entries
*/
class UserAddress
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*
* #Serializer\Type("integer")
* #Serializer\Expose
* #serializer\SerializedName("ID")
* #serializer\Groups({"all"})
*/
public $ID;
/**
* #var integer
*
* #ORM\Column(name="user_id", type="integer", nullable=false)
*/
public $UserId;
/**
* #var integer
*
* #ORM\Column(name="level_id", type="integer", nullable=false)
*
* #Serializer\Type("integer")
* #Serializer\Expose
* #serializer\SerializedName("LevelId")
* #serializer\Groups({"all"})
*/
public $LevelId;
/**
* #var integer
*
* #ORM\Column(name="address_type_id", type="integer", nullable=false)
*
* #Serializer\Type("integer")
* #Serializer\Expose
* #serializer\SerializedName("AddressTypeId")
* #serializer\Groups({"all"})
*
* #Assert\NotBlank()
*/
public $AddressTypeId;
/**
* #var string
*
* #ORM\Column(name="address_data", type="text", nullable=false)
*
* #Serializer\Type("string")
* #Serializer\Expose
* #serializer\SerializedName("Address Data")
* #serializer\Groups({"all"})
*
* #Assert\NotBlank()
*/
public $AddressData;
/**
* #var integer
*
* #ORM\Column(name="public_yn", type="integer", nullable=false)
*
* #Serializer\Type("boolean")
* #Serializer\Expose
* #serializer\SerializedName("PublicYN")
* #serializer\Groups({"all"})
*
* #Assert\NotBlank()
*/
public $PublicYN;
/**
* #var integer
*
* #ORM\Column(name="primary_yn", type="integer", nullable=false)
*
* #Serializer\Type("boolean")
* #Serializer\Expose
* #serializer\SerializedName("PrimaryYN")
* #serializer\Groups({"all"})
*
* #Assert\NotBlank()
*/
public $PrimaryYN;
/**
* #ORM\ManyToOne(targetEntity="Site\UserBundle\Entity\UserMain", inversedBy="UserAddress")
* #ORM\JoinColumn(name="user_id", referencedColumnName="user_id")
*/
public $User;
/**
* #ORM\ManyToOne(targetEntity="Site\UserBundle\Entity\UserAddressType", inversedBy="UserAddress")
* #ORM\JoinColumn(name="address_type_id", referencedColumnName="address_type_id")
*
* #Serializer\Type("Site\UserBundle\Entity\UserAddressType")
* #Serializer\Expose
* #serializer\SerializedName("UserAddressType")
* #serializer\Groups({"all"})
*/
public $UserAddressType;
/**
* Get ID
*
* #return integer
*/
public function getID()
{
return $this->ID;
}
/**
* Set UserId
*
* #param integer $userId
* #return UserAddress
*/
public function setUserId($userId)
{
$this->UserId = $userId;
return $this;
}
/**
* Get UserId
*
* #return integer
*/
public function getUserId()
{
return $this->UserId;
}
/**
* Set LevelId
*
* #param integer $levelId
* #return UserAddress
*/
public function setLevelId($levelId)
{
$this->LevelId = $levelId;
return $this;
}
/**
* Get LevelId
*
* #return integer
*/
public function getLevelId()
{
return $this->LevelId;
}
/**
* Set AddressTypeId
*
* #param integer $addressTypeId
* #return UserAddress
*/
public function setAddressTypeId($addressTypeId)
{
$this->AddressTypeId = $addressTypeId;
return $this;
}
/**
* Get AddressTypeId
*
* #return integer
*/
public function getAddressTypeId()
{
return $this->AddressTypeId;
}
/**
* Set AddressData
*
* #param string $addressData
* #return UserAddress
*/
public function setAddressData($addressData)
{
$this->AddressData = $addressData;
return $this;
}
/**
* Get AddressData
*
* #return string
*/
public function getAddressData()
{
return $this->AddressData;
}
/**
* Set PublicYN
*
* #param integer $publicYN
* #return UserAddress
*/
public function setPublicYN($publicYN)
{
$this->PublicYN = $publicYN;
return $this;
}
/**
* Get PublicYN
*
* #return integer
*/
public function getPublicYN()
{
return $this->PublicYN;
}
/**
* Set PrimaryYN
*
* #param integer $primaryYN
* #return UserAddress
*/
public function setPrimaryYN($primaryYN)
{
$this->PrimaryYN = $primaryYN;
return $this;
}
/**
* Get PrimaryYN
*
* #return integer
*/
public function getPrimaryYN()
{
return $this->PrimaryYN;
}
/**
* Set User
*
* #param \Site\UserBundle\Entity\UserMain $user
* #return UserAddress
*/
public function setUser(\Site\UserBundle\Entity\UserMain $user = null)
{
$this->User = $user;
return $this;
}
/**
* Get User
*
* #return \Site\UserBundle\Entity\UserMain
*/
public function getUser()
{
return $this->User;
}
/**
* Set UserAddressType
*
* #param \Site\UserBundle\Entity\UserAddressType $userAddressType
* #return UserAddress
*/
public function setUserAddressType(\Site\UserBundle\Entity\UserAddressType $userAddressType = null)
{
$this->UserAddressType = $userAddressType;
return $this;
}
/**
* Get UserAddressType
*
* #return \Site\UserBundle\Entity\UserAddressType
*/
public function getUserAddressType()
{
return $this->UserAddressType;
}
}
The form is:
namespace Site\UserBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Doctrine\ORM\EntityRepository;
class UserAddressType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('UserId','hidden')
->add('LevelId', 'integer', array(
'label'=>'Sort Rate (Order)'
))
->add('AddressTypeId', 'entity', array(
'class'=>'SiteUserBundle:UserAddressType',
'query_builder'=> function(EntityRepository $er){
return $er->createQueryBuilder('t')
->orderBy('t.AddressDescription', 'ASC');
},
'property'=>'AddressDescription',
'label'=>'Address Type'
))
->add('AddressData', 'text')
->add('PublicYN', 'choice', array(
'choices' => array( 'false'=>'Private', 'true'=>'Public'),
'required'=>true,
'label'=>'Pubicly Visable'
))
->add('PrimaryYN', 'choice', array(
'choices' => array( 'false'=>'Secondary', 'true'=>'Primary'),
'required'=>true,
'label'=>'Primary Contact',
))
->add('save', 'submit', array(
'label'=>'Add Address',
'attr'=>array(
'class'=>'btn btn-primary',
),
))
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Site\UserBundle\Entity\UserAddress',
'csrf_protection'=>false,
));
}
/**
* #return string
*/
public function getName()
{
return 'Create_User_Address';
}
}
Controller Function is: (I'm using fosrestbundle)
public function newAddressAction($userid, Request $request)
{
$statusCode = 201;
$address = new UserAddress();
$address->setUserId($userid);
$form = $this->createForm( new UserAddressType(), $address, array(
'method'=>'GET',
));
$form->handleRequest($request);
if($form->isValid()){
$em = $this->getDoctrine()->getManager();
$em->persist($address);
$em->flush();
return new Response('User Added to system');
}
return $this->render('SiteUserBundle:UserAddress:newUserAddress.html.twig', array(
'form' => $form->createView(),
));
}
The Twig template is very simple. All the data is posted correctly to the server: (Query String Parameters )
Create_User_Address[LevelId]:0
Create_User_Address[AddressTypeId]:5
Create_User_Address[AddressData]:555-555-5555
Create_User_Address[PublicYN]:false
Create_User_Address[PrimaryYN]:false
Create_User_Address[save]:
Create_User_Address[UserId]:3
but i keep getting the following error:
An exception occurred while executing 'INSERT INTO user_address (user_id, level_id, address_type_id, address_data, public_yn, primary_yn) VALUES (?, ?, ?, ?, ?, ?)' with params [null, 0, null, "555-555-5555", "false", "false"]:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'user_id' cannot be null
As you can see the UserID and AddressTypeId fields are not mapping from the form to the Entity. I have looked over the code for all 3 pieces over and ove and for the life of me i can't see where the mismatch is happening. I did at one point change the names of those two fields in the Entity but i deleted all the getters and setters and regenerated them as well as clear the dev cache.
My hunch is there is a file somewhere in Symfony2 there is a mapping class that is wrong but i can't find it..
Thanks all
EDIT:
I tried clearing the doctrine cache as stated here: Symfony2 doctrine clear cache .
app/console doctrine:cache:clear-metadata
app/console doctrine:cache:clear-query
app/console doctrine:cache:clear-result
this resulted in the same error being generated,so the cache issue may be off the table.
EDIT:
As per Isaac's suggestion i removed ->add('UserId', 'hidden') . The form still posted with the same error message. The field is being generated correctly to the page;
<input type="hidden" id="Create_User_Address_UserId" name="Create_User_Address[UserId]" class=" form-control" value="3">
and as you can see from the Query Parameters above being posted back to the server correctly.
EDIT:
I tracked the issue down to the User and UserAddressType variables. If i remove these two variables and their getters and setters the form works perfectly without other modifications of my code. I should note that these two variables are joins to other entities. Some how they seem to be wiping out the data being submitted by the forms.

Remove
->add('UserId','hidden')
It's probably overwriting the UserId with null since it's hidden and has no value

As per lsouza suggestion I had to create a data transformer.
namespace Site\UserBundle\Form\DataTransformer;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;
use Doctrine\Common\Persistence\ObjectManager;
use Site\UserBundle\Entity\UserAddressType;
class AddressTypeToNumber implements DataTransformerInterface
{
/**
* #var ObjectManager
*/
private $om;
/**
* #param ObjectManager $om
*/
public function __construct(ObjectManager $om)
{
$this->om = $om;
}
/**
* Transforms an object(val) to a string
*
* #param UserAddressType|null $val
* #return string
*/
public function transform($val)
{
if (null === $val) {
return "";
}
return array();
}
/**
* Transfers a string to an object (UserAddressType)
*
* #param string $val
* #return UserAddressType|null
* #throws TransformationFailedException if object is not found
*/
public function reverseTransform($val)
{
if (!$val) {
return null;
}
$addId = $this->om
->getRepository('SiteUserBundle:UserAddressType')
->findOneBy(array('AddressTypeId' => $val));
if (null === $addId) {
throw new TransformationFailedException(sprintf(
'An Address Type with the ID of "%s" does not exsist in the system',
$val
));
}
return $addId;
}
}
Please note that the Transformer function is currently returning null but this should return a value that can be used by the form.
Some other notes that may help others are that the form class needs to be changed as well.
The setDefaultOptions function needs the following added to the $resolver variable:
->setRequired(array(
'em',
))
->setAllowedTypes(array(
'em'=>'Doctrine\Common\Persistence\ObjectManager',
));
The buildForm function needs to be changed slightly to accept the em option:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$em = $options['em'];
$transformer = new AddressTypeToNumber($em);
The field needs to be change to the varrable that holds the relationship in the Entity and not the field that is use in the link:
->add(
$builder->create('UserAddressType', 'entity', array(
'class' => 'SiteUserBundle:UserAddressType',
'property' => 'AddressDescription',
'label' => 'Address Type'
))
->addModelTransformer($transformer)
)
Finally in your controller you need to pass an instance of $this->getDoctrine()->getManager() to the form class:
$form = $this->createForm( new UserAddressType(), $address, array(
'em' => $this->getDoctrine()->getManager(),
));
I hope this helps others.

Related

upgrade symfony from 2.3 to 2.7 issues with form that do not retrieve the entity

I am retrieving the code of an old application that have not been updated for a few years now. Our sysadmin have put the code in a php7 server (it was working correctly on a php5 previously). The code worked quite good. I wanted to make some updates and the first one I did was to upgrade symfony from 2.3 to 2.7.*. And of course, now the problems arise.
I have a form that is correctly rendered (all the fields are OK even the ones from the database). Here is my builer:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('object','text',array(
"required"=>false,
"attr"=>array(
"placeholder"=>"Object"
)
))
->add('date','date',array(
'widget'=>'single_text',
))
->add('contact', 'entity', array(
'label'=>'Contact',
'class'=>'MyApp\AppliBundle\Entity\Contact',
'choice_translation_domain' => true,
'placeholder'=>'initials',
'choice_label' => 'initials',
'multiple'=>true
))
->add('text','redactor',array(
"required"=>false,
"redactor"=>"default"
))
;
}
Here is my controller:
public function editMeetingAction($id,Request $request)
{
$em = $this->getDoctrine()->getManager();
$meeting = $em->getRepository('MyAPPAppliBundle:Meeting')-
>findOneById($id);
$form = $this->createForm(new MeetingType, $meeting);
$form->handleRequest($request);
if ($form->isValid()) {
$em->persist($meeting);
$em->flush();
$this->get('session')->getFlashBag()->add('success', 'Meeting
edited successfully');
return $this->redirect($this-
>generateUrl('myapp_appli_manage_editmeeting', array("id" => $id)));
}
return array(
"form" => $form->createView(),
"id" => $id,
);
}
Now when I try to save the form, I have the following error:
[Syntax Error] line 0, col -1: Error: Expected Literal, got end of string.
[1/2] QueryException: SELECT e FROM MyApp\AppliBundle\Entity\Contact e WHERE
It seems that the app is not able to retrieve the Contact being selected in the form.
I have no idea what is wrong here as it worked correctly in the previous version. I followed the steps in this website to help me with the migration and modified already some fields in the form (placeholder, choices_as_values etc)
https://gist.github.com/mickaelandrieu/5211d0047e7a6fbff925
It would be much appreciated if you could help me.
[EDIT1]: the form was working properly before I updated symfony from 2.3 to 2.7
[EDIT2]: Entity Contact:
<?php
namespace MyApp\AppliBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\EntityRepository;
/**
* Contact
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="MyApp\AppliBundle\Entity\ContactRepository")
*/
class Contact
{
/**
* #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;
/**
* #var string
*
* #ORM\Column(name="Email", type="string", length=255)
*/
private $email;
/**
* #var string
*
* #ORM\Column(name="Initials", type="string", length=255)
*/
private $initials;
/**
* #var integer
*
* #ORM\Column(name="id_binome", type="integer")
*/
private $id_binome;
/**
* #var string
*
* #ORM\Column(name="JobTitles", type="string", length=255)
*/
private $jobtitle;
/**
* Tostring method
*
*/
public function __toString()
{
return $this->name;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Contact
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set email
*
* #param string $email
* #return Contact
*/
public function setEmail($email)
{
$this->email = $email;
return $this;
}
/**
* Get email
*
* #return string
*/
public function getEmail()
{
return $this->email;
}
/**
* Set initials
*
* #param string $initials
* #return Contact
*/
public function setInitials($initials)
{
$this->initials = $initials;
return $this;
}
/**
* Get initials
*
* #return string
*/
public function getInitials()
{
return $this->initials;
}
/**
* Get id_binome
*
* #return integer
*/
public function getIdBinome()
{
return $this->id_binome;
}
/**
* Set id_binome
*
* #param integer $id
* #return Contact
*/
public function setIdBinome($id)
{
$this->id_binome = $id;
return $this;
}
/**
* Get jobtitle
*
* #return string
*/
public function getjobtitle()
{
return $this->jobtitle;
}
/**
* Set jobtitle
*
* #param string $jobtitle
* #return Contact
*/
public function setjobtitle($jobtitle)
{
$this->jobtitle = $jobtitle;
return $this;
}
}
class ContactRepository extends EntityRepository
{
public function findEmailBinome($id_binome)
{
$querybuilder = $this->createQueryBuilder("Contact")
->select("Contact.email")
->where("Contact.id = :idbinome")
->setParameter('idbinome',$id_binome)
;
return $querybuilder
->getQuery()
->getSingleResult()
;
}
}
[EDIT getter setter]
/**
* Add contacts
*
* #param \MyApp\AppliBundle\Entity\Contact $contacts
* #return Meeting
*/
public function addContact(\MyApp\AppliBundle\Entity\Contact $contacts)
{
$this->contacts[] = $contacts;
return $this;
}
/**
* Remove contacts
*
* #param \MyApp\AppliBundle\Entity\Contact $contacts
*/
public function removeContact(\MyApp\AppliBundle\Entity\Contact $contacts)
{
$this->contacts->removeElement($contacts);
}
/**
* Get contacts
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getContacts()
{
return $this->contacts;
}
I think I found the solution. As it was a problem related to the db connection I suspected dotrine/orm to be guilty! I update the composer.json by changing :
"doctrine/orm": "=2.2.*"
to
"doctrine/orm": ">=2.2.3"
When I tried composer update doctrine/orm it did not solve the problem. However when I simply tried composer update then my app worked again.
Thanks a lot for your help

Unable to save data from a One To Many

I created a one to many relationship between a society and its employees. Everything worked great, I can see the user list when I'm editing the society page and I can select some of them, but the problem is that I can't save / persist those data, and i don't know why.
I tried a lot of things, like adding allow_add =>true or by_reference => false inside the FormType, but it doesn't work even though it still saves the rest of the form, such as the society's name and its address.
Here are the entities :
Societe.php
<?php
namespace SocieteBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Societe
*
* #ORM\Table(name="societe")
* #ORM\Entity(repositoryClass="SocieteBundle\Repository\SocieteRepository")
*/
class Societe
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="RaisonSociale", type="string", length=255, unique=true)
*/
private $raisonSociale;
/**
* #var string
*
* #ORM\Column(name="adresse", type="string", length=255, unique=true)
*/
private $adresse;
/**
* #ORM\OneToMany(targetEntity="UserBundle\Entity\User", mappedBy="entreprise", cascade={"persist"})
*/
private $salaries;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set raisonSociale
*
* #param string $raisonSociale
*
* #return Societe
*/
public function setRaisonSociale($raisonSociale)
{
$this->raisonSociale = $raisonSociale;
return $this;
}
/**
* Get raisonSociale
*
* #return string
*/
public function getRaisonSociale()
{
return $this->raisonSociale;
}
/**
* Set adresse
*
* #param string $adresse
*
* #return Societe
*/
public function setAdresse($adresse)
{
$this->adresse = $adresse;
return $this;
}
/**
* Get adresse
*
* #return string
*/
public function getAdresse()
{
return $this->adresse;
}
/**
* Constructor
*/
public function __construct()
{
$this->salaries = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add salary
*
* #param \UserBundle\Entity\User $salary
*
* #return Societe
*/
public function addSalary(\UserBundle\Entity\User $salary)
{
$this->salaries[] = $salary;
return $this;
}
/**
* Remove salary
*
* #param \UserBundle\Entity\User $salary
*/
public function removeSalary(\UserBundle\Entity\User $salary)
{
$this->salaries->removeElement($salary);
}
/**
* Get salaries
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getSalaries()
{
return $this->salaries;
}
/**
* Set salaries
* Something I tried, didn't work
*/
public function setSalaries($salaries)
{
$this->salaries = $salaries;
return $this;
}
}
User.php
<?php
namespace UserBundle\Entity;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="fos_user")
*/
class User extends BaseUser{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
* #ORM\Column(name="prenom", type="string", length=255, nullable=true)
*/
protected $prenom;
/**
* #var string
* #ORM\Column(name="nom", type="string", length=255, nullable=true)
*/
protected $nom;
/**
* #var string
* #ORM\Column(name="telephone", type="string", length=255, nullable=true)
*/
protected $telephone;
/**
* #ORM\OneToMany(targetEntity="MissionBundle\Entity\Mission", mappedBy="createur", cascade={"remove", "persist"})
*
*/
protected $post;
/**
* #ORM\ManyToOne(targetEntity="EcoleBundle\Entity\Ecole", inversedBy="representant", cascade={"persist"})
* #ORM\JoinColumn(name="ecole_id", referencedColumnName="id")
*/
protected $ecole;
/**
* #ORM\ManyToOne(targetEntity="SocieteBundle\Entity\Societe", inversedBy="salaries", cascade={"persist"})
* #ORM\JoinColumn(name="salaries_id", referencedColumnName="id")
*/
private $entreprise;
/**
* Set prenom
*
* #param string $prenom
*
* #return User
*/
public function setPrenom($prenom)
{
$this->prenom = $prenom;
return $this;
}
/**
* Get prenom
*
* #return string
*/
public function getPrenom()
{
return $this->prenom;
}
/**
* Set nom
*
* #param string $nom
*
* #return User
*/
public function setNom($nom)
{
$this->nom = $nom;
return $this;
}
/**
* Get nom
*
* #return string
*/
public function getNom()
{
return $this->nom;
}
/**
* Set telephone
*
* #param string $telephone
*
* #return User
*/
public function setTelephone($telephone)
{
$this->telephone = $telephone;
return $this;
}
/**
* Get telephone
*
* #return string
*/
public function getTelephone()
{
return $this->telephone;
}
/**
* Add post
*
* #param \MissionBundle\Entity\Mission $post
*
* #return User
*/
public function addPost(\MissionBundle\Entity\Mission $post)
{
$this->post[] = $post;
return $this;
}
/**
* Remove post
*
* #param \MissionBundle\Entity\Mission $post
*/
public function removePost(\MissionBundle\Entity\Mission $post)
{
$this->post->removeElement($post);
}
/**
* Get post
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getPost()
{
return $this->post;
}
/**
* Set post
*
* #param \Doctrine\Common\Collections\Collection $comments
*/
public function setDeskComment(\Doctrine\Common\Collections\Collection $post){
$this->post = $post;
}
/**
* Set ecole
*
* #param \EcoleBundle\Entity\Ecole $ecole
*
* #return User
*/
public function setEcole(\EcoleBundle\Entity\Ecole $ecole = null)
{
$this->ecole = $ecole;
return $this;
}
/**
* Get ecole
*
* #return \EcoleBundle\Entity\Ecole
*/
public function getEcole()
{
return $this->ecole;
}
/**
* Set entreprise
*
* #param \SocieteBundle\Entity\Societe $entreprise
*
* #return User
*/
public function setEntreprise(\SocieteBundle\Entity\Societe $entreprise = null)
{
$this->entreprise = $entreprise;
return $this;
}
/**
* Get entreprise
*
* #return \SocieteBundle\Entity\Societe
*/
public function getEntreprise()
{
return $this->entreprise;
}
}
SocieteType.php
<?php
namespace SocieteBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
//use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\OptionsResolver\OptionsResolver;
class SocieteType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('raisonSociale')
->add('adresse')
->add('salaries', null, array(
'by_reference' => false,
)
)
;
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'SocieteBundle\Entity\Societe'
));
}
}
SocieteController.php
<?php
namespace SocieteBundle\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use SocieteBundle\Entity\Societe;
use SocieteBundle\Form\SocieteType;
/**
* Societe controller.
*
* #Route("/societe")
*/
class SocieteController extends Controller
{
/**
* Lists all Societe entities.
*
* #Route("/", name="societe_index")
* #Method("GET")
*/
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$societes = $em->getRepository('SocieteBundle:Societe')->findAll();
return $this->render('societe/index.html.twig', array(
'societes' => $societes,
));
}
/**
* Creates a new Societe entity.
*
* #Route("/new", name="societe_new")
* #Method({"GET", "POST"})
*/
public function newAction(Request $request)
{
$societe = new Societe();
$form = $this->createForm('SocieteBundle\Form\SocieteType', $societe);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($societe);
$em->flush();
return $this->redirectToRoute('societe_show', array('id' => $societe->getId()));
}
return $this->render('societe/new.html.twig', array(
'societe' => $societe,
'form' => $form->createView(),
));
}
/**
* Finds and displays a Societe entity.
*
* #Route("/{id}", name="societe_show")
* #Method("GET")
*/
public function showAction(Societe $societe)
{
$deleteForm = $this->createDeleteForm($societe);
return $this->render('societe/show.html.twig', array(
'societe' => $societe,
'delete_form' => $deleteForm->createView(),
));
}
/**
* Displays a form to edit an existing Societe entity.
*
* #Route("/{id}/edit", name="societe_edit")
* #Method({"GET", "POST"})
*/
public function editAction(Request $request, Societe $societe)
{
$deleteForm = $this->createDeleteForm($societe);
$editForm = $this->createForm('SocieteBundle\Form\SocieteType', $societe);
$editForm->handleRequest($request);
if ($editForm->isSubmitted() && $editForm->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($societe);
$em->flush();
return $this->redirectToRoute('societe_edit', array('id' => $societe->getId()));
}
return $this->render('societe/edit.html.twig', array(
'societe' => $societe,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
));
}
/**
* Deletes a Societe entity.
*
* #Route("/{id}", name="societe_delete")
* #Method("DELETE")
*/
public function deleteAction(Request $request, Societe $societe)
{
$form = $this->createDeleteForm($societe);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->remove($societe);
$em->flush();
}
return $this->redirectToRoute('societe_index');
}
/**
* Creates a form to delete a Societe entity.
*
* #param Societe $societe The Societe entity
*
* #return \Symfony\Component\Form\Form The form
*/
private function createDeleteForm(Societe $societe)
{
return $this->createFormBuilder()
->setAction($this->generateUrl('societe_delete', array('id' => $societe->getId())))
->setMethod('DELETE')
->getForm()
;
}
}
Please tell me if you want me to add a file to the question, I'll edit it. Thank you in advance
edit: I can see the array with the user I selected if I dump the form content
In your SocieteType.php change:
->add('salaries', null, array(
'by_reference' => false,
)
to
->add('salaries', 'entity', array(
'class' => 'SocieteBundle\Entity\Societe',
'property' => 'raisonSociale',
)

Symfony - Integrity constraint violation: 1062 Duplicate entry

I tried to find an answer for my question but it was unsuccessful. I'm using Symfony (Ive been using it 2 months) and I have a problem when I want to make many to many relationship.
I have homes and I have services. One home can have a lot of services and one service can have a lot of homes. Everything is ok and I understand the way many to many works with the doctrine, i persisted all values before flush in my controller, but i always get this message:
An exception occurred while executing 'INSERT INTO homess_services (home_id, service_id) VALUES (?, ?)' with params [25, 7]:
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '25' for key 'home_id'
My codes are (home entity):
<?php
namespace Filip\SymfonyBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Filip\SymfonyBundle\FilipSymfonyBundle;
/**
* Home
*
* #ORM\Table(name="homes")
* #ORM\Entity
*
*
*/
class Home
{
/**
* #var ArrayCollection
*
* #ORM\ManyToMany(targetEntity="Service", inversedBy="homes")
* #ORM\JoinTable(name="homess_services")
*/
protected $services;
public function __construct() {
$this->photos = new ArrayCollection();
$this->services = new ArrayCollection();
}
/**
* Renders a publication as a string
*
* #return string
*/
public function __toString (){
return $this->getName();
}
/**
* Add services
*
* #param \Filip\SymfonyBundle\Entity\Service $services
* #return Home
*/
public function addService(\Filip\SymfonyBundle\Entity\Service $services)
{
$this->services[] = $services;
return $this;
}
/**
* Remove services
*
* #param \Filip\SymfonyBundle\Entity\Service $services
*/
public function removeService(\Filip\SymfonyBundle\Entity\Service $services)
{
$this->services->removeElement($services);
}
/**
* Get services
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getServices()
{
return $this->services;
}
Service entity:
<?php
namespace Filip\SymfonyBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Filip\SymfonyBundle\FilipSymfonyBundle;
/**
* Service
*
* #ORM\Table("services")
* #ORM\Entity
*/
class Service
{
/**
* #var ArrayCollection
*
* #ORM\ManyToMany(targetEntity="Home", mappedBy="services")
*/
protected $homes;
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM
\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="category", type="string", length=45)
*/
private $category;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=45)
*/
private $name;
/**
* Renders a service as a string
*
* #return string
*/
/**
* Get id
*
6
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set category
*
* #param string $category
* #return Service
*/
public function setCategory($category)
{
$this->category = $category;
return $this;
}
/**
* Get category
*
* #return string
*/
public function getCategory()
{
return $this->category;
}
/**
* Set name
*
* #param string $name
* #return Service
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
public function __construct()
{
$this->homes = new ArrayCollection();
}
/**
* Add homes
*
* #param \Filip\SymfonyBundle\Entity\Home $homes
* #return Service
*/
public function addHome(\Filip\SymfonyBundle\Entity\Home $homes)
{
$this->homes[] = $homes;
return $this;
}
/**
* Remove homes
*
* #param \Filip\SymfonyBundle\Entity\Home $homes
*/
public function removeHome(\Filip\SymfonyBundle\Entity\Home $homes)
{
$this->homes->removeElement($homes);
}
/**
* Get homes
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getHomes()
{
return $this->homes;
}
}
Form(HomeType):
<?php
namespace Filip\SymfonyBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class HomeType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('city')
->add('region')
->add('phone')
->add('address')
->add('email')
->add('website')
->add('content')
->add('youtubeApi')
->add('premium')
->add('services' , 'entity' , array(
'class' => 'FilipSymfonyBundle:Service' ,
'property' => 'name' ,
'expanded' => true ,
'multiple' => true ,
));
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Filip\SymfonyBundle\Entity\Home'
));
}
/**
* #return string
*/
public function getName()
{
return 'filip_symfonybundle_home';
}
}
Home controller:
/**
* Creates a new Home entity.
*
* #Route("/", name="home_create")
* #Method("POST")
* #Template("FilipSymfonyBundle:Home:new.html.twig")
*/
public function createAction(Request $request)
{
$entity = new Home();
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$services = $entity->getServices();
foreach($services as $service) {
$entity->addService($service);
$em->persist($service);
}
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('home_show', array('id' => $entity->getId())));
}
return array(
'entity' => $entity,
'form' => $form->createView(),
);
}
/**
* Creates a form to create a Home entity.
*
* #param Home $entity The entity
*
* #return \Symfony\Component\Form\Form The form
*/
private function createCreateForm(Home $entity)
{
$form = $this->createForm(new HomeType(), $entity, array(
'action' => $this->generateUrl('home_create'),
'method' => 'POST',
));
$form->add('submit', 'submit', array('label' => 'Create'));
return $form;
}
in the if($form->isValid()) part you don't need to call the addService() method in the foreach loop as Symfony will do this for you on the handleRequest() call.
If the Home entity is at the owning side of the ManyToMany relation you don't need to persist every Service object too. So you can try to remove the whole foreach loop too.

Symfony2 error on submitting form with a collection of forms - "Warning: spl_object_hash() expects parameter 1 to be object, array given"

I have an Employee class which has a OneToMany relation to the PhoneNumber class, and I'm using form builders, and using prototypes to embed multiple phone numbers into the New Employee form, with javascript.
From dumping my employee variable, I see that each submitted PhoneNumber is represented as an array, when I suppose it should be converted to a PhoneNumber object when the submitted data is processed.
My entitites are:
/**
* Employee
*
* #ORM\Table(uniqueConstraints={#UniqueConstraint(name="employee_username_idx", columns={"username"})})
* #ORM\Entity(repositoryClass="Acme\BambiBundle\Entity\EmployeeRepository")
*/
class Employee
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var array
*
* #OneToMany(targetEntity="PhoneNumber", mappedBy="employee", cascade={"persist","remove"}, fetch="EAGER")
**/
private $phoneNumbers;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Constructor
*/
public function __construct()
{
$this->phoneNumbers = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add phoneNumbers
*
* #param \Acme\BambiBundle\Entity\PhoneNumber $phoneNumbers
* #return Employee
*/
public function addPhoneNumber(\Acme\BambiBundle\Entity\PhoneNumber $phoneNumbers)
{
$phoneNumbers->setEmployee($this);
$this->phoneNumbers[] = $phoneNumbers;
return $this;
}
/**
* Remove phoneNumbers
*
* #param \Acme\BambiBundle\Entity\PhoneNumber $phoneNumbers
*/
public function removePhoneNumber(\Acme\BambiBundle\Entity\PhoneNumber $phoneNumbers)
{
$this->phoneNumbers->removeElement($phoneNumbers);
}
/**
* Get phoneNumbers
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getPhoneNumbers()
{
return $this->phoneNumbers;
}
// ...
}
and
/**
* PhoneNumber
*
* #ORM\Table()
* #ORM\Entity
*/
class PhoneNumber
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="type", type="text", nullable=true)
*/
private $type;
/**
* #var string
*
* #ORM\Column(name="number", type="text")
*/
private $number;
/**
* #var Employee
*
* #ManyToOne(targetEntity="Employee", inversedBy="phoneNumbers")
* #JoinColumn(name="employee_id", referencedColumnName="id", onDelete="CASCADE")
**/
private $employee;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set number
*
* #param string $number
* #return PhoneNumber
*/
public function setNumber($number)
{
$this->number = $number;
return $this;
}
/**
* Get number
*
* #return string
*/
public function getNumber()
{
return $this->number;
}
/**
* Set employee
*
* #param \Acme\BambiBundle\Entity\Employee $employee
* #return PhoneNumber
*/
public function setEmployee(\Acme\BambiBundle\Entity\Employee $employee = null)
{
$this->employee = $employee;
return $this;
}
/**
* Get employee
*
* #return \Acme\BambiBundle\Entity\Employee
*/
public function getEmployee()
{
return $this->employee;
}
/**
* Set type
*
* #param string $type
* #return PhoneNumber
*/
public function setType($type)
{
$this->type = $type;
return $this;
}
/**
* Get type
*
* #return string
*/
public function getType()
{
return $this->type;
}
}
My form types are:
class EmployeeType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('phoneNumbers', 'collection', array(
'type' => new PhoneNumberType(),
'allow_add' => true,
'allow_delete' => true,
'delete_empty' => true,
'prototype_name' => 'phoneNumberPrototype',
'by_reference' => false,
))
// ...
->add('save', 'submit', array('attr' => array('class' => 'btn btnBlue')));
}
public function getName() {
return 'employee';
}
}
and
class PhoneNumberType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('type', 'text', array('required' => false, 'label' => 'Type (optional)'))
->add('number', 'text');
}
public function getName() {
return 'phoneNumber';
}
}
Are there any things I could try to solve the problem? Is there anything that I am obviously doing wrong?
The solution was in a detail that I didn't know about - setting a data_class in the PhoneNumberType class:
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
'data_class' => 'Acme\BambiBundle\Entity\PhoneNumber',
));
}
Without this, the code that processes the data from the submitted form does not know that each phone number should be converted to a PhoneNumber class, and thus they stay as arrays.
Please bear in mind that I am using Symfony 2.6. In Symfony 2.7 the above function is called configureOptions and has a slightly different definition:
public function configureOptions(OptionsResolver $resolver) {

symfony2.3, persist related entity with foregin key

i'm looking for nice way to persist 2 objects to db via doctrine in symfony 2.3
class CatController extends Controller
{
/**
* Creates a new Cat entity.
*
*/
public function createAction(Request $request)
{
$entity = new Cat();
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity); <-- Split it or what ?
$em->flush();
return $this->redirect($this->generateUrl('cat_show', array('id' => $entity->getId())));
}
return $this->render('ViszmanCatBundle:Cat:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
));
}
when form is validated i can get post data and create 2 objects with that data but i think there should be clearer way to do this, above code is working not as i wanted, it only inserts foreign key to related entity when i do this:
class CatType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', 'text')
->add('meetings','collection',
array('type' => new MeetingType(),
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
)
);
}
class MeetingType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$plDays = array('Poniedziałek', 'Wtorek', 'Środa', 'Czwartek', 'Piątek', 'Sobota', 'Niedziela');
$builder
->add('meetingDay', 'choice', array('choices' => $plDays))
->add('meetingTime', 'time',)
->add('cat', 'entity', array('class' => 'ViszmanCatBundle:Cat', 'property' => 'name'))
;
}
entities: Cat
namespace Viszman\CatBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Cat
*
* #ORM\Table()
* #ORM\Entity
*/
class Congregation
{
/**
* #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="Viszman\CatBundle\Entity\Member", mappedBy="cat")
*/
private $members;
/**
* #ORM\OneToMany(targetEntity="Viszman\CatBundle\Entity\Meeting", mappedBy="cat", cascade={"persist"})
*/
private $meetings;
public function __construct(){
$this->members = new \Doctrine\Common\Collections\ArrayCollection();
$this->meetings = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Cat
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Add members
*
* #param \Viszman\CatBundle\Entity\Member $members
* #return Cat
*/
public function addMember(\Viszman\CatBundle\Entity\Member $members)
{
$this->members[] = $members;
return $this;
}
/**
* Remove members
*
* #param \Viszman\CatBundle\Entity\Member $members
*/
public function removeMember(\Viszman\CatBundle\Entity\Member $members)
{
$this->members->removeElement($members);
}
/**
* Get members
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getMembers()
{
return $this->members;
}
/**
* Add meetings
*
* #param \Viszman\CationBundle\Entity\Meeting $meetings
* #return Cat
*/
public function addMeeting(\Viszman\CatBundle\Entity\Meeting $meetings)
{
$this->meetings[] = $meetings;
return $this;
}
/**
* Remove meetings
*
* #param \Viszman\CatBundle\Entity\Meeting $meetings
*/
public function removeMeeting(\Viszman\CatBundle\Entity\Meeting $meetings)
{
$this->meetings->removeElement($meetings);
}
/**
* Get meetings
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getMeetings()
{
return $this->meetings;
}
namespace Viszman\CatBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Meeting
*
* #ORM\Table()
* #ORM\Entity
*/
class Meeting
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var integer
*
* #ORM\Column(name="meeting_day", type="smallint")
*/
private $meetingDay;
/**
* #var \DateTime
*
* #ORM\Column(name="meeting_time", type="time")
*/
private $meetingTime;
/**
* #ORM\ManyToOne(targetEntity="Viszman\CatBundle\Entity\Cat", inversedBy="meetings")
* #ORM\JoinColumn(name="cat_id", referencedColumnName="id")
*/
private $cat;
public function __construct()
{
$this->created = new \DateTime();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set meetingDay
*
* #param integer $meetingDay
* #return Meeting
*/
public function setMeetingDay($meetingDay)
{
$this->meetingDay = $meetingDay;
return $this;
}
/**
* Get meetingDay
*
* #return integer
*/
public function getMeetingDay()
{
return $this->meetingDay;
}
/**
* Set cat
*
* #param \Viszman\CatBundle\Entity\Cat $cat
* #return Member
*/
public function setCat(\Viszman\CatBundle\Entity\Cat $cat = null)
{
$this->cat = $cat;
return $this;
}
/**
* Get cat
*
* #return \stdClass
*/
public function getCat()
{
return $this->cat;
}
/**
* Set meetingTime
*
* #param \DateTime $meetingTime
* #return Meeting
*/
public function setMeetingTime($meetingTime)
{
$this->meetingTime = $meetingTime;
return $this;
}
/**
* Get meetingTime
*
* #return \DateTime
*/
public function getMeetingTime()
{
return $this->meetingTime;
}
this generate embedded form with unwanted data, meaning in Meeting section i need to choice Cat, but i dont want to, what i want is that meeting is on default attached to Cat on create, update. Do i need to change something in Cat or Meeting Entity? I don't know if i'm clear, sorry for my poor english
You need to remove this line in the MeetingType:
->add('cat', 'entity', array('class' => 'ViszmanCatBundle:Cat', 'property' => 'name'))
Then in yout Controller persist your Cat entity and yout Meeting entity (which you can find using cat's getMeetings method).
If you want both to be persisted in one shot, take a look at the cascade operation for Doctrine entities.

Categories