yii relation for multiple column foreign keys

2019-06-14 04:42发布

I have a table Friend (PersonA, PersonB). These are foreign keys of Person(id, name).

I want to create a Yii relation between them. This is what I have come up with:

public function relations() {
    return array(
        'friends1' => array(self::HAS_MANY, 'Friend', 'PersonA'),
        'friends2' => array(self::HAS_MANY, 'Friend', 'PersonB'),
    );
}

Is there a way to combine these two relations into one? I was hoping for something like this:

public function relations() {
    return array(
        'allFriends' => array(self::HAS_MANY, 'Friend', 'PersonA, PersonB'),
    );
}

Any ideas?

EDIT #1:

For completeness, let's also imagine that I want to order friends1 and friends2 like this:

public function relations() {
    return array(
        'friends1' => array(self::HAS_MANY, 'Friend', 'PersonA', 'order'=>'id ASC'),
        'friends2' => array(self::HAS_MANY, 'Friend', 'PersonB', 'order'=>'id ASC'),
    );
}

2条回答
迷人小祖宗
2楼-- · 2019-06-14 05:27

I had the exact same thing come up in something I was working on. What I did is I created another function to compile the two relations into one array. The reason for this is because even if you were to get the two relationships combined, each time you would still need to test to see if PersonA or PersonB is the current user's id and use the other id to pull the Friends info. Here is the function I created in my model:

public function getFriends() {
    $all_friends = array();
    foreach($this->friends1 as $friend) {
        if($friend->PersonA == $this->id) {
            $all_friends[] = $friend->PersonA;
        } else {
            $all_friends[] = $friend->PersonB;
        }
    }
    foreach($this->friends2 as $friend) {
        if($friend->PersonA != $this->id) {
            $all_friends[] = $friend->PersonA;
        } else {
            $all_friends[] = $friend->PersonB;
        }
    }
    return $all_friends;
}

Another options:

public function getFriends() {
    $criteria = new CDbCriteria;
    $criteria->compare('PersonA',$this->id);

    $criteria2 = new CDbCriteria;
    $criteria2->compare('PersonB',$this->id);

    $criteria->mergeWith($criteria2,'OR');

    $friends = Challenge::model()->findAll($criteria);
    return $friends;
}

Then for any Person you can just say:

$person = Person::model()->findByPk(1);
$friends = $person->friends;

Or instead of an array you could send back an CActiveDataProvider that you could do sorts and other things with. You could do this:

public function getFriends() {
    $criteria = new CDbCriteria;
    $criteria->compare('PersonA',$this->id);

    $criteria2 = new CDbCriteria;
    $criteria2->compare('PersonB',$this->id);

    $criteria->mergeWith($criteria2,'OR');

    return new CActiveDataProvider('Friend', array(
        'criteria' => $criteria,
    ));
}

Then since you have CActiveDataProvider you can sort:

$friends = $user->friends->getData(); //not sorted or anything
//or you can manipulate the CActiveDataprovider
$data = $user->friends;
$data->setSort(array(
    'defaultOrder'=>'PersonA ASC',
));
$friends = $data->getData();
查看更多
虎瘦雄心在
3楼-- · 2019-06-14 05:33

This solution worked for me :

Override the __get function in your model:

public function __get($name)
{
    if(($name == 'friends1') || ($name == 'friends2')) {
        return parent::__get('friends1') + parent::__get('friends2');
    }
    else
        return parent::__get($name);
}
查看更多
登录 后发表回答