relations as $relation_key => &$relation) { if (is_string($relation)) { // Get data from module's data $relation_entity = $relation; $relation = $this->_getRelationParams($relation_key); $relation['inner'] = $relation[$relation_entity]; $relation['outer'] = $relation[$relation_entity == 'entity1' ? 'entity2' : 'entity1']; $relation['linked_table'] = $relation['via']['model']::tableName(); if (!empty($relation['via']['alias'])) { $relation['linked_alias'] = $relation['via']['alias']; } } $this->fields[$relation['field']] = $relation_key; } } /* * Events for auto-drive relations data */ public function events() { return [ ActiveRecord::EVENT_AFTER_INSERT => 'relationsAfterSave', ActiveRecord::EVENT_AFTER_UPDATE => 'relationsAfterSave', ActiveRecord::EVENT_BEFORE_DELETE => 'relationBeforeDelete', ]; } public function relationsAfterSave($insert) { if (is_array($modelPrimaryKey = $this->owner->getPrimaryKey())) { throw new ErrorException('This behavior does not support composite primary keys'); } foreach ($this->relations as $relation_key => $relation) { if (empty($relation['field']) || !is_array($this->{$relation['field']})) continue; $values = $this->{$relation['field']}; /** @var ActiveRecord $model */ $model = new $relation['inner']['model']; $connection = $model::getDb(); $transaction = $connection->beginTransaction(); $delete_where = [$relation['inner']['linked_key'] => $this->owner->{$relation['inner']['key']}]; if (!empty($relation['linked_alias'])) { $delete_where[$relation['linked_alias']] = $relation_key; } try { // Delete all links from viaTable $connection->createCommand() ->delete ( $relation['linked_table'], $delete_where ) ->execute(); if (!empty($values)) { foreach($values as $value) { $insertData = [ $relation['inner']['linked_key'] => $this->owner->{$relation['inner']['key']}, $relation['outer']['linked_key'] => $value ]; if (!empty($relation['linked_alias'])) { $insertData[$relation['linked_alias']] = $relation_key; } $connection->createCommand() ->insert ( $relation['linked_table'], $insertData ) ->execute(); } } $transaction->commit(); // $model->link($relation_key, ) } catch (Exception $ex) { // var_dump($relation_key, $relation);exit; $transaction->rollback(); throw $ex; } } } public function relationBeforeDelete() { if (is_array($modelPrimaryKey = $this->owner->getPrimaryKey())) { throw new ErrorException('This behavior does not support composite primary keys'); } foreach ($this->relations as $relation_key => $relation) { if (empty($relation['field'])) continue; $values = $this->{$relation['field']}; /** @var ActiveRecord $model */ $model = new $relation['inner']['model']; $connection = $model::getDb(); $transaction = $connection->beginTransaction(); // @todo Refix to ActiveRecord format try { // Delete all links from viaTable $connection->createCommand() ->delete ( $relation['linked_table'], [$relation['inner']['linked_key'] => $this->owner->{$relation['inner']['key']}] ) ->execute(); $transaction->commit(); } catch (Exception $ex) { $transaction->rollback(); throw $ex; } } } /** * Get related data for $relation * @params string $relation Relation key */ public function getRelations($relation) { $relation = $this->_getRelation($relation); return $this->owner ->hasMany($relation['outer']['model'], [$relation['outer']['key'] => $relation['outer']['linked_key']]) ->viaTable($relation['linked_table'], [$relation['inner']['linked_key'] => $relation['inner']['key']]); } /* * Get relation params for $relation * @param string $relation Relation key */ protected function _getRelation($relation) { $relation = strtolower($relation); return isset($this->relations[$relation]) ? $this->relations[$relation] : null; } /** * Return relation data from main app config * @params string $section Relations key */ protected function _getRelationParams($section) { $relation = relationHelper::getRelation($section); if (!$relation) throw new Exception('Relation "' . $section . '" not set on this application.'); return $relation; } protected function _getRelationNameByField($field) { return isset($this->fields[$field]) ? $this->fields[$field] : null; } protected function _getRelationByField($field) { return ( isset($this->fields[$field]) && isset($this->relations[$this->fields[$field]]) ) ? $this->relations[$this->fields[$field]] : null; } /** * @inheritdoc */ public function canGetProperty($name, $checkVars = true) { return true; } /** * @inheritdoc */ public function canSetProperty($name, $checkVars = true) { return array_key_exists($name, $this->fields) ? true : parent::canSetProperty($name, $checkVars = true); } /** * @inheritdoc */ public function __set($name, $value) { if (isset($this->fields[$name])) { $this->values[$name] = $value; } } /** * @inheritdoc */ public function __get($name) { if (isset($this->values[$name])) { return $this->values[$name]; } else { $relation_key = $this->_getRelationNameByField($name); if (!$relation_key) return; return $this->getRelations($relation_key); } } }