Last active
August 29, 2015 14:27
-
-
Save hom3chuk/1f0e9e9076c5f7c4480a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class ActiveRecord extends CActiveRecord | |
{ | |
/** | |
* Updates cross-table for MANY_MANY relations, no AR class for cross-table needed. | |
* This method will delete all existing cross-table records not present in relatedIdList, then populate cross-table with new relations from relatedIdList in one transaction. | |
* @param string $relationName relation name to be updated (as given in CActiveRecord::relations()) | |
* @param array $relatedIdList list of related ids OR list of related ARs | |
* @param string $idKey PK accessor for related entity (used only if list of ARs passed in relatedIdList). Defaults to `id`, which is ok for almost every AR. | |
* @throws CDbException | |
*/ | |
public function setRelated($relationName, array $relatedIdList, $idKey = 'id'){ | |
// getting relation options | |
$crossTableTempInfo = explode('(', $this->relations()[$relationName][2]); | |
$crossTableMeta['table_name'] = trim($crossTableTempInfo[0], "() \t\n\r\0\x0B"); | |
$crossTableMeta['key_1'] = trim(explode(',', $crossTableTempInfo[1])[0], "() \t\n\r\0\x0B"); | |
$crossTableMeta['key_2'] = trim(explode(',', $crossTableTempInfo[1])[1], "() \t\n\r\0\x0B"); | |
// filtering out ids | |
$flat = []; | |
foreach ( $relatedIdList as $currentRelated ){ | |
if ( is_object($currentRelated) ){ | |
$flat[] = $currentRelated->$idKey; | |
} else { | |
$flat[] = $currentRelated; | |
} | |
} | |
$related = []; | |
foreach ( $this->$relationName as $currentRelated ){ | |
$related[] = $currentRelated->$idKey; | |
} | |
// relations to connect | |
$connect = array_diff($flat, $related); | |
// relations to disconnect | |
$disconnect = array_diff($related, $flat); | |
$transaction = $this->dbConnection->beginTransaction(); | |
// connecting | |
if ( !empty($connect) ){ | |
$params = []; | |
foreach ( $connect as $key => $value ){ | |
$params[':rel_con_v_'.(string)$key] = $value; | |
} | |
$query = 'INSERT INTO ' | |
. $crossTableMeta['table_name'] | |
. ' (' | |
. $crossTableMeta['key_2'] | |
. ', ' | |
. $crossTableMeta['key_1'] | |
. ') VALUES (' . implode(', :rel_pk), (', array_keys($params)) | |
. ', :rel_pk)'; | |
/** @var CDbCommand $connectRelatedCommand */ | |
$connectRelatedCommand = Yii::app()->db->createCommand($query); | |
$connectRelatedCommand->bindValues($params + [':rel_pk' => $this->primaryKey]); | |
$connectRelatedCommand->execute(); | |
} | |
// disconnecting | |
if ( !empty($disconnect) ){ | |
$criteria = new CDbCriteria(); | |
$criteria->addInCondition($crossTableMeta['key_2'], $disconnect); | |
$criteria->addCondition($crossTableMeta['key_1'] . '=:rel_pk'); | |
/** @var CDbCommand $clearRelatedCommand */ | |
$clearRelatedCommand = Yii::app()->db->createCommand('DELETE FROM ' . $crossTableMeta['table_name'] . ' WHERE ' . $criteria->condition); | |
$clearRelatedCommand->bindValues($criteria->params + [':rel_pk' => $this->primaryKey]); | |
$clearRelatedCommand->execute(); | |
} | |
$transaction->commit(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Given
used for checkbox groups: