Created
September 27, 2012 13:40
-
-
Save hugodotlau/3794059 to your computer and use it in GitHub Desktop.
Using before and after for transactions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* @property int $bit_id | |
*/ | |
class Thing extends CActiveRecord { | |
} | |
/** | |
* @property int $id | |
* @property Thing[] $things | |
*/ | |
class Bit extends CActiveRecord { | |
public function relations() { | |
return array( | |
'things' => array(self::HAS_MANY, 'Thing', 'bit_id'), | |
); | |
} | |
/** | |
* This is an example function that another model method or a controller might use. | |
* | |
* @param Thing[] $things | |
* @return bool true on success | |
*/ | |
public function saveThings($things) { | |
$curTr = Yii::app()->db->getCurrentTransaction(); | |
$transaction = $curTr === null || !$curTr->getActive() | |
? app()->db->beginTransaction() | |
: false; | |
try { | |
// Begin of example task... | |
if ($this->things) | |
foreach ($this->things as $thing) | |
$thing->delete(); | |
if ($things) | |
foreach ($things as $thing) { | |
$thing->bit_id = $this->id; | |
if (!$thing->save()) | |
throw new CDbException('Cannot save a thing'); | |
} | |
// ...end of example task. | |
if ($transaction) | |
$transaction->commit(); | |
} catch(Exception $e) { | |
if ($transaction) { | |
$transaction->rollback(); | |
Yii::log(__CLASS__ . '::' . __FUNCTION__ . '() failed'); | |
return false; | |
} else | |
throw $e; | |
} | |
return true; | |
} | |
} | |
/** | |
* @property int $id | |
* @property Thing[] $things | |
*/ | |
class Bit extends CActiveRecord { | |
/** | |
* @var CDbTransaction | |
*/ | |
protected $_transaction; | |
public function relations() { | |
return array( | |
'things' => array(self::HAS_MANY, 'Thing', 'bit_id'), | |
); | |
} | |
protected function beforeDelete() { | |
$this->beforeChange(); | |
return parent::beforeDelete(); | |
} | |
protected function beforeSave() { | |
$this->beforeChange(); | |
return parent::beforeSave(); | |
} | |
protected function afterDelete() { | |
$this->afterChange(); | |
return parent::afterDelete(); | |
} | |
protected function afterSave() { | |
$this->afterChange(); | |
return parent::afterDelete(); | |
} | |
/** | |
* Begins a transaction if the caller of the model's method didn't already do so. | |
*/ | |
protected function beforeChange() { | |
$transaction = Yii::app()->db->getCurrentTransaction(); | |
if (($transaction === null || !$transaction->getActive()) | |
&& ($this->_transaction === null || !$this->_transaction->getActive()) | |
) | |
$this->_transaction = Yii::app()->db->beginTransaction(); | |
} | |
/** | |
* If this model has a $this->_transaction then try to committ it and roll it | |
* back if commit throws a CDbException. | |
*/ | |
protected function afterChange() { | |
if ($this->_transaction !== null && $this->_transaction->active) { | |
// Does Yii know to *not* call either afterDelete() or afterSave() | |
// until the method has finished all its deletes, updates and saves? | |
try { | |
$this->_transaction->commit(); | |
} catch (Exception $e) { | |
$this->_transaction->rollback(); | |
// Handle the error with some application logic, e.g. log it and | |
// display an error message. | |
} | |
} | |
} | |
/** | |
* This is an example function that another model method or a controller might use. | |
* | |
* @param Thing[] $things | |
* @return bool true on success | |
*/ | |
public function saveThings($things) { | |
// Handle the exceptions thrown by model manipulation here but | |
// leave the commit to afterChnage(). | |
try { | |
// Begin of example task... | |
if ($this->things) | |
foreach ($this->things as $thing) | |
$thing->delete(); | |
if ($things) | |
foreach ($things as $thing) { | |
$thing->bit_id = $this->id; | |
if (!$thing->save()) | |
throw new CDbException('Cannot save a thing'); | |
} | |
// ...end of example task. | |
} catch (Exception $e) { | |
if ($this->_transaction !== null && $this->_transaction->getActive()) | |
$this->_transaction->rollback(); | |
else | |
throw $e; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment