Php 教条没有';无法从会话中正确加载关联
我在原则2.1中有这样的行为,我正在寻找一个好的“解决方法”。问题如下: 我有一个用户实体:Php 教条没有';无法从会话中正确加载关联,php,orm,doctrine-orm,Php,Orm,Doctrine Orm,我在原则2.1中有这样的行为,我正在寻找一个好的“解决方法”。问题如下: 我有一个用户实体: /** * @Entity(repositoryClass="Application\Entity\Repository\UserRepository") * @HasLifecycleCallbacks */ class User extends AbstractEntity { /** * * @var integer * * @Column
/**
* @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;
}
以及用户组实体:
/**
* @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;
}
如果我实例化一个用户对象(使用Zend_Auth执行此操作),Zend_Auth会自动将其放入会话
但问题是,我在下一页从会话中将其拉回来,然后用户类中的数据完全加载,但不在用户组关联中。如果将cascade={“merge”}添加到用户对象中的注释中,则会加载userGroup对象,但数据为空。如果您转储以下内容:
echo $user->userGroup->name;
$user->userGroup->name
你会回来的。问题是在会话中保存用户对象之前,没有访问usergroup实体的数据,因此将返回一个空的初始化对象。如果我这样做:
echo $user->userGroup->name;
在我将用户对象存储到会话中之前,Association用户组的所有数据都已成功保存,并且如果我尝试访问$user->userGroup->name变量,则不会在下一页返回NULL
有没有简单的方法来解决这个问题?我可以在用户类中使用生命周期回调@onLoad手动加载userGroup对象/关联吗?有什么建议吗?当您将实体存储到会话(通过Zend_Auth或其他方式)时,对象将被序列化,并且在随后检索和取消序列化时不再由条令维护。尝试将实体合并回EntityManager。请参见当您将实体存储到会话(通过Zend_Auth或其他方式)时,对象将被序列化,并且在随后检索和取消序列化时不再由条令维护。尝试将实体合并回EntityManager。请参见您的问题是mjh_ca回答的问题和您的
抽象实体
实现的问题的组合
由于显示您以这种方式访问实体字段:
$user->userGroup->name;
我假设您的抽象实体
基类使用的是\uu get()
和\uu set()
魔术方法,而不是正确的getter和setter:
function getUserGroup()
{
return $this->userGroup;
}
function setUserGroup(UserGroup $userGroup)
{
$this->userGroup = $userGroup;
}
实际上,您正在打破延迟加载:
“…当您访问尚未初始化的代理对象的公共属性时,返回值将为null。条令无法挂接到此过程并神奇地使实体延迟加载。”
资料来源:
您应改为通过以下方式访问字段:
$user->getUserGroup()->getName();
问题的第二部分正是mjh_ca编写的-Zend_Auth
在实体管理器序列化实体以便在会话中存储时将其从实体管理器中分离。在关联上设置cascade={“merge”}
将不起作用,因为它是分离的实际实体。您必须将反序列化的用户
实体合并到实体管理器中
$detachedIdentity = Zend_Auth::getInstance()->getIdentity();
$identity = $em->merge($detachedIdentity);
问题是,如何干净地做到这一点。您可以考虑为您的用户
实体实现一个\uuu wakeup()
魔术方法,但这也违反了条令最佳实践
资料来源:
由于我们讨论的是Zend_Auth
,因此可以扩展Zend_Auth
并重写getIdentity()
函数,使其具有实体感知功能
use Doctrine\ORM\EntityManager,
Doctrine\ORM\UnitOfWork;
class My_Auth extends \Zend_Auth
{
protected $_entityManager;
/**
* override otherwise self::$_instance
* will still create an instance of Zend_Auth
*/
public static function getInstance()
{
if (null === self::$_instance) {
self::$_instance = new self();
}
return self::$_instance;
}
public function getEntityManager()
{
return $this->_entityManager;
}
public function setEntityManager(EntityManager $entityManager)
{
$this->_entityManager = $entityManager;
}
public function getIdentity()
{
$storage = $this->getStorage();
if ($storage->isEmpty()) {
return null;
}
$identity = $storage->read();
$em = $this->getEntityManager();
if(UnitOfWork::STATE_DETACHED === $em->getUnitOfWork()->getEntityState($identity))
{
$identity = $em->merge($identity);
}
return $identity;
}
}
然后将\u init
函数添加到引导程序:
public function _initAuth()
{
$this->bootstrap('doctrine');
$em = $this->getResource('doctrine')->getEntityManager();
$auth = My_Auth::getInstance();
$auth->setEntityManager($em);
}
此时调用
$user->getUserGroup()->getName()代码>应该按预期工作。您的问题是mjh_ca回答的问题和您的抽象实体的问题的组合
由于显示您以这种方式访问实体字段:
$user->userGroup->name;
我假设您的抽象实体
基类使用的是\uu get()
和\uu set()
魔术方法,而不是正确的getter和setter:
function getUserGroup()
{
return $this->userGroup;
}
function setUserGroup(UserGroup $userGroup)
{
$this->userGroup = $userGroup;
}
实际上,您正在打破延迟加载:
“…当您访问尚未初始化的代理对象的公共属性时,返回值将为null。条令无法挂接到此过程并神奇地使实体延迟加载。”
资料来源:
您应改为通过以下方式访问字段:
$user->getUserGroup()->getName();
问题的第二部分正是mjh_ca编写的-Zend_Auth
在实体管理器序列化实体以便在会话中存储时将其从实体管理器中分离。在关联上设置cascade={“merge”}
将不起作用,因为它是分离的实际实体。您必须将反序列化的用户
实体合并到实体管理器中
$detachedIdentity = Zend_Auth::getInstance()->getIdentity();
$identity = $em->merge($detachedIdentity);
问题是,如何干净地做到这一点。您可以考虑为您的用户
实体实现一个\uuu wakeup()
魔术方法,但这也违反了条令最佳实践
资料来源:
由于我们讨论的是Zend_Auth
,因此可以扩展Zend_Auth
并重写getIdentity()
函数,使其具有实体感知功能
use Doctrine\ORM\EntityManager,
Doctrine\ORM\UnitOfWork;
class My_Auth extends \Zend_Auth
{
protected $_entityManager;
/**
* override otherwise self::$_instance
* will still create an instance of Zend_Auth
*/
public static function getInstance()
{
if (null === self::$_instance) {
self::$_instance = new self();
}
return self::$_instance;
}
public function getEntityManager()
{
return $this->_entityManager;
}
public function setEntityManager(EntityManager $entityManager)
{
$this->_entityManager = $entityManager;
}
public function getIdentity()
{
$storage = $this->getStorage();
if ($storage->isEmpty()) {
return null;
}
$identity = $storage->read();
$em = $this->getEntityManager();
if(UnitOfWork::STATE_DETACHED === $em->getUnitOfWork()->getEntityState($identity))
{
$identity = $em->merge($identity);
}
return $identity;
}
}
然后将\u init
函数添加到引导程序:
public function _initAuth()
{
$this->bootstrap('doctrine');
$em = $this->getResource('doctrine')->getEntityManager();
$auth = My_Auth::getInstance();
$auth->setEntityManager($em);
}
此时调用$user->getUserGroup()->getName()代码>应该按预期工作。我尝试过,但实际问题是,用户组关联在序列化之前没有填充。这导致merge()即使直接调用userGroup对象本身也不会生效。如果在序列化userGroup对象之前不访问该对象,则会出现此问题,因为Doctrine仅在调用该对象时加载实体数据。你明白我的问题吗?现在,我有一个echo$user->userGroup->name的解决方案;但这不是个好主意。我正在寻找一些东西来手动加载userGroup实体。希望你能理解。我试过了,但实际的问题是用户组关联在序列化之前没有被填充。这导致merge()即使直接调用userGroup对象本身也不会生效。如果不访问用户组对象,则会出现此问题