I’m having this behavior with Doctrine 2.1 where I’m looking for a nice ‘workaround’. The problem is as follows:
I have a user Entity:
/**
* @Entity(repositoryClass="Application\Entity\Repository\UserRepository")
* @HasLifecycleCallbacks
*/
class User extends AbstractEntity
{
/**
*
* @var integer
*
* @Column(type="integer",nullable=false)
* @Id
* @GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
*
* @var \DateTime
* @Column(type="datetime",nullable=false)
*/
protected $insertDate;
/**
*
* @var string
* @Column(type="string", nullable=false)
*/
protected $username;
/**
*
* @ManyToOne(targetEntity="UserGroup", cascade={"merge"})
*/
protected $userGroup;
}
And a usergroup entity:
/**
* @Entity
*/
class UserGroup extends AbstractEntity
{
/**
*
* @var integer
*
* @Column(type="integer",nullable=false)
* @Id
* @GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
*
* @var string
* @Column(type="string",nullable=false)
*/
protected $name;
}
If I instantiate a user object (doing this with Zend_Auth) and Zend_Auth puts it automatically the session.
The problem is however, that is I pull it back from the session at a next page then the data in the user class is perfectly loaded but not in the userGroup association. If I add cascade={“merge”} into the annotation in the user object the userGroup object IS loaded but the data is empty. If you dump something like:
$user->userGroup->name
You will get NULL back. The problem is no data of the usergroup entity is accesed before the user object is saved in the session so a empty initialized object will be returned. If I do something like:
echo $user->userGroup->name;
Before I store the user object in the session all data of the assocication userGroup is succesfully saved and won’t return NULL on the next page if I try to access the $user->userGroup->name variable.
Is there a simple way to fix this? Can I manually load the userGroup object/association with a lifecycle callback @onLoad in the user class maybe? Any suggestions?
Your problem is a combination of what mjh_ca answered and a problem with your
AbstractEntityimplementation.Since you show that you access entity fields in this fashion:
I assume your
AbstractEntitybase class is using__get()and__set()magic methods instead of proper getters and setters:You are essentially breaking lazy loading:
Source: Doctrine Best Practices: Don’t Use Public Properties on Entities
You should instead be accessing fields this way:
The second part of your problem is exactly as mjh_ca wrote –
Zend_Authdetaches your entity from the entity manager when it serializes it for storage in the session. Settingcascade={"merge"}on your association will not work because it is the actual entity that is detached. You have to merge the deserializedUserentity into the entity manager.The question, is how to do this cleanly. You could look into implementing a
__wakeup()magic method for yourUserentity, but that is also against doctrine best practices…Source: Implementing Wakeup or Clone
Since we are talking about
Zend_Auth, you could extendZend_Authand override thegetIdentity()function so that it is entity aware.And than add an
_initfunction to your Bootstrap:At this point calling
$user->getUserGroup()->getName();should work as intended.