2011-03-24 65 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)即可。這種方法還有一個優點。如果您發現自己處於這種情況,那麼當您需要從任何其他應用程序連接到數據庫時,該完整性約束將被保留。