mirror of
https://github.com/kamilwylegala/cakephp2-php8.git
synced 2024-11-15 03:18:26 +00:00
Merge pull request #4140 from chinpei215/master-issue2849-fix
Fix transactions do not get rollbacked in saveAssociated/saveMany. Fixes #2849
This commit is contained in:
commit
221fc862aa
2 changed files with 562 additions and 187 deletions
|
@ -2215,6 +2215,7 @@ class Model extends Object implements CakeEventListener {
|
|||
* @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()) {
|
||||
|
@ -2242,11 +2243,13 @@ class Model extends Object implements CakeEventListener {
|
|||
$options['validate'] = false;
|
||||
}
|
||||
|
||||
$transactionBegun = false;
|
||||
if ($options['atomic']) {
|
||||
$db = $this->getDataSource();
|
||||
$transactionBegun = $db->begin();
|
||||
}
|
||||
|
||||
try {
|
||||
$return = array();
|
||||
foreach ($data as $key => $record) {
|
||||
$validates = $this->create(null) !== null;
|
||||
|
@ -2284,8 +2287,16 @@ class Model extends Object implements CakeEventListener {
|
|||
return true;
|
||||
}
|
||||
|
||||
if ($transactionBegun) {
|
||||
$db->rollback();
|
||||
}
|
||||
return false;
|
||||
} catch (Exception $e) {
|
||||
if ($transactionBegun) {
|
||||
$db->rollback();
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2337,6 +2348,7 @@ class Model extends Object implements CakeEventListener {
|
|||
* @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()) {
|
||||
|
@ -2365,11 +2377,13 @@ class Model extends Object implements CakeEventListener {
|
|||
$options['validate'] = false;
|
||||
}
|
||||
|
||||
$transactionBegun = false;
|
||||
if ($options['atomic']) {
|
||||
$db = $this->getDataSource();
|
||||
$transactionBegun = $db->begin();
|
||||
}
|
||||
|
||||
try {
|
||||
$associations = $this->getAssociated();
|
||||
$return = array();
|
||||
$validates = true;
|
||||
|
@ -2493,8 +2507,16 @@ class Model extends Object implements CakeEventListener {
|
|||
return true;
|
||||
}
|
||||
|
||||
if ($transactionBegun) {
|
||||
$db->rollback();
|
||||
}
|
||||
return false;
|
||||
} catch (Exception $e) {
|
||||
if ($transactionBegun) {
|
||||
$db->rollback();
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -36,6 +36,8 @@ class TestAuthor extends Author {
|
|||
|
||||
protected $_dataSourceObject;
|
||||
|
||||
public $dataForAfterSave;
|
||||
|
||||
/**
|
||||
* Helper method to set a datasource object
|
||||
*
|
||||
|
@ -74,6 +76,8 @@ class TestPost extends Post {
|
|||
|
||||
protected $_dataSourceObject;
|
||||
|
||||
public $dataForAfterSave;
|
||||
|
||||
/**
|
||||
* Helper method to set a datasource object
|
||||
*
|
||||
|
@ -4124,25 +4128,57 @@ class ModelWriteTest extends BaseModelTest {
|
|||
public function testSaveAllManyRowsTransactionNoRollback() {
|
||||
$this->loadFixtures('Post');
|
||||
|
||||
$db = $this->getMock('DboSource', array('begin', 'connect', 'rollback', 'describe'));
|
||||
|
||||
$db->expects($this->once())
|
||||
->method('describe')
|
||||
->will($this->returnValue(array()));
|
||||
$db->expects($this->once())->method('rollback');
|
||||
|
||||
$Post = new TestPost();
|
||||
$Post->setDataSourceObject($db);
|
||||
|
||||
$Post->validate = array(
|
||||
'title' => array('rule' => array('notEmpty'))
|
||||
);
|
||||
|
||||
// If validation error occurs, rollback() should be called.
|
||||
$db = $this->_getMockDboSource(array('begin', 'commit', 'rollback'));
|
||||
$db->expects($this->once())->method('begin')->will($this->returnValue(true));
|
||||
$db->expects($this->never())->method('commit');
|
||||
$db->expects($this->once())->method('rollback');
|
||||
|
||||
$Post->setDataSourceObject($db);
|
||||
|
||||
$data = array(
|
||||
array('author_id' => 1, 'title' => 'New Fourth Post'),
|
||||
array('author_id' => 1, 'title' => '')
|
||||
);
|
||||
$Post->saveAll($data, array('atomic' => true, 'validate' => true));
|
||||
|
||||
// If exception thrown, rollback() should be called too.
|
||||
$db = $this->_getMockDboSource(array('begin', 'commit', 'rollback'));
|
||||
$db->expects($this->once())->method('begin')->will($this->returnValue(true));
|
||||
$db->expects($this->never())->method('commit');
|
||||
$db->expects($this->once())->method('rollback');
|
||||
|
||||
$Post->setDataSourceObject($db);
|
||||
|
||||
$data = array(
|
||||
array('author_id' => 1, 'title' => 'New Fourth Post'),
|
||||
array('author_id' => 1, 'title' => 'New Fifth Post', 'body' => $db->expression('PDO_EXCEPTION()'))
|
||||
);
|
||||
|
||||
try {
|
||||
$Post->saveAll($data, array('atomic' => true, 'validate' => true));
|
||||
$this->fail('No exception thrown');
|
||||
} catch (PDOException $e) {
|
||||
}
|
||||
|
||||
// Otherwise, commit() should be called.
|
||||
$db = $this->_getMockDboSource(array('begin', 'commit', 'rollback'));
|
||||
$db->expects($this->once())->method('begin')->will($this->returnValue(true));
|
||||
$db->expects($this->once())->method('commit');
|
||||
$db->expects($this->never())->method('rollback');
|
||||
|
||||
$Post->setDataSourceObject($db);
|
||||
|
||||
$data = array(
|
||||
array('author_id' => 1, 'title' => 'New Fourth Post'),
|
||||
array('author_id' => 1, 'title' => 'New Fifth Post')
|
||||
);
|
||||
$Post->saveAll($data, array('atomic' => true, 'validate' => true));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4151,28 +4187,22 @@ class ModelWriteTest extends BaseModelTest {
|
|||
* @return void
|
||||
*/
|
||||
public function testSaveAllAssociatedTransactionNoRollback() {
|
||||
$testDb = ConnectionManager::getDataSource('test');
|
||||
|
||||
$db = $this->getMock('DboSource', array('connect', 'rollback', 'describe', 'create', 'update', 'begin'));
|
||||
$db->columns = $testDb->columns;
|
||||
|
||||
$db->expects($this->once())->method('rollback');
|
||||
$db->expects($this->any())->method('describe')
|
||||
->will($this->returnValue(array(
|
||||
'id' => array('type' => 'integer', 'length' => 11),
|
||||
'title' => array('type' => 'string'),
|
||||
'body' => array('type' => 'text'),
|
||||
'published' => array('type' => 'string')
|
||||
)));
|
||||
$this->loadFixtures('Post', 'Author');
|
||||
|
||||
$Post = new TestPost();
|
||||
$Post->setDataSourceObject($db);
|
||||
$Post->Author->setDataSourceObject($db);
|
||||
|
||||
$Post->Author->validate = array(
|
||||
'user' => array('rule' => array('notEmpty'))
|
||||
);
|
||||
|
||||
// If validation error occurs, rollback() should be called.
|
||||
$db = $this->_getMockDboSource(array('begin', 'commit', 'rollback'));
|
||||
$db->expects($this->once())->method('begin')->will($this->returnValue(true));
|
||||
$db->expects($this->never())->method('commit');
|
||||
$db->expects($this->once())->method('rollback');
|
||||
|
||||
$Post->setDataSourceObject($db);
|
||||
$Post->Author->setDataSourceObject($db);
|
||||
|
||||
$data = array(
|
||||
'Post' => array(
|
||||
'title' => 'New post',
|
||||
|
@ -4185,6 +4215,55 @@ class ModelWriteTest extends BaseModelTest {
|
|||
)
|
||||
);
|
||||
$Post->saveAll($data, array('validate' => true));
|
||||
|
||||
// If exception thrown, rollback() should be called too.
|
||||
$db = $this->_getMockDboSource(array('begin', 'commit', 'rollback'));
|
||||
$db->expects($this->once())->method('begin')->will($this->returnValue(true));
|
||||
$db->expects($this->never())->method('commit');
|
||||
$db->expects($this->once())->method('rollback');
|
||||
|
||||
$Post->setDataSourceObject($db);
|
||||
$Post->Author->setDataSourceObject($db);
|
||||
|
||||
$data = array(
|
||||
'Post' => array(
|
||||
'title' => 'New post',
|
||||
'body' => $db->expression('PDO_EXCEPTION()'),
|
||||
'published' => 'Y'
|
||||
),
|
||||
'Author' => array(
|
||||
'user' => 'New user',
|
||||
'password' => "sekret"
|
||||
)
|
||||
);
|
||||
|
||||
try {
|
||||
$Post->saveAll($data, array('validate' => true));
|
||||
$this->fail('No exception thrown');
|
||||
} catch (PDOException $e) {
|
||||
}
|
||||
|
||||
// Otherwise, commit() should be called.
|
||||
$db = $this->_getMockDboSource(array('begin', 'commit', 'rollback'));
|
||||
$db->expects($this->once())->method('begin')->will($this->returnValue(true));
|
||||
$db->expects($this->once())->method('commit');
|
||||
$db->expects($this->never())->method('rollback');
|
||||
|
||||
$Post->setDataSourceObject($db);
|
||||
$Post->Author->setDataSourceObject($db);
|
||||
|
||||
$data = array(
|
||||
'Post' => array(
|
||||
'title' => 'New post',
|
||||
'body' => 'Content',
|
||||
'published' => 'Y'
|
||||
),
|
||||
'Author' => array(
|
||||
'user' => 'New user',
|
||||
'password' => "sekret"
|
||||
)
|
||||
);
|
||||
$Post->saveAll($data, array('validate' => true));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -5557,25 +5636,57 @@ class ModelWriteTest extends BaseModelTest {
|
|||
public function testSaveManyTransactionNoRollback() {
|
||||
$this->loadFixtures('Post');
|
||||
|
||||
$db = $this->getMock('DboSource', array('begin', 'connect', 'rollback', 'describe'));
|
||||
|
||||
$db->expects($this->once())
|
||||
->method('describe')
|
||||
->will($this->returnValue(array()));
|
||||
$db->expects($this->once())->method('rollback');
|
||||
|
||||
$Post = new TestPost();
|
||||
$Post->setDataSourceObject($db);
|
||||
|
||||
$Post->validate = array(
|
||||
'title' => array('rule' => array('notEmpty'))
|
||||
);
|
||||
|
||||
// If validation error occurs, rollback() should be called.
|
||||
$db = $this->_getMockDboSource(array('begin', 'commit', 'rollback'));
|
||||
$db->expects($this->once())->method('begin')->will($this->returnValue(true));
|
||||
$db->expects($this->never())->method('commit');
|
||||
$db->expects($this->once())->method('rollback');
|
||||
|
||||
$Post->setDataSourceObject($db);
|
||||
|
||||
$data = array(
|
||||
array('author_id' => 1, 'title' => 'New Fourth Post'),
|
||||
array('author_id' => 1, 'title' => '')
|
||||
);
|
||||
$Post->saveMany($data, array('validate' => true));
|
||||
|
||||
// If exception thrown, rollback() should be called too.
|
||||
$db = $this->_getMockDboSource(array('begin', 'commit', 'rollback'));
|
||||
$db->expects($this->once())->method('begin')->will($this->returnValue(true));
|
||||
$db->expects($this->never())->method('commit');
|
||||
$db->expects($this->once())->method('rollback');
|
||||
|
||||
$Post->setDataSourceObject($db);
|
||||
|
||||
$data = array(
|
||||
array('author_id' => 1, 'title' => 'New Fourth Post'),
|
||||
array('author_id' => 1, 'title' => 'New Fifth Post', 'body' => $db->expression('PDO_EXCEPTION()'))
|
||||
);
|
||||
|
||||
try {
|
||||
$Post->saveMany($data, array('validate' => true));
|
||||
$this->fail('No exception thrown');
|
||||
} catch (PDOException $e) {
|
||||
}
|
||||
|
||||
// Otherwise, commit() should be called.
|
||||
$db = $this->_getMockDboSource(array('begin', 'commit', 'rollback'));
|
||||
$db->expects($this->once())->method('begin')->will($this->returnValue(true));
|
||||
$db->expects($this->once())->method('commit');
|
||||
$db->expects($this->never())->method('rollback');
|
||||
|
||||
$Post->setDataSourceObject($db);
|
||||
|
||||
$data = array(
|
||||
array('author_id' => 1, 'title' => 'New Fourth Post'),
|
||||
array('author_id' => 1, 'title' => 'New Fifth Post')
|
||||
);
|
||||
$Post->saveMany($data, array('validate' => true));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -5584,28 +5695,22 @@ class ModelWriteTest extends BaseModelTest {
|
|||
* @return void
|
||||
*/
|
||||
public function testSaveAssociatedTransactionNoRollback() {
|
||||
$testDb = ConnectionManager::getDataSource('test');
|
||||
|
||||
$db = $this->getMock('DboSource', array('connect', 'rollback', 'describe', 'create', 'begin'));
|
||||
$db->columns = $testDb->columns;
|
||||
|
||||
$db->expects($this->once())->method('rollback');
|
||||
$db->expects($this->any())->method('describe')
|
||||
->will($this->returnValue(array(
|
||||
'id' => array('type' => 'integer', 'length' => 11),
|
||||
'title' => array('type' => 'string'),
|
||||
'body' => array('type' => 'text'),
|
||||
'published' => array('type' => 'string')
|
||||
)));
|
||||
$this->loadFixtures('Post', 'Author');
|
||||
|
||||
$Post = new TestPost();
|
||||
$Post->setDataSourceObject($db);
|
||||
$Post->Author->setDataSourceObject($db);
|
||||
|
||||
$Post->Author->validate = array(
|
||||
'user' => array('rule' => array('notEmpty'))
|
||||
);
|
||||
|
||||
// If validation error occurs, rollback() should be called.
|
||||
$db = $this->_getMockDboSource(array('begin', 'commit', 'rollback'));
|
||||
$db->expects($this->once())->method('begin')->will($this->returnValue(true));
|
||||
$db->expects($this->never())->method('commit');
|
||||
$db->expects($this->once())->method('rollback');
|
||||
|
||||
$Post->setDataSourceObject($db);
|
||||
$Post->Author->setDataSourceObject($db);
|
||||
|
||||
$data = array(
|
||||
'Post' => array(
|
||||
'title' => 'New post',
|
||||
|
@ -5618,6 +5723,55 @@ class ModelWriteTest extends BaseModelTest {
|
|||
)
|
||||
);
|
||||
$Post->saveAssociated($data, array('validate' => true, 'atomic' => true));
|
||||
|
||||
// If exception thrown, commit() should be called.
|
||||
$db = $this->_getMockDboSource(array('begin', 'commit', 'rollback'));
|
||||
$db->expects($this->once())->method('begin')->will($this->returnValue(true));
|
||||
$db->expects($this->never())->method('commit');
|
||||
$db->expects($this->once())->method('rollback');
|
||||
|
||||
$Post->setDataSourceObject($db);
|
||||
$Post->Author->setDataSourceObject($db);
|
||||
|
||||
$data = array(
|
||||
'Post' => array(
|
||||
'title' => 'New post',
|
||||
'body' => $db->expression('PDO_EXCEPTION()'),
|
||||
'published' => 'Y'
|
||||
),
|
||||
'Author' => array(
|
||||
'user' => 'New user',
|
||||
'password' => "sekret"
|
||||
)
|
||||
);
|
||||
|
||||
try {
|
||||
$Post->saveAssociated($data, array('validate' => true, 'atomic' => true));
|
||||
$this->fail('No exception thrown');
|
||||
} catch (PDOException $e) {
|
||||
}
|
||||
|
||||
// Otherwise, commit() should be called.
|
||||
$db = $this->_getMockDboSource(array('begin', 'commit', 'rollback'));
|
||||
$db->expects($this->once())->method('begin')->will($this->returnValue(true));
|
||||
$db->expects($this->once())->method('commit');
|
||||
$db->expects($this->never())->method('rollback');
|
||||
|
||||
$Post->setDataSourceObject($db);
|
||||
$Post->Author->setDataSourceObject($db);
|
||||
|
||||
$data = array(
|
||||
'Post' => array(
|
||||
'title' => 'New post',
|
||||
'body' => 'Content',
|
||||
'published' => 'Y'
|
||||
),
|
||||
'Author' => array(
|
||||
'user' => 'New user',
|
||||
'password' => "sekret"
|
||||
)
|
||||
);
|
||||
$Post->saveAssociated($data, array('validate' => true, 'atomic' => true));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -7315,4 +7469,203 @@ class ModelWriteTest extends BaseModelTest {
|
|||
$Model = $event->subject;
|
||||
$Model->getDataSource()->delete($Model, array($Model->alias . '.' . $Model->primaryKey => $Model->id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a convenient mock DboSource
|
||||
*
|
||||
* We cannot call several methods via mock DboSource, such as DboSource::value()
|
||||
* because mock DboSource has no $_connection.
|
||||
* This method helps us to avoid this problem.
|
||||
*
|
||||
* @param array $methods Configurable method names.
|
||||
* @return DboSource
|
||||
*/
|
||||
protected function _getMockDboSource($methods = array()) {
|
||||
$testDb = ConnectionManager::getDataSource('test');
|
||||
|
||||
$passthrough = array_diff(array('value', 'begin', 'rollback', 'commit', 'describe', 'lastInsertId', 'execute'), $methods);
|
||||
|
||||
$methods = array_merge($methods, $passthrough);
|
||||
if (!in_array('connect', $methods)) {
|
||||
$methods[] = 'connect'; // This will be called by DboSource::__construct().
|
||||
}
|
||||
|
||||
$db = $this->getMock('DboSource', $methods);
|
||||
$db->columns = $testDb->columns;
|
||||
$db->startQuote = $testDb->startQuote;
|
||||
$db->endQuote = $testDb->endQuote;
|
||||
|
||||
foreach ($passthrough as $method) {
|
||||
$db->expects($this->any())
|
||||
->method($method)
|
||||
->will($this->returnCallback(array($testDb, $method)));
|
||||
}
|
||||
|
||||
return $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that transactions behave correctly on nested saveMany calls.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testTransactionOnNestedSaveMany() {
|
||||
$this->loadFixtures('Post');
|
||||
$Post = new TestPost();
|
||||
$Post->getEventManager()->attach(array($this, 'nestedSaveMany'), 'Model.afterSave');
|
||||
|
||||
// begin -> [ begin -> commit ] -> commit
|
||||
$db = $this->_getMockDboSource(array('begin', 'commit', 'rollback'));
|
||||
$db->expects($this->exactly(2))->method('begin')->will($this->returnValue(true));
|
||||
$db->expects($this->exactly(2))->method('commit');
|
||||
$db->expects($this->never())->method('rollback');
|
||||
$Post->setDataSourceObject($db);
|
||||
|
||||
$data = array(
|
||||
array('author_id' => 1, 'title' => 'Outer Post'),
|
||||
);
|
||||
$Post->dataForAfterSave = array(
|
||||
array('author_id' => 1, 'title' => 'Inner Post'),
|
||||
);
|
||||
$this->assertTrue($Post->saveMany($data));
|
||||
|
||||
// begin -> [ begin(false) ] -> commit
|
||||
$db = $this->_getMockDboSource(array('begin', 'commit', 'rollback'));
|
||||
$db->expects($this->at(0))->method('begin')->will($this->returnValue(true));
|
||||
$db->expects($this->at(1))->method('begin')->will($this->returnValue(false));
|
||||
$db->expects($this->once())->method('commit');
|
||||
$db->expects($this->never())->method('rollback');
|
||||
$Post->setDataSourceObject($db);
|
||||
|
||||
$data = array(
|
||||
array('author_id' => 1, 'title' => 'Outer Post'),
|
||||
);
|
||||
$Post->dataForAfterSave = array(
|
||||
array('author_id' => 1, 'title' => 'Inner Post'),
|
||||
);
|
||||
$this->assertTrue($Post->saveMany($data));
|
||||
|
||||
// begin -> [ begin -> rollback ] -> rollback
|
||||
$db = $this->_getMockDboSource(array('begin', 'commit', 'rollback'));
|
||||
$db->expects($this->exactly(2))->method('begin')->will($this->returnValue(true));
|
||||
$db->expects($this->never())->method('commit');
|
||||
$db->expects($this->exactly(2))->method('rollback');
|
||||
$Post->setDataSourceObject($db);
|
||||
$data = array(
|
||||
array('author_id' => 1, 'title' => 'Outer Post'),
|
||||
);
|
||||
$Post->dataForAfterSave = array(
|
||||
array('author_id' => 1, 'title' => 'Inner Post', 'body' => $db->expression('PDO_EXCEPTION()')),
|
||||
);
|
||||
|
||||
try {
|
||||
$Post->saveMany($data);
|
||||
$this->fail('No exception thrown');
|
||||
} catch(Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that transaction behaves correctly on nested saveAssociated calls.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testTransactionOnNestedSaveAssociated() {
|
||||
$this->loadFixtures('Author', 'Post');
|
||||
|
||||
$Author = new TestAuthor();
|
||||
$Author->getEventManager()->attach(array($this, 'nestedSaveAssociated'), 'Model.afterSave');
|
||||
|
||||
// begin -> [ begin -> commit ] -> commit
|
||||
$db = $this->_getMockDboSource(array('begin', 'commit', 'rollback'));
|
||||
$db->expects($this->exactly(2))->method('begin')->will($this->returnValue(true));
|
||||
$db->expects($this->exactly(2))->method('commit');
|
||||
$db->expects($this->never())->method('rollback');
|
||||
$Author->setDataSourceObject($db);
|
||||
$Author->Post->setDataSourceObject($db);
|
||||
|
||||
$data = array(
|
||||
'Author' => array('user' => 'outer'),
|
||||
'Post' => array(
|
||||
array('title' => 'Outer Post'),
|
||||
)
|
||||
);
|
||||
$Author->dataForAfterSave = array(
|
||||
'Author' => array('user' => 'inner'),
|
||||
'Post' => array(
|
||||
array('title' => 'Inner Post'),
|
||||
)
|
||||
);
|
||||
$this->assertTrue($Author->saveAssociated($data));
|
||||
|
||||
// begin -> [ begin(false) ] -> commit
|
||||
$db = $this->_getMockDboSource(array('begin', 'commit', 'rollback'));
|
||||
$db->expects($this->at(0))->method('begin')->will($this->returnValue(true));
|
||||
$db->expects($this->at(1))->method('begin')->will($this->returnValue(false));
|
||||
$db->expects($this->once())->method('commit');
|
||||
$db->expects($this->never())->method('rollback');
|
||||
$Author->setDataSourceObject($db);
|
||||
$Author->Post->setDataSourceObject($db);
|
||||
$data = array(
|
||||
'Author' => array('user' => 'outer'),
|
||||
'Post' => array(
|
||||
array('title' => 'Outer Post'),
|
||||
)
|
||||
);
|
||||
$Author->dataForAfterSave = array(
|
||||
'Author' => array('user' => 'inner'),
|
||||
'Post' => array(
|
||||
array('title' => 'Inner Post'),
|
||||
)
|
||||
);
|
||||
$this->assertTrue($Author->saveAssociated($data));
|
||||
|
||||
// begin -> [ begin -> rollback ] -> rollback
|
||||
$db = $this->_getMockDboSource(array('begin', 'commit', 'rollback'));
|
||||
$db->expects($this->exactly(2))->method('begin')->will($this->returnValue(true));
|
||||
$db->expects($this->never())->method('commit');
|
||||
$db->expects($this->exactly(2))->method('rollback');
|
||||
$Author->setDataSourceObject($db);
|
||||
$Author->Post->setDataSourceObject($db);
|
||||
$data = array(
|
||||
'Author' => array('user' => 'outer'),
|
||||
'Post' => array(
|
||||
array('title' => 'Outer Post'),
|
||||
)
|
||||
);
|
||||
$Author->dataForAfterSave = array(
|
||||
'Author' => array('user' => 'inner', 'password' => $db->expression('PDO_EXCEPTION()')),
|
||||
'Post' => array(
|
||||
array('title' => 'Inner Post'),
|
||||
)
|
||||
);
|
||||
|
||||
try {
|
||||
$Author->saveAssociated($data);
|
||||
$this->fail('No exception thrown');
|
||||
} catch(Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A callback for testing nested saveMany.
|
||||
*
|
||||
* @param CakeEvent $event containing the Model
|
||||
* @return void
|
||||
*/
|
||||
public function nestedSaveMany($event) {
|
||||
$Model = $event->subject;
|
||||
$Model->saveMany($Model->dataForAfterSave, array('callbacks' => false));
|
||||
}
|
||||
|
||||
/**
|
||||
* A callback for testing nested saveAssociated.
|
||||
*
|
||||
* @param CakeEvent $event containing the Model
|
||||
* @return void
|
||||
*/
|
||||
public function nestedSaveAssociated($event) {
|
||||
$Model = $event->subject;
|
||||
$Model->saveAssociated($Model->dataForAfterSave, array('callbacks' => false));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue