扫描数据透视表以获得两个相同的值

时间:2014-12-19 17:27:23

标签: laravel laravel-4 eloquent pivot-table

我有这个数据透视表:

+----+---------+-----------------+
| id | user_id | conversation_id |
+----+---------+-----------------+
| 1  | 2       | 48              |
+----+---------+-----------------+
| 2  | 1       | 48              |
+----+---------+-----------------+

我正在尝试找到一种方法来检测两个用户是否在同一个对话中,如果是,则返回对话。有些像:

Conversation::with([1, 2]); // should return conversation 48

我的Conversation课程如下:

class Conversation extend Eloquent {
    public function users() {
        return $this->belongsToMany('User');
    }

    public function messages(){
        return $this->hasMany('Message');
    }
}

到目前为止,我有下面的代码,但它很笨拙而且非常无效,并且认为必须有一些更干净的Laravel方式:

class Conversation {

    public static function user_filter(Array $users) {

        $ids = array();

        foreach ($users as $user)
            $ids[$user->id] = $user->id;

        sort($ids);

        foreach (self::all() as $conversation){ // loop through ALL conversations (!!!)
            $u_ids = $conversation->users->lists('id');
            sort ( $u_ids );

            if ($u_ids === $ids)
                return $conversation;
        }

        return null;
    }
}

用法:

Conversation::user_filter([User::find(1), User::find(2)]); // returns conversation 48

有什么想法吗?

3 个答案:

答案 0 :(得分:3)

让我们首先看一下如何实际检索结果,而不必通过所有类型的数组进行循环...

您可以使用whereHas功能过滤关系。我们可以应用条件,如果它们符合模型的相关记录,它将包含在结果中。

$conversations = Conversation::whereHas('users', function($q){
    $q->where('user_id', 1);
})->get();

对于一个用户来说就是这样。对于两个或更多用户,它基本相同。您只需要链接whereHas s

$conversations = Conversation::whereHas('users', function($q){
    $q->where('user_id', 1);
})
->whereHas('users', function($q){
    $q->where('user_id', 2);
})->get();

现在这不是很优雅。您可以创建query scope来为您完成所有工作并保持控制器代码清洁。在Conversation

public function scopeWithUsers($query, array $userIds){
    foreach($userIds as $id){
        $query->whereHas('users', function($q) use ($id){
            $q->where('user_id', $id);
        });
    }
    return $query;
}

用法:

$conversations = Conversation::withUsers([1,2])->get();
$conversations = Conversation::withUsers([1,2,3,4])->get();
$conversations = Conversation::withUsers([1])->get();

如果它只应该是一个,请使用first()代替get()

答案 1 :(得分:0)

这样的事情应该有效。

class Conversation {
    public static function user_filter(Array $users) {
        $ids = array();
        foreach ($users as $user) {
            $ids[] = $user->id;
        }
        return self::select("conversation_id")->whereIn("user_id", $ids)->groupBy("conversation_id")->havingRaw("count(*) = " . count($ids))->get();
    }
}

答案 2 :(得分:0)

与给定用户进行所有对话。

Conversation::whereHas('users', function($query) use ($userids) {
    $query->whereIn('user_id', $userids);
})->get();

如果你需要特别的,你可以:

 Conversation::whereHas('users', function($query) use ($userids) {
        $query->whereIn('user_id', $userids);
    })->whereId($id)->first();