0
votes

Problem

I created a simple friendship relationship for my Laravel app which all worked ok until I noticed that when I queried the friendship of a user it would only search the current user on the UID1 field.

Since friendships are in essence a two-way relationship, Im trying to find a way in a laravel Model to retrieve ALL friendships relations by multiple columns.

Current Implementation

    public function friends()
    {
        return $this->belongsToMany( App\Modules\Users\Models\User::class ,'friends', 'uid1');
    }

Ideal Implementation

    public function friends()
    {
        $a = $this->belongsToMany( App\Modules\Users\Models\User::class ,'users_friends', 'uid1');
        $b = $this->belongsToMany( App\Modules\Users\Models\User::class ,'users_friends', 'uid2');

        return combine($a,$b);

    }

Table Structure

     +----------------------+
     | users table          |
     +----------------------+
+----|   id: primary UserID |
|    |   fname: string      |
|    +----------------------+
|    
|    
|    +----------------------+
|    | friends table        |
|    +----------------------+
|    |   id: primary iD     |
|    |                      |
+----|   uid1: user_id      |
|    |                      |
+----|   uid2: user_id      |
     +----------------------+

The current implementation will only result in 1 of these records returning if the Current UserID = 1 as per the data in the friends table below.

     +-------------------------------+
     |      friends table (data)     |
     +--------|---------|------------+
     |   id   |  uid1   |   uid2     |
     +--------|---------|------------+
     |    1   |   1     |    7       |
     |    2   |   7     |    1       |
     |    3   |   9     |    1       |
     +-------------------------------+      

User Model

<?php

namespace App\Modules\Users\Models;

use Illuminate\Database\Eloquent\Model;


class User extends Model
{


    protected $table = 'users';


    protected $fillable = [
        'username', 'email', 'password', .... . 
    ];


    public function friends()
    {
        return $this->belongsToMany( App\Modules\Users\Models\User::class ,'users_friends', 'uid1');

    }

Environment

  • Server = Homestead/linux
  • PHP = 7
  • MySQL

Update

I have a FriendShip helper class I created which does something similar, however in this function I pass in the UserID explicitly

Friendship::where( [
                    [ 'uid1' ,'=', $uid],
                ])->orWhere( [
                    [ 'uid2', '=', $uid]
                ])->all();
1

1 Answers

0
votes

You can add additional conditions when you're declaring relationship by simply chaining it.

<?php
//...
class User extends Model {
//...
    public function friends() {
        return $this->hasMany(/*...*/)->orWhere('uid2', $this->id);
    }
//...

But keep in mind that eloquent is not grouping the first conditions of relation in parenthesis so you might end with SQL that will not work as expected in some cases (if using or, and should be fine)

For example the above might result in a SQL that looks like this

SELECT * FROM users_friends WHERE uid1 = ? AND uid1 IS NOT NULL OR uid2 = ?

Which is a correct SQL statement but without grouping you will not get the result that you're expecting.

Another way is to use accessor and two separate relationships

<?php
//...
public function friends1() {
    return $this->belongsToMany(User::class, 'users_friends', 'uid1');
}

public function friends2() {
    return $this->belongsToMany(User::class, 'users_friends', 'uid2');
}

public function getFriendsAttribute() {
    return $this->friends1->merge($this->friends2);
}
//...

But this way you get two separate trips to DB.