Browse Source

Fix for bug #45

tags/1.7.2
Alban Jubert 5 years ago
parent
commit
ff6968a098
  1. 20
      src/SaveRelationsBehavior.php
  2. 10
      tests/SaveRelationsBehaviorTest.php

20
src/SaveRelationsBehavior.php

@ -77,6 +77,7 @@ class SaveRelationsBehavior extends Behavior
{ {
return [ return [
BaseActiveRecord::EVENT_BEFORE_VALIDATE => 'beforeValidate', BaseActiveRecord::EVENT_BEFORE_VALIDATE => 'beforeValidate',
BaseActiveRecord::EVENT_AFTER_VALIDATE => 'afterValidate',
BaseActiveRecord::EVENT_AFTER_INSERT => 'afterSave', BaseActiveRecord::EVENT_AFTER_INSERT => 'afterSave',
BaseActiveRecord::EVENT_AFTER_UPDATE => 'afterSave', BaseActiveRecord::EVENT_AFTER_UPDATE => 'afterSave',
BaseActiveRecord::EVENT_BEFORE_DELETE => 'beforeDelete', BaseActiveRecord::EVENT_BEFORE_DELETE => 'beforeDelete',
@ -320,6 +321,17 @@ class SaveRelationsBehavior extends Behavior
} }
/** /**
* After the owner model validation, rollback newly saved hasOne relations if it fails
* @throws DbException
*/
public function afterValidate()
{
if ($this->owner->hasErrors() && !empty($this->_savedHasOneModels)) {
$this->_rollbackSavedHasOneModels();
}
}
/**
* Prepare each related model (validate or save if needed). * Prepare each related model (validate or save if needed).
* This is done during the before validation process to be able * This is done during the before validation process to be able
* to set the related foreign keys for newly created has one records. * to set the related foreign keys for newly created has one records.
@ -350,7 +362,7 @@ class SaveRelationsBehavior extends Behavior
} }
} catch (Exception $e) { } catch (Exception $e) {
Yii::warning(get_class($e) . ' was thrown while saving related records during beforeValidate event: ' . $e->getMessage(), __METHOD__); Yii::warning(get_class($e) . ' was thrown while saving related records during beforeValidate event: ' . $e->getMessage(), __METHOD__);
$this->_rollback(); // Rollback saved records during validation process, if any $this->_rollbackSavedHasOneModels(); // Rollback saved records during validation process, if any
$model->addError($model->formName(), $e->getMessage()); $model->addError($model->formName(), $e->getMessage());
$event->isValid = false; // Stop saving, something went wrong $event->isValid = false; // Stop saving, something went wrong
return false; return false;
@ -443,7 +455,7 @@ class SaveRelationsBehavior extends Behavior
* Delete newly created Has one models if any * Delete newly created Has one models if any
* @throws DbException * @throws DbException
*/ */
private function _rollback() private function _rollbackSavedHasOneModels()
{ {
foreach ($this->_savedHasOneModels as $savedHasOneModel) { foreach ($this->_savedHasOneModels as $savedHasOneModel) {
$savedHasOneModel->delete(); $savedHasOneModel->delete();
@ -506,7 +518,7 @@ class SaveRelationsBehavior extends Behavior
} }
} catch (Exception $e) { } catch (Exception $e) {
Yii::warning(get_class($e) . ' was thrown while saving related records during afterSave event: ' . $e->getMessage(), __METHOD__); Yii::warning(get_class($e) . ' was thrown while saving related records during afterSave event: ' . $e->getMessage(), __METHOD__);
$this->_rollback(); $this->_rollbackSavedHasOneModels();
/*** /***
* Sadly mandatory because the error occurred during afterSave event * Sadly mandatory because the error occurred during afterSave event
* and we don't want the user/developper not to be aware of the issue. * and we don't want the user/developper not to be aware of the issue.
@ -699,7 +711,7 @@ class SaveRelationsBehavior extends Behavior
} }
} catch (Exception $e) { } catch (Exception $e) {
Yii::warning(get_class($e) . ' was thrown while deleting related records during afterDelete event: ' . $e->getMessage(), __METHOD__); Yii::warning(get_class($e) . ' was thrown while deleting related records during afterDelete event: ' . $e->getMessage(), __METHOD__);
$this->_rollback(); $this->_rollbackSavedHasOneModels();
throw $e; throw $e;
} }
} }

10
tests/SaveRelationsBehaviorTest.php

@ -268,6 +268,16 @@ class SaveRelationsBehaviorTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('Microsoft', $project->company->name); $this->assertEquals('Microsoft', $project->company->name);
} }
public function testHasOneRelationsShouldNotBeSavedFail()
{
$project = New Project();
$company = new Company();
$company->name = "Oracle";
$project->company = $company;
$this->assertFalse($project->save(), 'Project could be saved');
$this->assertEmpty(Company::findOne(['name' => 'Oracle']), 'Company still exists');
}
public function testSaveInvalidNewHasOneRelationShouldFail() public function testSaveInvalidNewHasOneRelationShouldFail()
{ {
$project = new Project(); $project = new Project();

Loading…
Cancel
Save