'linkObject', ]; } /** * @inheritdoc */ public function attach($owner) { parent::attach($owner); $this->checkValidity(); } /** * Save link object. * * @param Event $event Handler for insertion success * * @return \yii\db\ActiveRecord * @throws \yii\base\InvalidConfigException */ public function linkObject($event = null) { $owner = $this->owner; /** * @var ActiveRecord $linkClassInstance */ $linkClassInstance = $this->linkClassInstance; $value = null; if ($owner->canGetProperty($this->parentKey, true, false)) { $key = $this->parentKey; $value = $owner->$key; } else { throw new InvalidConfigException(\Yii::t('core', 'Can\'t get $parentKey property')); } if (empty( $value )) { throw new InvalidConfigException(\Yii::t('core', "Can't get parent key {$key}")); } $linkClassInstance->setAttribute($this->linkKey, $value); foreach ($this->detachBehaviors as $name) { if (is_string($name)) { $linkClassInstance->detachBehavior($name); } } $linkClassInstance->save(); return $linkClassInstance; } /** * Check if $linkClassInstance ready to be inserted, otherwise throw exception * * @throws \yii\base\InvalidConfigException */ protected function checkValidity() { $owner = $this->owner; if (empty( $this->linkClass )) { throw new InvalidConfigException(\Yii::t('core', 'Link class must be set')); } else { $this->linkClassInstance = \Yii::createObject($this->linkClass); if (!$this->linkClassInstance instanceof ActiveRecord) { throw new InvalidConfigException( \Yii::t('core', 'Link class must be instance of yii\db\ActiveRecord') ); } } /** @noinspection PhpParamsInspection */ $this->ensureAttribute('parentKey', $owner); /** @noinspection PhpParamsInspection */ $this->ensureAttribute('linkKey', $this->linkClassInstance); if (empty( $this->parentKey ) || empty( $this->linkKey )) { throw new InvalidConfigException( \Yii::t( 'core', '$parentKey and $linkKey must be set or use ActiveRecord to get its primaryKey()[0] attributes.' ) ); } if (!$owner->canGetProperty($this->parentKey, true, false)) { throw new InvalidConfigException(\Yii::t('core', 'Can\'t get $parentKey property')); } } /** * Bind keys to default properties if keys empty. * * @param string $property Property to bind * @param Object $object Property owner */ protected function ensureAttribute(string $property, Object $object) { if (empty( $this->$property )) { if ($object instanceof ActiveRecord) { $pks = $object->primaryKey(); if (!empty( $pks )) { $this->$property = $pks[ 0 ]; } } } } /** * Generate link object an d save it directly. * * @return ActiveRecord */ public function ensureExistance() { $link = $this->getLinkObject(); if (!$link) { $link = $this->linkObject(); } return $link; } /** * Get link object * * @param bool $throw Whether to throw exception if link object not found * * @return null|\yii\db\ActiveRecord * @throws \yii\web\NotFoundHttpException */ public function getLinkObject(bool $throw = false) { /** * @var ActiveRecord $linkClassInstance */ $linkClassInstance = $this->linkClassInstance; $owner = $this->owner; $parentKey = $this->parentKey; /** * @var ActiveRecord $result */ $result = $linkClassInstance::find() ->where([ $this->linkKey => $this->owner->$parentKey ]) ->one(); if ($throw && !$result) { throw new NotFoundHttpException(\Yii::t('core', "Linked object for {$owner::className()} not found")); } return $result; } }