Skip to content

Instantly share code, notes, and snippets.

@tanakahisateru
Last active October 7, 2017 08:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save tanakahisateru/4266408 to your computer and use it in GitHub Desktop.
Save tanakahisateru/4266408 to your computer and use it in GitHub Desktop.
MANY_MANY relation support behavior for Yii framework
<?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