Browse Source

Refactoring

tags/1.5.0
Alban Jubert 7 years ago
parent
commit
3075d5e3d0
  1. 169
      src/SaveRelationsBehavior.php

169
src/SaveRelationsBehavior.php

@ -8,7 +8,7 @@ use yii\base\Behavior;
use yii\base\Exception; use yii\base\Exception;
use yii\base\ModelEvent; use yii\base\ModelEvent;
use yii\base\UnknownPropertyException; use yii\base\UnknownPropertyException;
use yii\db\ActiveQueryInterface; use yii\db\ActiveQuery;
use yii\db\BaseActiveRecord; use yii\db\BaseActiveRecord;
use yii\db\Exception as DbException; use yii\db\Exception as DbException;
use yii\db\Transaction; use yii\db\Transaction;
@ -249,13 +249,11 @@ class SaveRelationsBehavior extends Behavior
foreach ($this->_relations as $relationName) { foreach ($this->_relations as $relationName) {
if (array_key_exists($relationName, $this->_oldRelationValue)) { // Relation was not set, do nothing... if (array_key_exists($relationName, $this->_oldRelationValue)) { // Relation was not set, do nothing...
$relation = $model->getRelation($relationName); $relation = $model->getRelation($relationName);
if ($relation instanceof ActiveQueryInterface) { if ($relation->multiple === false && !empty($model->{$relationName})) {
if ($relation->multiple === false && !empty($model->{$relationName})) { Yii::debug("Setting foreign keys for {$relationName}", __METHOD__);
Yii::debug("Setting foreign keys for {$relationName}", __METHOD__); foreach ($relation->link as $relatedAttribute => $modelAttribute) {
foreach ($relation->link as $relatedAttribute => $modelAttribute) { if ($model->{$modelAttribute} !== $model->{$relationName}->{$relatedAttribute}) {
if ($model->{$modelAttribute} !== $model->{$relationName}->{$relatedAttribute}) { $model->{$modelAttribute} = $model->{$relationName}->{$relatedAttribute};
$model->{$modelAttribute} = $model->{$relationName}->{$relatedAttribute};
}
} }
} }
} }
@ -292,7 +290,7 @@ class SaveRelationsBehavior extends Behavior
try { try {
foreach ($this->_relations as $relationName) { foreach ($this->_relations as $relationName) {
if (array_key_exists($relationName, $this->_oldRelationValue)) { // Relation was not set, do nothing... if (array_key_exists($relationName, $this->_oldRelationValue)) { // Relation was not set, do nothing...
/** @var ActiveQueryInterface $relation */ /** @var ActiveQuery $relation */
$relation = $model->getRelation($relationName); $relation = $model->getRelation($relationName);
if (!empty($model->{$relationName})) { if (!empty($model->{$relationName})) {
if ($relation->multiple === false) { if ($relation->multiple === false) {
@ -304,14 +302,14 @@ class SaveRelationsBehavior extends Behavior
// Save Has one relation new record // Save Has one relation new record
$this->saveModelRecord($model->{$relationName}, $event, $pettyRelationName, $relationName); $this->saveModelRecord($model->{$relationName}, $event, $pettyRelationName, $relationName);
} else { } else {
$this->validateRelationModel($pettyRelationName, $relationName, $relationModel, $event); $this->validateRelationModel($pettyRelationName, $relationName, $relationModel);
} }
} else { } else {
// Save Has many relations new records // Save Has many relations new records
/** @var BaseActiveRecord $relationModel */ /** @var BaseActiveRecord $relationModel */
foreach ($model->{$relationName} as $i => $relationModel) { foreach ($model->{$relationName} as $i => $relationModel) {
$pettyRelationName = Inflector::camel2words($relationName, true) . " #{$i}"; $pettyRelationName = Inflector::camel2words($relationName, true) . " #{$i}";
$this->validateRelationModel($pettyRelationName, $relationName, $relationModel, $event); $this->validateRelationModel($pettyRelationName, $relationName, $relationModel);
} }
} }
} }
@ -404,8 +402,8 @@ class SaveRelationsBehavior extends Behavior
public function afterSave() public function afterSave()
{ {
if ($this->_relationsSaveStarted === false) { if ($this->_relationsSaveStarted === false) {
/** @var BaseActiveRecord $model */ /** @var BaseActiveRecord $owner */
$model = $this->owner; $owner = $this->owner;
$this->_relationsSaveStarted = true; $this->_relationsSaveStarted = true;
// Populate relations with updated values // Populate relations with updated values
foreach ($this->_newRelationValue as $name => $value) { foreach ($this->_newRelationValue as $name => $value) {
@ -415,12 +413,12 @@ class SaveRelationsBehavior extends Behavior
foreach ($this->_relations as $relationName) { foreach ($this->_relations as $relationName) {
if (array_key_exists($relationName, $this->_oldRelationValue)) { // Relation was not set, do nothing... if (array_key_exists($relationName, $this->_oldRelationValue)) { // Relation was not set, do nothing...
Yii::debug("Linking {$relationName} relation", __METHOD__); Yii::debug("Linking {$relationName} relation", __METHOD__);
/** @var ActiveQueryInterface $relation */ /** @var ActiveQuery $relation */
$relation = $model->getRelation($relationName); $relation = $owner->getRelation($relationName);
if ($relation->multiple === true) { // Has many relation if ($relation->multiple === true) { // Has many relation
$this->_afterSaveHasManyRelation($model, $relationName); $this->_afterSaveHasManyRelation($relationName);
} else { // Has one relation } else { // Has one relation
$this->_afterSaveHasOneRelation($model, $relationName); $this->_afterSaveHasOneRelation($relationName);
} }
unset($this->_oldRelationValue[$relationName]); unset($this->_oldRelationValue[$relationName]);
} }
@ -434,7 +432,7 @@ class SaveRelationsBehavior extends Behavior
***/ ***/
throw $e; throw $e;
} }
$model->refresh(); $owner->refresh();
$this->_relationsSaveStarted = false; $this->_relationsSaveStarted = false;
if (($this->_transaction instanceof Transaction) && $this->_transaction->isActive) { if (($this->_transaction instanceof Transaction) && $this->_transaction->isActive) {
$this->_transaction->commit(); $this->_transaction->commit();
@ -507,7 +505,7 @@ class SaveRelationsBehavior extends Behavior
foreach ($this->_relations as $relationName) { foreach ($this->_relations as $relationName) {
$relation = $model->getRelation($relationName); $relation = $model->getRelation($relationName);
$modelClass = $relation->modelClass; $modelClass = $relation->modelClass;
/** @var ActiveQueryInterface $relationalModel */ /** @var ActiveQuery $relationalModel */
$relationalModel = new $modelClass; $relationalModel = new $modelClass;
$formName = $relationalModel->formName(); $formName = $relationalModel->formName();
if (array_key_exists($formName, $data)) { if (array_key_exists($formName, $data)) {
@ -517,92 +515,107 @@ class SaveRelationsBehavior extends Behavior
} }
/** /**
* @param $owner
* @param $relationName * @param $relationName
* @throws \RuntimeException
* @throws DbException * @throws DbException
*/ */
public function _afterSaveHasManyRelation($owner, $relationName) public function _afterSaveHasManyRelation($relationName)
{ {
$owner = $this->owner;
$relation = $owner->getRelation($relationName); $relation = $owner->getRelation($relationName);
// Process new relations if ($this->_hasActiveRelationTrait($relation)) {
$existingRecords = []; // Process new relations
/** @var ActiveQueryInterface $relationModel */ $existingRecords = [];
foreach ($owner->{$relationName} as $i => $relationModel) { /** @var ActiveQuery $relationModel */
if ($relationModel->isNewRecord) { foreach ($owner->{$relationName} as $i => $relationModel) {
if ($relation->via !== null) { if ($relationModel->isNewRecord) {
if ($relation->via !== null) {
if ($relationModel->validate()) {
$relationModel->save();
} else {
$pettyRelationName = Inflector::camel2words($relationName, true) . " #{$i}";
$this->_addError($relationModel, $owner, $relationName, $pettyRelationName);
throw new DbException("Related record {$pettyRelationName} could not be saved.");
}
}
$junctionTableColumns = $this->_getJunctionTableColumns($relationName, $relationModel);
$owner->link($relationName, $relationModel, $junctionTableColumns);
} else {
$existingRecords[] = $relationModel;
}
if (count($relationModel->dirtyAttributes)) {
if ($relationModel->validate()) { if ($relationModel->validate()) {
$relationModel->save(); $relationModel->save();
} else { } else {
$pettyRelationName = Inflector::camel2words($relationName, true) . " #{$i}"; $pettyRelationName = Inflector::camel2words($relationName, true);
$this->_addError($relationModel, $owner, $relationName, $pettyRelationName); $this->_addError($relationModel, $owner, $relationName, $pettyRelationName);
throw new DbException("Related record {$pettyRelationName} could not be saved."); throw new DbException("Related record {$pettyRelationName} could not be saved.");
} }
} }
$junctionTableColumns = $this->_getJunctionTableColumns($relationName, $relationModel);
$owner->link($relationName, $relationModel, $junctionTableColumns);
} else {
$existingRecords[] = $relationModel;
} }
if (count($relationModel->dirtyAttributes)) { $junctionTablePropertiesUsed = array_key_exists($relationName, $this->_relationsExtraColumns);
if ($relationModel->validate()) {
$relationModel->save();
} else {
$pettyRelationName = Inflector::camel2words($relationName, true);
$this->_addError($relationModel, $owner, $relationName, $pettyRelationName);
throw new DbException("Related record {$pettyRelationName} could not be saved.");
}
}
}
$junctionTablePropertiesUsed = array_key_exists($relationName, $this->_relationsExtraColumns);
// Process existing added and deleted relations // Process existing added and deleted relations
list($addedPks, $deletedPks) = $this->_computePkDiff( list($addedPks, $deletedPks) = $this->_computePkDiff(
$this->_oldRelationValue[$relationName], $this->_oldRelationValue[$relationName],
$existingRecords, $existingRecords,
$junctionTablePropertiesUsed $junctionTablePropertiesUsed
); );
// Deleted relations // Deleted relations
$initialModels = ArrayHelper::index($this->_oldRelationValue[$relationName], function (BaseActiveRecord $model) { $initialModels = ArrayHelper::index($this->_oldRelationValue[$relationName], function (BaseActiveRecord $model) {
return implode('-', $model->getPrimaryKey(true));
});
$initialRelations = $owner->{$relationName};
foreach ($deletedPks as $key) {
$owner->unlink($relationName, $initialModels[$key], true);
}
// Added relations
$actualModels = ArrayHelper::index(
$junctionTablePropertiesUsed ? $initialRelations : $owner->{$relationName},
function (BaseActiveRecord $model) {
return implode('-', $model->getPrimaryKey(true)); return implode('-', $model->getPrimaryKey(true));
});
$initialRelations = $owner->{$relationName};
foreach ($deletedPks as $key) {
$owner->unlink($relationName, $initialModels[$key], true);
}
// Added relations
$actualModels = ArrayHelper::index(
$junctionTablePropertiesUsed ? $initialRelations : $owner->{$relationName},
function (BaseActiveRecord $model) {
return implode('-', $model->getPrimaryKey(true));
}
);
foreach ($addedPks as $key) {
$junctionTableColumns = $this->_getJunctionTableColumns($relationName, $actualModels[$key]);
$owner->link($relationName, $actualModels[$key], $junctionTableColumns);
} }
);
foreach ($addedPks as $key) {
$junctionTableColumns = $this->_getJunctionTableColumns($relationName, $actualModels[$key]);
$owner->link($relationName, $actualModels[$key], $junctionTableColumns);
} }
} }
/** /**
* @param $owner
* @param $relationName * @param $relationName
*/ */
private function _afterSaveHasOneRelation($owner, $relationName) private function _afterSaveHasOneRelation($relationName)
{ {
if ($this->_oldRelationValue[$relationName] !== $owner->{$relationName}) { $owner = $this->owner;
if ($owner->{$relationName} instanceof BaseActiveRecord) { $relation = $owner->getRelation($relationName);
$owner->link($relationName, $owner->{$relationName});
} else { if ($this->_hasActiveRelationTrait($relation)) {
if ($this->_oldRelationValue[$relationName] instanceof BaseActiveRecord) { if ($this->_oldRelationValue[$relationName] !== $owner->{$relationName}) {
$owner->unlink($relationName, $this->_oldRelationValue[$relationName]); if ($owner->{$relationName} instanceof BaseActiveRecord) {
$owner->link($relationName, $owner->{$relationName});
} else {
if ($this->_oldRelationValue[$relationName] instanceof BaseActiveRecord) {
$owner->unlink($relationName, $this->_oldRelationValue[$relationName]);
}
} }
} }
if ($owner->{$relationName} instanceof BaseActiveRecord) {
$owner->{$relationName}->save();
}
} }
if ($owner->{$relationName} instanceof BaseActiveRecord) { }
$owner->{$relationName}->save();
} /**
* @param ActiveQuery $relation
* @return bool
*/
private function _hasActiveRelationTrait(ActiveQuery $relation)
{
$relationTraits = class_uses($relation);
return in_array('yii\db\ActiveRelationTrait', $relationTraits);
} }
} }

Loading…
Cancel
Save