Last active
October 7, 2017 08:34
-
-
Save tanakahisateru/4266408 to your computer and use it in GitHub Desktop.
MANY_MANY relation support behavior for Yii framework
This file contains 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 | |
/** | |
* This behavior is for a model having one or more MANY-MANY relations. | |
* | |
* You need a junction table: | |
* | |
* CREATE_TABLE self_target ( | |
* self_id integer(11) NOT NULL, | |
* target_id integer(11) NOT NULL, | |
* ... | |
* ); | |
* | |
* and also definition like as: | |
* | |
* public function relations() | |
* { | |
* return array( | |
* 'target' => array(self::MANY_MANY, 'Target', 'self_target(self_id,target_id)', ...), | |
* ); | |
* } | |
*/ | |
class ManyManySupport extends CActiveRecordBehavior | |
{ | |
/** | |
* @param string $relationName | |
* @throws CDbException | |
* @return CManyManyRelation | |
*/ | |
protected function getManyManyRelation($relationName) | |
{ | |
foreach ($this->owner->metaData->relations as $rel) { | |
if ($rel->name == $relationName) { | |
if ($rel instanceof CManyManyRelation) { | |
return $rel; | |
} | |
else { | |
throw new CDbException('The relation was not defined as Many-Many: ' . $relationName); | |
} | |
} | |
} | |
throw new CDbException('No such relation: ' . $relationName); | |
} | |
/** | |
* @param CActiveRecord $target | |
* @throws CDbException | |
* @return void | |
*/ | |
protected function checkExistence($target) { | |
if ($this->owner->isNewRecord) { | |
throw new CDbException("Relation owner is not saved."); | |
} | |
if ($target->isNewRecord) { | |
throw new CDbException("Relation target is not saved."); | |
} | |
} | |
/** | |
* Extended function | |
* | |
* @param string $relationName | |
* @param CActiveRecord $target | |
* @return boolean | |
*/ | |
public function isManyManyPeer($relationName, $target) | |
{ | |
$this->checkExistence($target); | |
return $this->isManyManyPeerByPk($relationName, $target->primaryKey); | |
} | |
/** | |
* Extended function | |
* | |
* @param string $relationName | |
* @param int $foreignPk | |
* @return boolean | |
*/ | |
public function isManyManyPeerByPk($relationName, $foreignPk) | |
{ | |
$cb = $this->owner->commandBuilder; | |
$rel = $this->getManyManyRelation($relationName); | |
return $cb->createCountCommand($rel->junctionTableName, $cb->createCriteria()->addColumnCondition(array( | |
$rel->junctionForeignKeys[0]=>$this->owner->primaryKey, | |
$rel->junctionForeignKeys[1]=>$foreignPk, | |
)))->queryScalar() > 0 ? true : false; | |
} | |
/** | |
* Extended function | |
* | |
* @param string $relationName | |
* @param CActiveRecord $target | |
* @return void | |
* @throws CDbException | |
*/ | |
public function bindManyMany($relationName, $target) | |
{ | |
if ($this->isManyManyPeer($relationName, $target)) { | |
return; | |
} | |
$this->__bindManyManyInternal($relationName, $target->primaryKey); | |
} | |
/** | |
* Extended function | |
* | |
* @param string $relationName | |
* @param int $foreignPk | |
* @return void | |
* @throws CDbException | |
*/ | |
public function bindManyManyByPk($relationName, $foreignPk) | |
{ | |
if ($this->isManyManyPeerByPk($relationName, $foreignPk)) { | |
return; | |
} | |
$this->__bindManyManyInternal($relationName, $foreignPk); | |
} | |
/** | |
* Extended function | |
* | |
* @param string $relationName | |
* @param CActiveRecord $target | |
* @return void | |
* @throws CDbException | |
*/ | |
public function unbindManyMany($relationName, $target) | |
{ | |
if (!$this->isManyManyPeer($relationName, $target)) { | |
return; | |
} | |
$this->__unbindManyManyInternal($relationName, $target->primaryKey); | |
} | |
/** | |
* Extended function | |
* | |
* @param string $relationName | |
* @param int $foreignPk | |
* @return void | |
* @throws CDbException | |
*/ | |
public function unbindManyManyByPk($relationName, $foreignPk) | |
{ | |
if (!$this->isManyManyPeerByPk($relationName, $foreignPk)) { | |
return; | |
} | |
$this->__unbindManyManyInternal($relationName, $foreignPk); | |
} | |
/** | |
* @param $relationName | |
* @param $foreignPk | |
*/ | |
protected function __bindManyManyInternal($relationName, $foreignPk) | |
{ | |
// Already checked: $this->checkExistence($target); | |
$cb = $this->owner->commandBuilder; | |
$rel = $this->getManyManyRelation($relationName); | |
$cb->createInsertCommand( | |
$rel->junctionTableName, | |
array( | |
$rel->junctionForeignKeys[0] => $this->owner->id, | |
$rel->junctionForeignKeys[1] => $foreignPk, | |
) | |
)->execute(); | |
} | |
/** | |
* @param $relationName | |
* @param $foreignPk | |
*/ | |
protected function __unbindManyManyInternal($relationName, $foreignPk) | |
{ | |
// Already checked: $this->checkExistence($target); | |
$cb = $this->owner->commandBuilder; | |
$rel = $this->getManyManyRelation($relationName); | |
$cb->createDeleteCommand( | |
$rel->junctionTableName, | |
$cb->createCriteria()->addColumnCondition( | |
array( | |
$rel->junctionForeignKeys[0] => $this->owner->id, | |
$rel->junctionForeignKeys[1] => $foreignPk, | |
) | |
) | |
)->execute(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment