zer*_*kms 76 php doctrine symfony doctrine-orm
让我们假设我检索一个实体$e并用setter修改它的状态:
$e->setFoo('a');
$e->setBar('b');
Run Code Online (Sandbox Code Playgroud)
有没有可能检索已更改的字段数组?
在我的例子的情况下,我想要检索foo => a, bar => b结果
PS:是的,我知道我可以修改所有的访问者并手动实现这个功能,但我正在寻找一些方便的方法来做到这一点
Ocr*_*ius 135
你可以
Doctrine\ORM\EntityManager#getUnitOfWork用来得到一个Doctrine\ORM\UnitOfWork.
然后只需触发变更集计算(仅适用于托管实体)Doctrine\ORM\UnitOfWork#computeChangeSets().
您也可以使用类似的方法,例如,Doctrine\ORM\UnitOfWork#recomputeSingleEntityChangeSet(Doctrine\ORM\ClassMetadata $meta, $entity)如果您确切地知道要检查的内容而不迭代整个对象图.
之后,您可以使用它Doctrine\ORM\UnitOfWork#getEntityChangeSet($entity)来检索对象的所有更改.
把它放在一起:
$entity = $em->find('My\Entity', 1);
$entity->setTitle('Changed Title!');
$uow = $em->getUnitOfWork();
$uow->computeChangeSets(); // do not compute changes if inside a listener
$changeset = $uow->getEntityChangeSet($entity);
Run Code Online (Sandbox Code Playgroud)
注意.如果尝试在preUpdate侦听器中获取更新的字段,请不要重新计算更改集,因为它已经完成.只需调用getEntityChangeSet即可获得对实体所做的所有更改.
Sla*_*nko 37
对于那些想要使用上述方法检查实体更改的人来说,要注意大的标志.
$uow = $em->getUnitOfWork();
$uow->computeChangeSets();
Run Code Online (Sandbox Code Playgroud)
该$uow->computeChangeSets()方法由持久例程在内部使用,使得上述解决方案无法使用.这也是该方法评论中所写的内容:@internal Don't call from the outside.在检查实体的更改后$uow->computeChangeSets(),在方法结束时执行以下代码(每个管理实体):
if ($changeSet) {
$this->entityChangeSets[$oid] = $changeSet;
$this->originalEntityData[$oid] = $actualData;
$this->entityUpdates[$oid] = $entity;
}
Run Code Online (Sandbox Code Playgroud)
该$actualData数组保存实体属性的当前更改.一旦写入这些内容$this->originalEntityData[$oid],这些尚未持久的更改将被视为实体的原始属性.
后来,当$em->persist($entity)被称为将更改保存到实体,它也涉及到方法$uow->computeChangeSets(),但现在无法找到更改的实体,因为这些尚未持久的变化被认为是实体的原有特性.
Moh*_*ami 29
检查这个公共(而不是内部)功能:
$this->em->getUnitOfWork()->getOriginalEntityData($entity);
来自学说回购:
/**
* Gets the original data of an entity. The original data is the data that was
* present at the time the entity was reconstituted from the database.
*
* @param object $entity
*
* @return array
*/
public function getOriginalEntityData($entity)
Run Code Online (Sandbox Code Playgroud)
您所要做的就是在您的实体中实现一个toArray或serialize函数并进行差异化.像这样的东西:
$originalData = $em->getUnitOfWork()->getOriginalEntityData($entity);
$toArrayEntity = $entity->toArray();
$changes = array_diff_assoc($toArrayEntity, $originalData);
Run Code Online (Sandbox Code Playgroud)
它将返回更改
$entityManager->getUnitOfWork()->getEntityChangeSet($entity)
Run Code Online (Sandbox Code Playgroud)
您可以使用通知政策跟踪更改.
首先,实现NotifyPropertyChanged接口:
/**
* @Entity
* @ChangeTrackingPolicy("NOTIFY")
*/
class MyEntity implements NotifyPropertyChanged
{
// ...
private $_listeners = array();
public function addPropertyChangedListener(PropertyChangedListener $listener)
{
$this->_listeners[] = $listener;
}
}
Run Code Online (Sandbox Code Playgroud)
然后,只需在每个更改数据的方法上调用_onPropertyChanged,如下所示:
class MyEntity implements NotifyPropertyChanged
{
// ...
protected function _onPropertyChanged($propName, $oldValue, $newValue)
{
if ($this->_listeners) {
foreach ($this->_listeners as $listener) {
$listener->propertyChanged($this, $propName, $oldValue, $newValue);
}
}
}
public function setData($data)
{
if ($data != $this->data) {
$this->_onPropertyChanged('data', $this->data, $data);
$this->data = $data;
}
}
}
Run Code Online (Sandbox Code Playgroud)