2011-03-24 62 views

回答

0

学说1.x中我已经覆盖了isValid()方法对混凝土Doctrine_Record(这里,LineItem):

public function isValid($deep = false, $hooks = true) { 
    $q = Doctrine_Query::create() 
     ->select('co.uid') 
     ->from('Company co') 
     ->leftJoin('co.workers w') 
     ->leftJoin('co.customers cust') 
     ->leftJoin('cust.workCases wc') 
     ->where('w.uid = ?', $this->_workerUid) // This LineItem's Worker must _always_ have the same Company as this LineItem (through LineItem -> WorkCase -> Customer -> Company) 
     ->andWhere('wc.state = ?', WorkCase::STATE_OPEN) // This LineItem's WorkCase must be open 
     ->andWhere('wc.uid = ?', $this->_caseUid); 
    $company = $q->fetchOne(); 

    return $company !== false && parent::isValid($deep, $hooks); 
} 

有几件事情,这里要注意:

  1. 我试图根据一些标准获取Company(其中,state必须“打开”)。最终结果取决于我是否找到满足这些标准的公司($company !== false
  2. isValid()覆盖的更深入实施。 总是使最终结果取决于parent::isValid($deep, $hooks)(我们必须确定原始实现也很开心)。
  3. 你可能会让“取公司记录”更简单一些。
+0

不错,但现在我有演出的问题。我的InvoiceItems可能有几百个,在保存发票之前我无法进行数百个查询。我是对的还是缺少什​​么? – giorgio 2011-03-24 10:23:47

+0

@giorgio那么,为了保持一致性,您无法事先获取'Invoice'的状态(至少在*之前不会)。因此,在每次更改“InvoiceItem”之前,都需要某种形式的查询。 – jensgram 2011-03-24 10:27:02

2

有几种可能性,你将如何实现这样的事情,这真的取决于你的情况,应用程序的业务逻辑等。(此外,你应该指定主义分支的1.x或2.x的)

  1. 它是完整性约束,在数据库级别执行:假设你的表有一个preUpdate触发器,它会引发异常(只有一些DB可以这样做,认为Postgres,Oracle),或者什么也不做,只是停止更新操作。

  2. 由于@jensgram建议,您可以覆盖验证方法,并且要么返回无效状态,或者因为它是完整性和逻辑约束,恕我直言

  3. 你可能会抛出异常,因为这不是一个验证问题

    使用preSave方法,或者跳过保存(但用户不会注意到某个事物)或再次抛出异常。

  4. 在您的应用程序中,您不应该允许用户进入这种情况。您的图形用户界面应该是明确的,并清楚地显示该发票已关闭,无法进一步修改。

就个人而言,我会用这样的情景: 首先,解决4号,不允许用户这样做。为了安全起见,请直接在数据库中实施触发器,以防止应用程序中的错误更改已关闭的发票,但默默地执行,不会产生错误,只需跳过保存操作(解决方案1)即可。这种方法还有一个优点。如果您发现自己处于这种情况,那么当您需要从任何其他应用程序连接到数据库时,该完整性约束将被保留。