Edited
There a many ways to do this:
- Check the intersection between 2 Eloquent query results. The intersection between:
App\User::find(1)->conversations->pluck('conversations.id') and App\User::find(2)->conversations->pluck('conversations.id). Here, array_intersect might help.
- Give some sort of name to a conversation to identify it easily such as: 1_2 (starting with the smallest user id number). Information is duplicated but the query for an existing conversation between 2 users is made simple and straightforward.
- Use the SQL way with query builders, here are 2 suggestions:
Option 1:
DB::table(function($q) {
$q->select('conversation_user.conversation_id')->from('conversation_user')->where('conversation_user.user_id',1);
},'authconversations')->join('conversation_user','authconversations.conversation_id','=','conversation_user.conversation_id')->where('conversation_user.user_id',2)->exists();
Here, I am using a sub query to retrieve all conversations for user 1. I assumed user 1 is the authenticated user, hence the naming authconversations, it could be changed. Then, I joined the result with the pivot table and restricted it to user 2 conversations.
Or to put it simply, we store user 1 conversations and perform a query on the result to check if one is matching with user 2.
I used exists at the end to shorten the query but it could be done with whereExists.
Option 2a:
DB::table('conversation_user as a')
->join('conversation_user as b', 'a.id', '!=','b.id')
->where([['a.user_id','=',1],['b.user_id','=',2]])
->whereColumn('a.conversation_id','b.conversation_id')
->exists();
Here, it is a self join. Think of a list of pivot entries 1,2,3,4 but associated with one another: 1-2, 1-3, 2-1. != prevents from having 1-1. If we find an entry with user id 1, user id 2, and the same conversation id, then there is a conversation between the users 1 and 2. Why do we bother checking that it is the same conversation id ? Well, the self join also joins unrelated conversations.
Option 2b:
DB::table('conversation_user as a')
->join('conversation_user as b', 'a.id', '<','b.id')
->where(function($q){
$q->where([['a.user_id','=',1],['b.user_id','=',2]])
->orWhere([['a.user_id','=',2],['b.user_id','=',1]]);
})
->whereColumn('a.conversation_id','b.conversation_id')
->exists();
Here, the join is more restrictive, < is used instead of !=. We get combinations instead of permutations. The benefit is that the join gets less results. If I have 1 - 2, I don't need 2 - 1. As a result, we use orWhere to check for either orders. Is it more performant than 2a ? Maybe. Even if we do add an 'orWhere', it is applied on a smaller data set. Performance tests would help to compare both options.