1

I know, how to use transactions in pure DAO or in ActiveModel, where transaction is initiated before call to $model->save() and rolled back upon any exception.

But how to use transactions, if the only place of code I have access to (no matter, why) is Yii event?

public function beforeDelete()
{
    foreach($this->menuItems as $menuItem) $menuItem->delete();

    return parent::beforeDelete();
}

If I initiate transaction there, capture possible exception and rollback entire transaction upon it, then only deletion of relational models (here: menu items) will be rolled back. It will not prevent (roll back) deletion of master record.

Does preventing deletion of master record, by returning FALSE in my own beforeDelete in case of exception, is all I need to take care here? Or should I avoid transactions at all in Yii events?

Community
  • 1
  • 1
trejder
  • 17,148
  • 27
  • 124
  • 216

2 Answers2

2

What about override save method:

public function save($runValidation=true,$attributes=null)
{
    $transaction=$this->getDbConnection()->beginTransaction();
    try
    {
        $result = parent::save($runValidation,$attributes);
        if($result)
            $transaction->commit();
        else
            $transaction->rollback();
    }
    catch(Exception $e)
    {
        $transaction->rollback();
        $result = false;
    }
    return $result;
}
Alex
  • 8,055
  • 7
  • 39
  • 61
  • I'm accepting your answer as an alternative. My own code, which still uses `beforeDelete` is quite similar to yours. And answer to my own question is (IMHO) "yes" -- preventing deletion of master record, by returning `FALSE` in my own `beforeDelete` in case of exception (after rolling back transaction) seems to be all, that I need to take care in this situation. – trejder Jul 01 '14 at 13:37
2

Answering my own question with example piece of code to further extend my comment given to Alex's answer:

public function beforeDelete()
{
    $transaction = $this->getDbConnection()->beginTransaction();

    try
    {
        foreach($this->menuItems as $menuItem) $menuItem->delete();

        $transaction->commit();
        return parent::beforeDelete();
    }
    catch(Exception $ex)
    {
        $transaction->rollback();
        return FALSE;
    }
}

Both answers seems correct, both are alternative to each other. Though, I accept Alex answer, as better.

trejder
  • 17,148
  • 27
  • 124
  • 216