AE_Ruggiero's avatar

Friends Model

Hi everyone, after a lot of search I still don't know how to manage friendship relationships in Laravel. What I mean is this: I have a users table, and a friends table. The friends table has, in addition to id and timestamps, user_1_id, user_2_id and the status column (an enum that can be ACCEPTED, DECLINED, PENDING).

It seems like Laravel can't face these kind of relations, for example, having something like $user->friends() (where $user is the instance of a User Model). What I did for now is, by following a tutorial online

public function friendsTo() {
    return $this->belongsToMany(User::class, 'friends', 'user_id_1', 'user_id_2')
        ->withPivot('status')
        ->withTimestamps();
}

public function friendsFrom() {
    return $this->belongsToMany(User::class, 'friends', 'user_id_2', 'user_id_1')
        ->withPivot('status')
        ->withTimestamps();
}
public function friends() {
    return $this->friendsFrom->merge($this->friendsTo);
}

But this is not working as intendent. Actually it makes hard to filter, query and limit the results.

Do you have any suggestions? What I don't want to do is create another view or table to fix this.

Thanks.

0 likes
5 replies
vincent15000's avatar

But this is not working as intended.

Can you explain what is the behavior of your code and what is the behavior you are waiting for ?

AE_Ruggiero's avatar

@jlrdw yes, I did! But it doesn't provide with what I was looking for. I expect to get a "query", that I can further work with.

Here's the code that is giving me trouble:

public function allFriends(Request $request) {
        $user = $request->attributes->get('user');
        $limit = $request->input('limit', 10);
        $offset = $request->input('offset', 0);
        $search = $request->input('search', '');      
        $query = $user->friends();        
        if (!empty($search)) {
            $query->where('name', 'LIKE', '%' . $search . '%');
        }
        return response()->json($query->skip($offset)->take($limit), 200);
    }

The issue here, for example, is that if $search is empty or not it doesn't change anything to the result, and that's probably because the 2 subqueries that are merged are executed before the where is called.

I m relatively new to Laravel and Eloquent, so I am sorry if I didn't use the correct terminology.

BTW, thank you very much for your quick reply!

1 like
jlrdw's avatar

@AE_Ruggiero what does the network tab show?

Also put a dd at various spots and see what is in the network tab.

Like:

$user = $request->attributes->get('user');
dd($user);

If good check next segment, but comment out first dd. Why attributes?

1 like
AE_Ruggiero's avatar

@jlrdw I'm using this section of codes for API calls for a mobile app, where laravel serves as a backend. I don't know how "good practice" is this, but it's a way for making sure that the app is authorized to do api calls

the code is this:

class ApiAuthentication {
    /**
     * Handle an incoming request.
     *
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     */
    public function handle(Request $request, Closure $next) {
        $token = $request->header('Authorization');
        $userID = $request->header('UserID');
        if (!$this->isValidUser($token, $userID)) {
            return response()->json(['error' => 'Non autorizzato'], 401);
        }
        $user = $this->getUserFromToken($token);
        $request->attributes->add(['user' => $user]);
        return $next($request);
    }

    private function isValidUser($token, $userID) {
        $personalAccessToken = PersonalAccessToken::findToken($token);
        if (!$personalAccessToken || $personalAccessToken->tokenable_id != $userID) {
            return false; 
        }
        return true;
    }
    private function getUserFromToken($token) {
        $userID = (PersonalAccessToken::findToken($token))->tokenable_id;
        $user = User::find($userID); 
        return $user;
    }
}

so basically the Middleware adds to the request attributes an user Model.

BTW, if I do a print_r($user) (to get that from the API) I recieve

App\Models\User Object
(
[connection:protected] => mysql
[table:protected] => users
[primaryKey:protected] => id
[keyType:protected] => int
[incrementing] => 1
[with:protected] => Array
(
)

[withCount:protected] => Array
(
)

[preventsLazyLoading] =>
[perPage:protected] => 15
[exists] => 1
[wasRecentlyCreated] =>
[escapeWhenCastingToString:protected] =>
[attributes:protected] => Array
(
[id] => 1
[name] => myname
[email] => [email protected]
[email_verified_at] => 2023-09-10 22:28:28
[password] => yIXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi
[two_factor_secret] =>
[two_factor_recovery_codes] =>
[two_factor_confirmed_at] =>
[remember_token] => Q4VMTHkqex
[current_team_id] =>
[profile_photo_path] =>
[firebase_uid] =>
[created_at] => 2023-09-10 22:28:28
[updated_at] => 2023-09-10 22:28:28
)

[original:protected] => Array
(
[id] => 1
[name] => myname
[email] => [email protected]
[email_verified_at] => 2023-09-10 22:28:28
[password] => yIXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi
[two_factor_secret] =>
[two_factor_recovery_codes] =>
[two_factor_confirmed_at] =>
[remember_token] => Q4VMTHkqex
[current_team_id] =>
[profile_photo_path] =>
[firebase_uid] =>
[created_at] => 2023-09-10 22:28:28
[updated_at] => 2023-09-10 22:28:28
)

[changes:protected] => Array
(
)

[casts:protected] => Array
(
[email_verified_at] => datetime
)

[classCastCache:protected] => Array
(
)

[attributeCastCache:protected] => Array
(
)

[dateFormat:protected] =>
[appends:protected] => Array
(
[0] => profile_photo_url
)

[dispatchesEvents:protected] => Array
(
)

[observables:protected] => Array
(
)

[relations:protected] => Array
(
)

[touches:protected] => Array
(
)

[timestamps] => 1
[usesUniqueIds] =>
[hidden:protected] => Array
(
[0] => password
[1] => remember_token
[2] => two_factor_recovery_codes
[3] => two_factor_secret
)

[visible:protected] => Array
(
)

[fillable:protected] => Array
(
[0] => name
[1] => email
[2] => password
[3] => firebase_uid
)

[guarded:protected] => Array
(
[0] => *
)

[rememberTokenName:protected] => remember_token
[accessToken:protected] =>
)
1
1 like

Please or to participate in this conversation.