'beforeSave', ActiveRecord::EVENT_BEFORE_UPDATE => 'beforeSave', ActiveRecord::EVENT_AFTER_INSERT => 'afterSave', ActiveRecord::EVENT_AFTER_UPDATE => 'afterSave', ]; } /** * Get $owner primary key to link language model * @return string */ public function getOwnerKey():string { if(!empty( $this->_owner_key )) { return $this->_owner_key; } else { return $this->owner->primaryKey()[ 0 ]; } } /** * Set which attribute to use as $owner primary key to link language model * * @param string $value */ public function setOwnerKey(string $value) { $this->_owner_key = $value; } /** * Get language model attribute that is used as foreign key to $owner * @return string */ public function getLangKey():string { if(!empty( $this->_lang_key )) { return $this->_lang_key; } else { $owner = $this->owner; return $owner::getTableSchema()->name . '_id'; } } /** * Set which attribute to use as language model foreign key to $owner * * @param $value */ public function setLangKey(string $value) { $this->_lang_key = $value; } /** * Additional checks to attach this behavior * * @param ActiveRecord $owner * * @throws InvalidConfigException */ public function attach($owner) { if(empty( $this->object_lang )) { $this->object_lang = $owner::className() . 'Lang'; } elseif(!is_string($this->object_lang)) { throw new InvalidConfigException('Object lang must be fully classified namespaced classname'); } try { $this->object_lang = \Yii::createObject($this->object_lang); } catch(\ReflectionException $exception) { throw new InvalidConfigException('Object lang must be fully classified namespaced classname'); } if(( !$owner instanceof ActiveRecord ) || ( !$this->object_lang instanceof ActiveRecord )) { throw new InvalidConfigException('Object lang must be fully classified namespaced classname'); } parent::attach($owner); } /** * Get query to get all language models for $owner indexed by language_id * @return ActiveQuery */ public function getLangs() { $object_lang = $this->object_lang; $owner = $this->owner; return $owner->hasMany($object_lang::className(), [ $this->getLangKey() => $this->getOwnerKey() ]) ->indexBy('language_id'); } /** * Get query to get language model for $owner for language_id, default to * Language::getCurrent() * * @param int $language_id * * @return ActiveQuery */ public function getLang(int $language_id = NULL) { if(empty( $language_id )) { $language_id = Language::getCurrent()->language_id; } $object_lang = $this->object_lang; $table_name = $object_lang::getTableSchema()->name; $owner = $this->owner; return $owner->hasOne($object_lang::className(), [ $this->getLangKey() => $this->getOwnerKey() ]) ->where([ $table_name . '.language_id' => $language_id ]); } /** * Generate language models for $owner for active languages. If $owner not new and language * models already inserted, models will be filled with them. * @return void */ public function generateLangs() { $owner = $this->owner; $languages = Language::find() ->where([ 'status' => true ]) ->orderBy([ 'language_id' => SORT_ASC ]) ->asArray() ->column(); $object_lang = $this->object_lang; $owner_key = $this->getOwnerKey(); $langs = []; if(!$owner->isNewRecord) { $langs = $this->getLangs() ->andFilterWhere([ 'language_id' => $languages ]) ->orderBy([ 'language_id' => SORT_ASC ]) ->all(); } foreach($languages as $language) { if(!array_key_exists($language, $langs)) { $langs[ $language ] = \Yii::createObject([ 'class' => $object_lang::className(), 'language_id' => $language, $this->getLangKey() => ( $owner->isNewRecord ? NULL : $owner->$owner_key ), ]); } } $this->model_langs = $langs; } /** * Load language models with post data. * * @param Request $request */ public function loadLangs(Request $request) { foreach($request->post($this->object_lang->formName(), []) as $lang => $value) { if(!empty( $this->model_langs[ $lang ] )) { $this->model_langs[ $lang ]->attributes = $value; $this->model_langs[ $lang ]->language_id = $lang; } } } /** * Link language models with $owner by setting language model language key to owner key of * owner * @return bool If $owner is new record then return false else true */ public function linkLangs() { $owner = $this->owner; if($owner->isNewRecord) { return false; } $lang_key = $this->getLangKey(); $owner_key = $this->getOwnerKey(); $model_langs = $this->model_langs; foreach($model_langs as $model_lang) { $model_lang->$lang_key = $owner->$owner_key; } return true; } /** * Try to save all language models to the db. Validation function is run for all models. * @return bool Whether all models are valid */ public function saveLangs() { $success = true; $model_langs = $this->model_langs; foreach($model_langs as $model_lang) { if(!$model_lang->save()) { $success = false; } } return $success; } public function beforeSave($event) { /** * @var ActiveRecord $owner */ $owner = $this->owner; $db = $owner::getDb(); $this->_transaction = $db->beginTransaction(); } public function afterSave($event) { /** * @var ActiveRecord $owner */ $owner = $this->owner; if(!empty( $this->model_langs )) { if($this->linkLangs() && $this->saveLangs()) { $this->_transaction->commit(); $this->_transaction_status = true; } else { $this->_transaction->rollBack(); $this->_transaction_status = false; } } else { $this->_transaction->commit(); $this->_transaction_status = true; } } /** * @return bool */ public function getTransactionStatus():bool { return $this->_transaction_status; } }