/** * Destroys the relationship between two models. * * The model with the foreign key of the relationship will be deleted if `$delete` is true. * Otherwise, the foreign key will be set null and the model will be saved without validation. * * @param string $name the case sensitive name of the relationship. * @param ActiveRecord $model the model to be unlinked from the current one. * @param boolean $delete whether to delete the model that contains the foreign key. * If false, the model's foreign key will be set null and saved. * If true, the model containing the foreign key will be deleted. * @throws InvalidCallException if the models cannot be unlinked */ public function unlink($name, $model, $delete = false) { $relation = $this->getRelation($name); if ($relation->via !== null) { if (is_array($relation->via)) { /** @var ActiveRelation $viaRelation */ list($viaName, $viaRelation) = $relation->via; $viaClass = $viaRelation->modelClass; unset($this->_related[$viaName]); } else { $viaRelation = $relation->via; $viaTable = reset($relation->via->from); } $columns = []; foreach ($viaRelation->link as $a => $b) { $columns[$a] = $this->{$b}; } foreach ($relation->link as $a => $b) { $columns[$b] = $model->{$a}; } if (is_array($relation->via)) { /** @var $viaClass ActiveRecord */ if ($delete) { $viaClass::deleteAll($columns); } else { $nulls = []; foreach (array_keys($columns) as $a) { $nulls[$a] = null; } $viaClass::updateAll($nulls, $columns); } } else { /** @var $viaTable string */ $command = static::getDb()->createCommand(); if ($delete) { $command->delete($viaTable, $columns)->execute(); } else { $nulls = []; foreach (array_keys($columns) as $a) { $nulls[$a] = null; } $command->update($viaTable, $nulls, $columns)->execute(); } } } else { $p1 = $model->isPrimaryKey(array_keys($relation->link)); $p2 = $this->isPrimaryKey(array_values($relation->link)); if ($p1 && $p2 || $p2) { foreach ($relation->link as $a => $b) { $model->{$a} = null; } $delete ? $model->delete() : $model->save(false); } elseif ($p1) { foreach ($relation->link as $b) { $this->{$b} = null; } $delete ? $this->delete() : $this->save(false); } else { throw new InvalidCallException('Unable to unlink models: the link does not involve any primary key.'); } } if (!$relation->multiple) { unset($this->_related[$name]); } elseif (isset($this->_related[$name])) { /** @var ActiveRecord $b */ foreach ($this->_related[$name] as $a => $b) { if ($model->getPrimaryKey() == $b->getPrimaryKey()) { unset($this->_related[$name][$a]); } } } }
/** * @param string $name relation name * @param ActiveRecord $model * @param array $extraColumns * @throws \yii\db\Exception */ public function link($name, $model, $extraColumns = []) { $relation = $this->getOwnerRelation($name); if ($relation->via !== null) { if ($this->owner->getIsNewRecord() || $model->getIsNewRecord()) { throw new InvalidCallException('Unable to link models: both models must NOT be newly created.'); } if (is_array($relation->via)) { /* @var $viaRelation ActiveQuery */ list($viaName, $viaRelation) = $relation->via; $viaClass = $viaRelation->modelClass; // unset $viaName so that it can be reloaded to reflect the change // unset($this->_related[$viaName]); } else { $viaRelation = $relation->via; $viaTable = reset($relation->via->from); } $columns = []; foreach ($viaRelation->link as $a => $b) { $columns[$a] = $this->owner->{$b}; } foreach ($relation->link as $a => $b) { $columns[$b] = $model->{$a}; } foreach ($extraColumns as $k => $v) { $columns[$k] = $v; } if (is_array($relation->via)) { /* @var $viaClass ActiveRecordInterface */ /* @var $record ActiveRecordInterface */ $record = new $viaClass(); foreach ($columns as $column => $value) { $record->{$column} = $value; } $record->insert(false); } else { /* @var $viaTable string */ ActiveRecord::getDb()->createCommand()->insert($viaTable, $columns)->execute(); } } else { $p1 = $model->isPrimaryKey(array_keys($relation->link)); $p2 = $this->owner->isPrimaryKey(array_values($relation->link)); if ($p1 && $p2) { if ($this->owner->getIsNewRecord() && $model->getIsNewRecord()) { throw new InvalidCallException('Unable to link models: both models are newly created.'); } elseif ($this->owner->getIsNewRecord()) { $this->bindModels(array_flip($relation->link), $this->owner, $model); } else { $this->bindModels($relation->link, $model, $this->owner); } } elseif ($p1) { $this->bindModels(array_flip($relation->link), $this->owner, $model); } elseif ($p2) { $this->bindModels($relation->link, $model, $this->owner); } else { throw new InvalidCallException('Unable to link models: the link does not involve any primary key.'); } } // // update lazily loaded related objects // if (!$relation->multiple) { // $this->_related[$name] = $model; // } elseif (isset($this->_related[$name])) { // if ($relation->indexBy !== null) { // $indexBy = $relation->indexBy; // $this->_related[$name][$model->$indexBy] = $model; // } else { // $this->_related[$name][] = $model; // } // } }