hasAndBelongsToMany不为associationForeignKey提取数据

时间:2012-09-26 22:13:54

标签: php cakephp

在我的CakePHP应用程序中,我的用户可以与其他用户成为朋友。

这是通过users表和friends_users表完成的,该表包含以下列:id, user_id, friend_id, status表示关系。

因此,如果用户ID 1是用户ID为2的朋友,则user_id中的1和friend_id列中的2

用户的模型如下:

public $hasAndBelongsToMany = array(
        'Friend'=>array(
            'className'              => 'User',
            'joinTable'              => 'friends_users',
            'foreignKey'             => 'user_id',
            'associationForeignKey'  => 'friend_id'
        )
    );

查看用户1时,它工作正常,并将用户2显示为朋友。但是,当查看用户2时,它不会将用户1显示为朋友...因此,当反向查看时,它不会填满数据!

以下是我用来列出用户朋友的方法:

$user = $this->User->find('first', array( 
                    'conditions' => array('User.id' => $this->Auth->user('id')),
                    'contain'=>'Profile'
                ));

        $friends = $this->User->find('first', 
            array(
                'conditions'=>array(
                   'User.id'=>$user['User']['id']
                ),
                'contain'=>array(
                    'Profile',
                    'Friend'=>array(
                        'Profile',
                        'conditions'=>array(
                            'FriendsUser.status'=>1
                        )
                    )
                )
            )
        );

        $this->set('friends', $friends);

为什么会发生这种情况?我查看了文档,但对我来说似乎都很好。

理想情况下,我想修复我的代码,而不是指向其他资源!

页面上的查询:http://pastebin.com/zQnBVM2X

2 个答案:

答案 0 :(得分:2)

当您为用户#6检索朋友时,您将获得#8朋友。当您为用户#8检索朋友时,您不应该收到任何内容,因为friends_users表中没有用户#8的记录。因此,您需要在friends_users表(user_id = 8, friend_id = 6)中插入其他数据,或者您需要创建Friend模型(不使用表格)并通过Friend检索用户。这就是心理体操 - 你需要意识到用户是朋友而朋友是用户。

        $friends = $this->User->Friend->find('first', 
            array(
                'conditions'=>array(
                   'Friend.id'=>$id // user id whose friends you need to find
                ),
                'contain'=>array(
                    'Profile',
                    'User'=>array( // here you will get friends
                        'Profile',
                        'conditions'=>array(
                            'FriendsUser.status'=>1
                        )
                    )
                )
            )
        );

答案 1 :(得分:0)

这是一个有趣的问题,几年前我在建立约会网站时遇到了同样的问题。

你需要做的是(在我的情况下)4组关系:

  • 前进关系
  • 前进关系(未经批准的友谊)
  • 落后关系
  • 落后关系(未经批准的友谊)

这将确保您提取所有必要的数据,尽可能使用containable

var $hasAndBelongsToMany = array(
    'ForwardRelation' => array(
        'className'  => 'User',
        'joinTable'  => 'friends_users',
        'foreignKey' => 'user_id',
        'conditions' => array('approved' => '1'),
        'associationForeignKey' => 'friend_id',
        ),
    'ForwardRelationUn' => array(
       'className'  => 'User',
        'joinTable'  => 'friends_users',
        'foreignKey' => 'user_id',
        'conditions' => array('approved' => '0'),
        'associationForeignKey' => 'friend_id'
        ),
    'BackRelation' => array(
        'className'  => 'User',
        'joinTable'  => 'friends_users',
        'foreignKey' => 'friend_id',
        'associationForeignKey' => 'user_id',
        'conditions' => array('approved' => 1)
        ),
    'BackRelationUn' => array(
        'className'  => 'User',
        'joinTable'  => 'friends_users',
        'foreignKey' => 'friend_id',
        'associationForeignKey' => 'user_id',
        'conditions' => array('approved' => '0')
    )
);

添加一些带有afterFind()魔法的行为,你就会变成金色!

这是我找朋友的功能:

function getFriends( $userid, $search = null ) {

    $Friends    = ClassRegistry::init( 'FriendsUser' );

    $Friends->bindModel( 
        array(
            'belongsTo' => array(
                'User' => array(
                    'className' => 'User',
                    'foreignKey' => 'user_id'
                ),
                'Friend' => array(
                    'className' => 'User',
                    'foreignKey' => 'friend_id'
                    )
                )
            )
        );

    $data = $Friends->find( 
        'all', 
        array( 
            'fields' => array( 
                'DISTINCT FriendsUser.friend_id', 
                'FriendsUser.user_id',
                'FriendsUser.approved',
                'User.id', 
                'User.username', 
                'Friend.id', 
                'Friend.username'
                ), 
            'conditions' => array(
                 'AND' => array(
                     'OR' => array( 
                        'Friend.username LIKE' => '%' . $search . '%',
                        'User.username LIKE' => '%' . $search . '%'
                        )
                    )
                ),
            'contain' => array(
                'User', 
                'Friend'
                ),
            'order' => array( 'User.username ASC', 'FriendsUser.approved DESC' )
        ) 
    );


    $friendlist = array();
    $i = 0;

    foreach ( $data as $datum ) {

        foreach ( $datum as $key => $value ) {

            if ( in_array( $key, array( 'User', 'Friend' ) ) ) {

                if ( $value['id'] == $userid ) {
                    $friendlist[$i]['Me'] = $value;
                } else {
                    $friendlist[$i]['Friend']           = $value;
                }

            }
        }

        $i++;

    }

    $matches = array();

    foreach ( $friendlist as $friend ) {

        if ( stripos( $friend['Friend']['username'], $search ) !== false )
            $matches[ $friend['Friend']['id'] ] = $friend['Friend']['username'];

    }

    asort( $matches );

    $i = 0;

    $newmatches = array();

    foreach ( $matches as $key => $match ) {
        $newmatches[$i]['Tag']['caption']   = $match;
        $newmatches[$i]['Tag']['value']     = $key; 
        $newmatches[$i]['Tag']['image']     = $this->getProfileImage( $key );

        $i++;       
    }

    return $newmatches;

}