【问题标题】:yii relation for multiple column foreign keys多列外键的 yii 关系
【发布时间】:2013-08-29 17:06:20
【问题描述】:

我有一张桌子Friend (PersonA, PersonB)。这些是Person(id, name) 的外键。

我想在它们之间创建一个 Yii 关系。这是我想出的:

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

有没有办法将这两种关系合二为一?我希望有这样的东西:

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

有什么想法吗?

编辑#1:

为了完整起见,我们还假设我想像这样订购friends1friends2

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'),
    );
}

【问题讨论】:

    标签: php mysql database yii


    【解决方案1】:

    这个解决方案对我有用:

    覆盖模型中的__get 函数:

    public function __get($name)
    {
        if(($name == 'friends1') || ($name == 'friends2')) {
            return parent::__get('friends1') + parent::__get('friends2');
        }
        else
            return parent::__get($name);
    }
    

    【讨论】:

    • 这是简单的函数覆盖。
    • 如果使用 ruby​​ on rails 就可以了。
    • 为什么不能使用 PHP 对象继承? class mymodel extends CActiveRecord { public function __get(...) { ... } }
    • 因为在 yii 中 __get 和 __set 方法已经被覆盖了,你不必这样做
    • 但是它仍然会使用父函数是否被覆盖,你不必关心这个......这是特定于模型的。如果要获取特定属性,请返回两个属性。这是一种非常简单的方法。
    【解决方案2】:

    在我正在做的事情中,我遇到了完全相同的事情。我所做的是我创建了另一个函数来将这两个关系编译成一个数组。这样做的原因是因为即使您要将这两个关系结合起来,每次您仍然需要测试 PersonA 或 PersonB 是否是当前用户的 id 并使用另一个 id 来提取好友信息。这是我在模型中创建的函数:

    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;
    }
    

    其他选项:

    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;
    }
    

    那么对于任何人,你可以说:

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

    或者你可以发回一个CActiveDataProvider而不是一个数组,你可以用它来做排序和其他事情。你可以这样做:

    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,
        ));
    }
    

    那么既然你有 CActiveDataProvider 你就可以排序了:

    $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();
    

    【讨论】:

    • 啊,我明白了。 :( 这不会利用 ORDER BY 之类的任何简洁的 SQL 功能 - 我必须自己以编程方式对其进行排序 - 这没关系,但有点烦人,因为 SQL 会巧妙地为我完成所有工作。
    • 如果您想这样做,您可以使用 CDBCriteria 和 CActiveDataProvider 轻松创建它。
    • 嗯....我不明白。正如我在上面看到的,你会得到一个从这个方法返回的数组 --- 前半部分将是在PersonA 中记下此人的位置,然后是在PersonB 中记下的位置。不? CDBCriteriaCActiveDataProvider 会在哪里出现?
    • 这将是一个不同的功能,在您的 OP 中,您只是得到一个无法按名称或任何内容排序的 Friend 实例数组。所以我只是在模仿你的开始。
    • 好的。 :) 我已经用新的关系更新了我的 OP - 我在这里按 ID 订购 friends1friends2。你是说你有一个解决方案来包括这个排序吗?使用CDBCriteraCActiveDataProvider?还是仅限于标准的程序排序?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-30
    • 2020-06-07
    • 2015-06-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多