Symfony2 doctrine exception in persisting OneToMany entities - php

I configure this entities:
MarketMain:
class MarketMain
{
/**
* #var integer
*
* #ORM\Column(name="id", type="bigint", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\OneToMany(targetEntity="\Acme\CMSBundle\Entity\MarketLanguage", mappedBy="marketMain", indexBy="langId", cascade="all", orphanRemoval=true, fetch="EXTRA_LAZY")
*/
private $marketLanguage;
}
MarketLanguage:
class MarketLanguage
{
/**
* #var \Acme\CMSBundle\Entity\MarketMain
* #ORM\Id
* #ORM\ManyToOne(targetEntity="\Acme\CMSBundle\Entity\MarketMain", inversedBy="marketLanguage")
* #ORM\JoinColumn(name="market_id", referencedColumnName="id")
*/
private $marketMain;
/**
* #var integer
*
* #ORM\Id
* #ORM\Column(name="lang_id", type="integer", nullable=false)
*/
private $langId = 1;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=200, nullable=true)
*/
private $name;
}
And I want to save entity like this:
...........
$form = $this->createForm(new MarketMainType(), new MarketMain());
$form->handleRequest($request);
$marketFormData = $form->getData();
$em->persist($marketFormData);
$em->flush($marketFormData);
foreach ($marketFormData->getMarketLanguage() as $market_language)
{
$market_language->setName("My market name");
$market_language->setMarketMain($marketFormData);
$em->persist($market_language);
}
$em->flush();
Than I get this error:
Entity of type Acme\CMSBundle\Entity\MarketLanguage is missing an
assigned ID for field 'marketMain'. The identifier generation strategy
for this entity requires the ID field to be populated before
EntityManager#persist() is called. If you want automatically generated
identifiers instead you need to adjust the metadata mapping
accordingly.
If I trying to do $marketFormData persist after foreach statment I get this error:
Entity of type Acme\CMSBundle\Entity\MarketLanguage has identity
through a foreign entity Acme\CMSBundle\Entity\MarketMain, however
this entity has no identity itself. You have to call
EntityManager#persist() on the related entity and make sure that an
identifier was generated before trying to persist
'Acme\CMSBundle\Entity\MarketLanguage'. In case of Post Insert ID
Generation (such as MySQL Auto-Increment or PostgreSQL SERIAL) this
means you have to call EntityManager#flush() between both persist
operations.
I know that If I try to persist $marketFormData before loop doctrine does not know the releated $marketLanguage references, but if I set persist after the foreach it says taht I have first persist parent entity. So I tried this code and it worked:
...........
$form = $this->createForm(new MarketMainType(), new MarketMain());
$form->handleRequest($request);
$marketFormData = $form->getData();
$market_languages = $marketFormData->getMarketLanguage();
$marketFormData->setMarketLanguage(null);
$em->persist($marketFormData);
$em->flush($marketFormData);
$marketFormData->setMarketLanguage($market_languages);
foreach ($marketFormData->getMarketLanguage() as $market_language)
{
$market_language->setName("My market name");
$market_language->setMarketMain($marketFormData);
$em->persist($market_language);
}
$em->flush();
But it is only way to persist related entities? To clone it set to null, persist parent entity, and then set it back, add references and flush all. I think I have missed something here.

I think that your entities is mapped wrong. The entity must have an annotation about ID and another to relation.
And also, when you don't have a primary key with autoincrement, it is necessary declare the class constructor, passing both values as mentioned in http://doctrine-orm.readthedocs.org/en/latest/tutorials/composite-primary-keys.html
It should look like this:
class MarketLanguage
{
/**
* #var integer
*
* #ORM\Id
* #ORM\Column(name="market_id", type="integer", nullable=false)
*/
private $marketId;
/**
* #var integer
*
* #ORM\Id
* #ORM\Column(name="lang_id", type="integer", nullable=false)
*/
private $langId = 1;
/**
* #var \Acme\CMSBundle\Entity\MarketMain
*
* #ORM\ManyToOne(targetEntity="\Acme\CMSBundle\Entity\MarketMain", inversedBy="marketLanguage")
* #ORM\JoinColumn(name="market_id", referencedColumnName="id")
*/
private $marketMain;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=200, nullable=true)
*/
private $name;
public function __construct($marketId, $langId) {
$this->marketId = $marketId;
$this->langId = $langId;
}
}

Did you try remove flush($marketFormData) ?:
$form = $this->createForm(new MarketMainType(),$marketMain);
$form->handleRequest($request);
$marketFormData = $form->getData();
$em->persist($marketFormData);
// $em->flush($marketFormData); // remove that flush
foreach ($marketFormData->getMarketLanguage() as $market_language)
{
$market_language->setName("My market name");
$market_language->setMarketMain($marketMain);
$em->persist($market_language);
}
$em->flush();
maybe problem is that you are trying flush $marketFormData which contains MarketLanguages which are not persised ? Not sure am i right, didn't tested this.
EDIT maybe this work:
$form = $this->createForm(new MarketMainType(), new MarketMain());
$form->handleRequest($request);
$marketFormData = $form->getData();
foreach ($marketFormData->getMarketLanguage() as $market_language)
{
$market_language->setName("My market name");
$market_language->setMarketMain($marketMain);
}
$em->persist($marketFormData);
$em->flush($marketFormData);

Related

Symfony: The given entity of type cannot be added to the identity map

I am getting the following exception whilst trying to persist a entity and associative entity to the database. Not sure what i'm doing wrong here:
Exception:
The given entity of type 'AppBundle\Entity\User'
(AppBundle\Entity\User#0000000065c3019f00000000123d7c75) has no
identity/no id values set. It cannot be added to the identity map.
Entities:
/**
* #ORM\Entity
*/
class User
{
/**
* #ORM\Column(type="string")
*/
private $name;
/**
* #ORM\OneToOne(targetEntity="Address", inversedBy="user")
* #ORM\JoinColumn(name="address_id", referencedColumnName="id")
* #ORM\Id
*/
protected $address;
}
/**
* #ORM\Entity
*/
class Address
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
*/
private $id
/**
* #ORM\OneToOne(targetEntity="User", mappedBy="address", cascade={"all"}, fetch="LAZY")
*/
private $user;
}
Entity creation:
$user = new User();
$address = new Address();
$address->setUser($user->setAddress($address));
$this->getDoctrine()->getManager()->persist($user);
$this->getDoctrine()->getManager()->persist($address);
$this->getDoctrine()->getManager()->flush();
Please see: Doctrine OneToOne identity through foreign entity exception on flush which helped to resolve this issue.
The actual object address needs to be saved by the EntityManager first. Just giving the class as reference to the other class does not make the entityManager aware of the fact both classes exists. With this in mind, the following code allows me to persist these objects to the database. I belive this is because doctrine needs to persist the address object first, so that it can retrieve the id for the primary & foreign key relationship in the User object.
$user = new User();
$address = new Address();
$this->getDoctrine()->getManager()->persist($address);
$this->getDoctrine()->getManager()->flush();
$address->setUser($user->setAddress($address));
$this->getDoctrine()->getManager()->persist($user);
$this->getDoctrine()->getManager()->flush();
You MUST specify an ID for doctrine entity
like this:
class User
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string")
*/
private $name;
/**
* #ORM\OneToOne(targetEntity="Address", inversedBy="user")
* #ORM\JoinColumn(name="address_id", referencedColumnName="id")
* #ORM\Id
*/
protected $address;
}

Symfony 3 error : Case mismatch between loaded and declared class names

i've just got this error
Case mismatch between loaded and declared class names: MyApp\UserBundle\Entity\post vs MyApp\UserBundle\Entity\Post
i'm using two controllers to do a specific operation of delete and getting back to the old page
here is my button's code
<a href="{{ path('DeleteComment',{'idc':comment.id}) }}"> <i
class="icon-trash"></i>Delete</a>
here is my routing's code :
get_view_post:
path: /blog/get/one/post/{id}/
defaults: { _controller: "MyAppBlogBundle:Blog:getpost" }
DeleteComment:
path: /blog/post/comment/delete/{idc}/
defaults: { _controller: "MyAppBlogBundle:Blog:DeleteComment" }
here is my controllers code :
public function DeleteCommentAction($idc)
{
$em = $this->getDoctrine()->getManager();
$comment = $em->getRepository('MyAppUserBundle:PostComment')->find($idc);
$idPost =$comment->getIdPost();
$em->remove($comment);
$em->flush();
return $this->redirectToRoute("get_view_post", array('id' => $idPost));
}
public function getpostAction($id)
{
$user = $this->getUser();
$idu = $user->getId();
$em = $this->getDoctrine()->getManager();
$em1 = $this->getDoctrine()->getManager();
$post = $em->getRepository('MyAppUserBundle:Post')->find($id);
$idPost=$post->getId();
$comment = $em1->getRepository('MyAppUserBundle:PostComment')->findBy(array('idPost' => $idPost));
return $this->render('MyAppBlogBundle::afficherPostAvecComment.html.twig', array('posts' => $post,'comments'=>$comment,'idu'=>$idu));
}
i'm declaring my entities like this :
use MyApp\UserBundle\Entity\Post;
use MyApp\UserBundle\Entity\PostComment;
Here is my Entity
namespace MyApp\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="post")
*/
class Post
{
/**
* #var integer
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
* #ORM\Column(name="titre", type="string", length=100, nullable=false)
*/
private $titre;
/**
* #var string
* #ORM\Column(name="contenu", type="string", length=250, nullable=false)
*/
private $contenu;
/**
* #var \DateTime
* #ORM\Column(name="dateajout", type="datetime", nullable=true)
*/
private $dateajout ;
/**
* #var integer
* #ORM\ManyToOne(targetEntity="User")
* #ORM\JoinColumn(name="id_utilisateur",referencedColumnName="id")
*/
private $idUser;
/**
* #var integer
* #ORM\Column(name="nbLike", type="integer", nullable=true)
*/
private $nbLike =0;
/**
* #var integer
* #ORM\Column(name="nbDislike", type="integer", nullable=true)
*/
private $nbDislike=0;
/**
* #var integer
* #ORM\Column(name="nbSignal", type="integer", nullable=true)
*/
private $nbSignal=0;
i did some changes in my code, as i see My IDE couldn't differentiate
between Post, PostComment and my array post or furthermore his own method of recuperation _POST.
you can see from the error above that it's based on hesitation between Post and post ,if you are using a latest version of Symfony, try to scan you whole project and change the names of your attributes or classes, believe it or not it creates some difficulties for the IDE when your project gets bigger
and here is what made the error gone:
old
/**
* #var integer
* #ORM\ManyToOne(targetEntity="post")
* #ORM\JoinColumn(name="id_post",referencedColumnName="id")
*/
private $idPost;
new
/**
* #var integer
* #ORM\ManyToOne(targetEntity="Post")
* #ORM\JoinColumn(name="id_post",referencedColumnName="id")
*/
private $idPost;
I was not giving the appropriate name of my Entity, so when I do any operation based on foreign keys, the IDE won't find any Entity of reference
if you are using and old version of Symfony, you have to add a line of code in some file's configuration
you can have a better explanation here:
Symfony2 error : Case mismatch between loaded and declared class names:
Once have look on the folder name of your userbundle file.
Since, you have mentioned UserBunlde in your namespace **(namespace MyApp\UserBundle\Entity;) then,
Your folder name must be UserBundle too.
If you have named as userBundle so that such error occurs.

Symfony find field

I have a Developers entity and table named CodeUserReference
class CodeUserReference
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
*#ORM\ManyToOne(targetEntity="Artel\CustomerBundle\Entity\Developers", inversedBy="newreference")
*/
protected $alluser;
/**
* #ORM\Column(type="string", length=255)
*/
protected $codereference;
and Developers
class Developers extends SUser
{
/**
* #var string
*
* #ORM\Column(name="email", type="string", length=255, unique=false, nullable=false)
* #Assert\Length(min=3, max=255)
* #Assert\NotBlank
*/
protected $email;
/**
* #ORM\ManyToMany(targetEntity="Artel\CustomerBundle\Entity\CodeUserReference", inversedBy="alluser")
*/
protected $newreference;
I have get query in my Action
public function profileGetAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$code_user_reference = $em->getRepository('ArtelCustomerBundle:CodeUserReference')->findOneByCodereference($request->query->get('reference'));
$user_by_email = $em->getRepository('ArtelCustomerBundle:Developers')->findOneByEmail($request->query->get('email'));
if (!empty($code_user_reference) && empty($user_by_email))
{
$id = $code_user_reference->getAlluser()->getId();
$user_by_reference = $em->getRepository('ArtelCustomerBundle:Developers')->findOneById($id);
$user_by_reference_json = $em->getRepository('ArtelCustomerBundle:Developers')->createQueryBuilder('d')
->where('d.id= :id')
->groupBy('d.id')
->setParameter('id', $code_user_reference->getAlluser()->getId())
->getQuery()->getArrayResult();
echo json_encode( array('user' => $user_by_reference_json));
die;
}
If(empty($code_user_reference) && !empty($user_by_email))
.......
I get Id in code_user_reference, then I find Developers objects with this ID, then I create a QueryBuilder and in this QueryBuilder I find the developers objects again, for JSON table. I find this very hard, who knows easier practics ?
There is certanly mismapping.
if you have #ORM\ManyToOne from one site, there should be #ORM\OneToMany from other.
Or, if you need many-to-many relationship, there should be #ORM\ManyToMany on both entities.
Also, relation should be mapped at one side. If you have (targetEntity="Artel\CustomerBundle\Entity\Developers", inversedBy="newreference") it means it should be mapped here
something like
#ORM\ManyToOne(targetEntity="Artel\CustomerBundle\Entity\Developers", inversedBy="newreference")
#ORM\JoinColumn(name="id_developer", referencedColumnName="id")
and at the other side must be mappedBy instead of inversedBy
* #ORM\OneToMany(targetEntity="Artel\CustomerBundle\Entity\CodeUserReference", mappedBy="alluser")

Reference ID not updated with Doctrine association

There is probably something I did understand with Doctrine association.
I have a first class :
class FitComments
{
/**
* #var integer
*
* #ORM\Column(name="ID", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="SEQUENCE")
* #ORM\SequenceGenerator(sequenceName="SEQ_FIT_COMMENTS", allocationSize=1, initialValue=1)
*/
private $id;
/**
*
* #ORM\OneToMany(targetEntity="FitCommentsId",mappedBy="comments",cascade={"persist"})
*
*/
private $elements;
/****/
public function __construct()
{
$this->elements=new ArrayCollection();
}
public function getElements()
{
return $this->elements;
}
....
}
And a another Class, the list of elements ID that the comments is link.
/**
* FitCommentsId
* #ORM\Entity
*/
class FitCommentsId
{
/**
* #var integer
*
* #ORM\Column(name="ID", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="SEQUENCE")
* #ORM\SequenceGenerator(sequenceName="SEQ_FIT_COMMENTS_ID", allocationSize=1, initialValue=1)
*/
private $id;
/**
*
* #ORM\ManyToOne(targetEntity="FitComments",inversedBy="elements")
* #ORM\JoinColumn(name="COMMENTS_ID",referencedColumnName="ID")
*/
private $comments;
....
}
I use :
$comments=new FitComment();
$commentId=new FitCommentId();
....
$comments->getElements()->add($commentId);
....
$entityManager->persist($comment);
$entityManager->flush();
But I have a error. $commentId->comments is null. It must be filled with $comment->id normally.
If I must filled manually $commentId->comments, association is not very usefull.
Perhaps I don't understand mechanism.
Note : the SGDB is Oracle.
Try persisting the $commentId also like this:
$comment = new FitComment();
$commentId = new FitCommentId();
....
$comment->getElements()->add($commentId);
....
$entityManager->persist($commentId);
$entityManager->persist($comment);
$entityManager->flush();
No I can't do a 'persist' to $commentId first, because 'persist' to $comment class initiate Oracle sequence for the Id of $comments. (I'm not sure it's very clean what I say....)
'commentID->comments' is link to 'comment->id', and is not null.
I must create $comment at first, and after, create the $commentId.
I know that Doctrine use Sequence before saving record, in persist command. Perhaps I can do a persist without flush at first, and at the end of $commentId recording, do a flush.

Doctrine inserting null for #ID field

I have a user object I am trying to insert via Doctrine.
The key fields are
/**
* #ORM\Column(type="integer", name="id")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $userId;
/**
* #ORM\Id
* #ORM\Column(type="string", name="login_name")
*/
private $loginName;
/**
* #ORM\Column(type="string", name="display_name")
*/
private $name;
In my controller code I can echo out the value of the $loginName field via the getLoginName() method on the object.
/**
* #param mixed $loginName
*/
public function setLoginName($loginName)
{
$this->loginName = $loginName;
}
/**
* #return mixed
*/
public function getLoginName()
{
return $this->loginName;
}
You can see the Controller code to do the insert here.
if ($request->getMethod() == 'POST') {
$form->bind($request);
$login = $form->getData();
$factory = $this->get('security.encoder_factory');
echo($login->getLoginName());
$encoder = $factory->getEncoder($login);
$login->setPassword($encoder->encodePassword($login->getPassword(), $login->getSalt()));
$em = $this->getDoctrine()->getManager();
$em->persist($login);
$em->flush();
$this->get('session')->setFlash(
'success',
'Account Successfully Created'
);
However, when I call persist and flush on my entity, the login_name field is getting '' put into it (empty space). I can't understand why the value is getting nulled out (I changed a DB setting to error when it comes in as non-unique).
There are associations against this class, but this is the primary so I am creating it first.
Any thoughtS?
I don't get what you're doing here. You want table.id to be an auto-generated ID but you want table.login_name to be the primary key? Because that's how you have it setup
#Id is for primary keys
#GeneratedValue defines how priamry keys are created
What I personally think you should want is for table.id to be the primary key, and for table.login_name to be unique
/**
* #ORM\Column(type="integer", name="id")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $userId;
/**
* #ORM\Column(type="string", name="login_name", length=255, unique=true)
*/
private $loginName;
So in testing I identified that you can't apply a generatedValue attribute to an Non-ID field. Once I removed that from the userID field (and allowed Mysql to handle that on it's own) things started to work again.

Categories