使用Symfony 2.5,Doctrine documentation表示preUpdate
事件监听器是最严格的。您不能只对实体进行更改,而是必须使用特殊功能:
$entity->setNewValue($fieldName, $value)
但是,我有一个实体$view
,它有一个到多个关联实体$routing
,我在$view
对象中有一个特殊的setter,它添加了多个路由:
class View {
protected $routing;
public function getRouting() {
return $this->routing;
}
public function addRouting(\Gutensite\CmsBundle\Entity\Routing\Routing $routing)
{
// Maintain Relationship
$routing->setView($this);
$this->routing[] = $routing;
return $this;
}
}
我在该实体中没有setRouting()
函数,因为我有一个addRouting(),因为它是一个多oneToMany
个关联。
所以...在我的preUpdate事件监听器中,我应该如何创建一个新的“默认”路由,并将其添加到视图中,因为$entity->setNewValue()
函数不能完全适用于集合,并且显然我不能只调用$view->addRouting($route)
(我试过了,但没有任何东西被持久化到数据库中)。
注意:从2.4开始我们应该使用LifeCycleEventArgs而不是PreUpdateEventArgs(evidently)。
public function preUpdate(LifeCycleEventArgs $eventArgs) {
$entity = $eventArgs->getEntity();
$em = $eventArgs->getEntityManager();
if($entity instanceof View) {
if(!$entity->getRouting() || !$entity->getRouting()[0]) {
$routing = new Routing();
// simplified code to Set Friendly URL
$routing->setFurl('Unknown-Friendly-URL-'.$entity->getId());
// Set Default Values for Route
$routing->setFlagPrimary(1);
$routing->setTime(time());
$routing->setTimeMod(time());
$routing->setStatus(1);
$routing->setView($entity);
// Add the route to the View Entity
$entity->addRouting($routing);
// Recalculate Entity Changes (not working)
$uow = $em->getUnitOfWork();
// This doesn't work whether I compute the changesets for $entity (which is $view)
// or if I calculate changes for $entity->getRouting() (which is the new route I'm adding).
$classMetadata = $em->getClassMetadata(get_class($entity));
// Recomputer Entire Change Set Because it's a New Record (I'm not sure this is necessary or not)
$uow->computeChangeSet($classMetadata, $entity);
// This doesn't work either
$uow->recomputeSingleEntityChangeSet($classMetadata, $entity);
}
}
}
答案 0 :(得分:2)
我最终只是在onFlush
事件中实现了这一点。 preUpdate
对我的用例来说限制太多了。所以这就引出了一个问题:为什么在onFlush更灵活时使用preUpdate?
preUpdate
将简单值插入实体,例如
$eventArgs->setNewValue('myField', $value);
您还可以访问实体的旧值和新值(这对于轻松比较更改的WHICH字段非常有用,这是我以前需要的。)
这个事件有一个强大的功能,但它是用一个执行的 PreUpdateEventArgs实例,其中包含对该引用的引用 计算此实体的变更集。这意味着您可以访问所有人 已为此实体更改过的旧字段和新字段 值。 - reference
注意:如果您确实使用了preUpdate,请记住您必须使用setNewValue()
语法,而不是实体的常规设置器。无需重新计算更改集,您还 should NOT call persist :
任何对EntityManager的调用#persist()或EntityManager #remove(),甚至 强烈建议不要与UnitOfWork API结合使用 在刷新操作之外不能按预期工作。
preUpdate
永远不允许对更新后的实体的关联进行更改 这个事件,因为Doctrine无法保证正确处理 刷新操作此时的参照完整性。 - reference
因此,如果您需要更新子级或父级值(例如更新父级的修改时间),则无法在preUpdate中执行此操作,因为在eventArgs上调用了setNewValue
方法当前实体,而不是特定实体。
或者如果你需要添加一个集合,就像在我的问题中一样,你不能调用像addRouting
这样的自定义设置器(由于我提到的原因)。我怀疑这意味着@ RomaKliuchko的建议是行不通的。
请添加其他优点和缺点。
答案 1 :(得分:0)
您是否尝试过实施setRouting(ArrayCollection $routing)
方法,该方法将覆盖现有的集合并执行如下操作:
$routings = $entity->getRouting();
// add entities to routing collection if needed
$eventArgs->setNewValue('routing', $routings);