Doctrine inserting null for #ID field - php

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.

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;
}

Symfony2 doctrine exception in persisting OneToMany entities

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);

Doctrine2 One to One Relation and extra table

I have 3 tables:
users, users_profile and extra table users_addresses.
User class:
class User
{
/**
* #ORM\Id()
* #ORM\Column(name="user_id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
* #var int
*/
private $userId;
/**
* #ORM\OneToOne(targetEntity="Entity\UserProfile", cascade={"persist", "remove"}, mappedBy="user", fetch="LAZY")
* #var Entity\UserProfile
*/
private $profile;
/**
* #param Entity\UserProfile $profile
*/
public function setProfile(UserProfile $profile) {
$this->profile = $profile;
$profile->setUser($this);
return $this;
}
(...)
}
User profile class
class UserProfile
{
/**
* #ORM\Id()
* #ORM\Column(name="profile_id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
* #var int
*/
private $profileId;
/**
* #ORM\OneToOne(targetEntity="Entity\User", inversedBy="profile")
* #ORM\JoinColumn(name="user_id", referencedColumnName="user_id")
* #var Entity\User
*/
private $user;
/**
* #ORM\ManyToMany(targetEntity="Entity\Address", cascade={"persist"})
* #ORM\JoinTable(name="users_addresses",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="user_id")},
* inverseJoinColumns={#ORM\JoinColumn(name="address_id", referencedColumnName="address_id")}
* )
**/
private $addresses;
/**
* #param Address $address
*/
public function addAddress(Address $address) {
if (!$this->addresses->contains($address)) {
$this->addresses->add($address);
}
return $this;
}
(...)
}
Address class
class Address
{
/**
* #ORM\Id()
* #ORM\Column(name="address_id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
* #var int
*/
private $addressId;
/**
* #ORM\Column(type="string", length=128, nullable=false)
* #var string
*/
private $city;
(...)
}
Add user with profile data and address
$userAddress = new \Entity\Address();
$userAddress->setStreet($street);
$userAddress->setCity($city);
$userAddress->setCountry($country);
$userAddress->setState($state);
$userAddress->setZipCode($zipCode);
$userProfile = new \Entity\UserProfile();
$userProfile->addAddress($userAddress);
$user = new \Entity\User();
$user->setProfile($userProfile);
$em->persist($user);
$em->flush();
The problem i am having at the moment is that the entities persist ok, but the 'user_id' in the join table ('users_addresses') is not correct ('user_id' = 0, 'address_id' = correct). Table 'addresses' must not contain extra field like 'user_id'. What am I doing wrong?
I need a structure like this:
Your modeling shows that tables users and users_profile share the same primary key, namely user_id, and thus that column is also a foreign key toward users in users_profile.
Hence, you should replace profile_id in the Php annotations by user_id, remove the key auto generation directive, and update (or delete and recreate) the schema.
class UserProfile {
/**
* #ORM\Id
* #ORM\Column(name="user_id", type="integer")
* #var int
*/
private $profileId;
/* ... */
}
Then
$ doctrine orm:info --verbose
Found 3 mapped entities:
[OK] Address
[OK] User
[OK] UserProfile
$ doctrine orm:schema-tool:create
ATTENTION: This operation should not be executed in a production environmnent.
Creating database schema...
Database schema created successfully!
Or use the update command if you already have a schema.
You could also rename the php class attribute ($profileId), for "consistency" with the DB model, but I don't think it matters much, unless you have code which relies on a specific name.

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.

Symfony: I Can't store primary key values

I have a problem, I have a table (downloads) with two fields: Token (primary key) and value.
I have my entity Downloads with these methods (only show token methods, value works right):
/**
* #var string
*
* #ORM\Column(name="token", type="string", length=45, nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $token;
/**
* Set token
*
* #param string $token
* #return Downloads
*/
public function setToken($token)
{
$this->token = $token;
return $this;
}
/**
* Get token
*
* #return string
*/
public function getToken()
{
return $this->token;
}
But, when I do this in my controller:
$em = $this->getDoctrine()->getManager();
$Download = new Downloads();
$Download->setToken($token);
$Download->setValid($now);
$em->persist($Download);
$em->flush();
Object is well created, but in my database Valid is stored correctly, and token is store empty!!
if I see the values, util $em->flush(); object download has two correct values, but after this, token (primary key) disappear his value.
How can I do?
try to remove the #ORM\GeneratedValue
(strategy="IDENTITY") because it is the one that causes doctrine to generate value for Token.
hope it helps :)
you have to create auto increment for your columns like this
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
Stupid answer, but have you tried:
Clearing your Symfony cache
Restarting Apache
It might have to do with Doctrine caching.

Categories