Skip to content
Permalink
Browse files

Fix transactions do not get rollbacked in saveAssociated/saveMany

Refs #2849
  • Loading branch information...
chinpei215 committed Aug 2, 2014
1 parent 3d77ce5 commit 799500ce6d10d46cb7b3804454319ce1cbb47520
Showing with 242 additions and 126 deletions.
  1. +150 −126 lib/Cake/Model/Model.php
  2. +92 −0 lib/Cake/Test/Case/Model/ModelWriteTest.php
@@ -2215,6 +2215,7 @@ public function saveAll($data = array(), $options = array()) {
* @return mixed If atomic: True on success, or false on failure.
* Otherwise: array similar to the $data array passed, but values are set to true/false
* depending on whether each record saved successfully.
* @throws PDOException
* @link http://book.cakephp.org/2.0/en/models/saving-your-data.html#model-savemany-array-data-null-array-options-array
*/
public function saveMany($data = null, $options = array()) {
@@ -2245,47 +2246,58 @@ public function saveMany($data = null, $options = array()) {
if ($options['atomic']) {
$db = $this->getDataSource();
$transactionBegun = $db->begin();
} else {
$transactionBegun = false;
}
$return = array();
foreach ($data as $key => $record) {
$validates = $this->create(null) !== null;
$saved = false;
if ($validates) {
if ($options['deep']) {
$saved = $this->saveAssociated($record, array_merge($options, array('atomic' => false)));
} else {
$saved = $this->save($record, $options);
try {
$return = array();
foreach ($data as $key => $record) {
$validates = $this->create(null) !== null;
$saved = false;
if ($validates) {
if ($options['deep']) {
$saved = $this->saveAssociated($record, array_merge($options, array('atomic' => false)));
} else {
$saved = $this->save($record, $options);
}
}
$validates = ($validates && ($saved === true || (is_array($saved) && !in_array(false, $saved, true))));
if (!$validates) {
$validationErrors[$key] = $this->validationErrors;
}
}
$validates = ($validates && ($saved === true || (is_array($saved) && !in_array(false, $saved, true))));
if (!$validates) {
$validationErrors[$key] = $this->validationErrors;
if (!$options['atomic']) {
$return[$key] = $validates;
} elseif (!$validates) {
break;
}
}
$this->validationErrors = $validationErrors;
if (!$options['atomic']) {
$return[$key] = $validates;
} elseif (!$validates) {
break;
return $return;
}
}
$this->validationErrors = $validationErrors;
if (!$options['atomic']) {
return $return;
}
if ($validates) {
if ($transactionBegun) {
return $db->commit() !== false;
}
return true;
}
if ($validates) {
if ($transactionBegun) {
return $db->commit() !== false;
$db->rollback();
}
return true;
return false;
} catch (Exception $e) {
if ($transactionBegun) {
$db->rollback();
}
throw $e;
}
$db->rollback();
return false;
}
/**
@@ -2337,6 +2349,7 @@ public function validateMany(&$data, $options = array()) {
* @return mixed If atomic: True on success, or false on failure.
* Otherwise: array similar to the $data array passed, but values are set to true/false
* depending on whether each record saved successfully.
* @throws PDOException
* @link http://book.cakephp.org/2.0/en/models/saving-your-data.html#model-saveassociated-array-data-null-array-options-array
*/
public function saveAssociated($data = null, $options = array()) {
@@ -2368,133 +2381,144 @@ public function saveAssociated($data = null, $options = array()) {
if ($options['atomic']) {
$db = $this->getDataSource();
$transactionBegun = $db->begin();
} else {
$transactionBegun = false;
}
$associations = $this->getAssociated();
$return = array();
$validates = true;
foreach ($data as $association => $values) {
$isEmpty = empty($values) || (isset($values[$association]) && empty($values[$association]));
if ($isEmpty || !isset($associations[$association]) || $associations[$association] !== 'belongsTo') {
continue;
}
try {
$associations = $this->getAssociated();
$return = array();
$validates = true;
foreach ($data as $association => $values) {
$isEmpty = empty($values) || (isset($values[$association]) && empty($values[$association]));
if ($isEmpty || !isset($associations[$association]) || $associations[$association] !== 'belongsTo') {
continue;
}
$Model = $this->{$association};
$Model = $this->{$association};
$validates = $Model->create(null) !== null;
$saved = false;
if ($validates) {
if ($options['deep']) {
$saved = $Model->saveAssociated($values, array('atomic' => false) + $options);
} else {
$saved = $Model->save($values, array('atomic' => false) + $options);
$validates = $Model->create(null) !== null;
$saved = false;
if ($validates) {
if ($options['deep']) {
$saved = $Model->saveAssociated($values, array('atomic' => false) + $options);
} else {
$saved = $Model->save($values, array('atomic' => false) + $options);
}
$validates = ($saved === true || (is_array($saved) && !in_array(false, $saved, true)));
}
$validates = ($saved === true || (is_array($saved) && !in_array(false, $saved, true)));
}
if ($validates) {
$key = $this->belongsTo[$association]['foreignKey'];
if (isset($data[$this->alias])) {
$data[$this->alias][$key] = $Model->id;
if ($validates) {
$key = $this->belongsTo[$association]['foreignKey'];
if (isset($data[$this->alias])) {
$data[$this->alias][$key] = $Model->id;
} else {
$data = array_merge(array($key => $Model->id), $data, array($key => $Model->id));
}
$options = $this->_addToWhiteList($key, $options);
} else {
$data = array_merge(array($key => $Model->id), $data, array($key => $Model->id));
$validationErrors[$association] = $Model->validationErrors;
}
$options = $this->_addToWhiteList($key, $options);
} else {
$validationErrors[$association] = $Model->validationErrors;
}
$return[$association] = $validates;
}
if ($validates && !($this->create(null) !== null && $this->save($data, $options))) {
$validationErrors[$this->alias] = $this->validationErrors;
$validates = false;
}
$return[$this->alias] = $validates;
foreach ($data as $association => $values) {
if (!$validates) {
break;
$return[$association] = $validates;
}
$isEmpty = empty($values) || (isset($values[$association]) && empty($values[$association]));
if ($isEmpty || !isset($associations[$association])) {
continue;
if ($validates && !($this->create(null) !== null && $this->save($data, $options))) {
$validationErrors[$this->alias] = $this->validationErrors;
$validates = false;
}
$return[$this->alias] = $validates;
$Model = $this->{$association};
foreach ($data as $association => $values) {
if (!$validates) {
break;
}
$type = $associations[$association];
$key = $this->{$type}[$association]['foreignKey'];
switch ($type) {
case 'hasOne':
if (isset($values[$association])) {
$values[$association][$key] = $this->id;
} else {
$values = array_merge(array($key => $this->id), $values, array($key => $this->id));
}
$isEmpty = empty($values) || (isset($values[$association]) && empty($values[$association]));
if ($isEmpty || !isset($associations[$association])) {
continue;
}
$validates = $Model->create(null) !== null;
$saved = false;
$Model = $this->{$association};
if ($validates) {
$options = $Model->_addToWhiteList($key, $options);
if ($options['deep']) {
$saved = $Model->saveAssociated($values, array('atomic' => false) + $options);
$type = $associations[$association];
$key = $this->{$type}[$association]['foreignKey'];
switch ($type) {
case 'hasOne':
if (isset($values[$association])) {
$values[$association][$key] = $this->id;
} else {
$saved = $Model->save($values, $options);
$values = array_merge(array($key => $this->id), $values, array($key => $this->id));
}
}
$validates = ($validates && ($saved === true || (is_array($saved) && !in_array(false, $saved, true))));
if (!$validates) {
$validationErrors[$association] = $Model->validationErrors;
}
$validates = $Model->create(null) !== null;
$saved = false;
$return[$association] = $validates;
break;
case 'hasMany':
foreach ($values as $i => $value) {
if (isset($values[$i][$association])) {
$values[$i][$association][$key] = $this->id;
} else {
$values[$i] = array_merge(array($key => $this->id), $value, array($key => $this->id));
if ($validates) {
$options = $Model->_addToWhiteList($key, $options);
if ($options['deep']) {
$saved = $Model->saveAssociated($values, array('atomic' => false) + $options);
} else {
$saved = $Model->save($values, $options);
}
}
}
$options = $Model->_addToWhiteList($key, $options);
$_return = $Model->saveMany($values, array('atomic' => false) + $options);
if (in_array(false, $_return, true)) {
$validationErrors[$association] = $Model->validationErrors;
$validates = false;
}
$validates = ($validates && ($saved === true || (is_array($saved) && !in_array(false, $saved, true))));
if (!$validates) {
$validationErrors[$association] = $Model->validationErrors;
}
$return[$association] = $_return;
break;
$return[$association] = $validates;
break;
case 'hasMany':
foreach ($values as $i => $value) {
if (isset($values[$i][$association])) {
$values[$i][$association][$key] = $this->id;
} else {
$values[$i] = array_merge(array($key => $this->id), $value, array($key => $this->id));
}
}
$options = $Model->_addToWhiteList($key, $options);
$_return = $Model->saveMany($values, array('atomic' => false) + $options);
if (in_array(false, $_return, true)) {
$validationErrors[$association] = $Model->validationErrors;
$validates = false;
}
$return[$association] = $_return;
break;
}
}
}
$this->validationErrors = $validationErrors;
$this->validationErrors = $validationErrors;
if (isset($validationErrors[$this->alias])) {
$this->validationErrors = $validationErrors[$this->alias];
unset($validationErrors[$this->alias]);
$this->validationErrors = array_merge($this->validationErrors, $validationErrors);
}
if (isset($validationErrors[$this->alias])) {
$this->validationErrors = $validationErrors[$this->alias];
unset($validationErrors[$this->alias]);
$this->validationErrors = array_merge($this->validationErrors, $validationErrors);
}
if (!$options['atomic']) {
return $return;
}
if ($validates) {
if ($transactionBegun) {
return $db->commit() !== false;
if (!$options['atomic']) {
return $return;
}
if ($validates) {
if ($transactionBegun) {
return $db->commit() !== false;
}
return true;
}
return true;
}
$db->rollback();
return false;
if ($transactionBegun) {
$db->rollback();
}
return false;
} catch (Exception $e) {
if ($transactionBegun) {
$db->rollback();
}
throw $e;
}
}
/**
Oops, something went wrong.

0 comments on commit 799500c

Please sign in to comment.
You can’t perform that action at this time.