user5203771
user5203771

Reputation:

Laravel get users by id in user model and store them in an array

I'm trying to make a simple "friends" system, by storing each friend id in a single column as a string separated with a comma.

I want to get the users by id and store them in an array:

public function getFriends() {
    $friendids = explode(',', $this->friends);
    $friends = [];

    foreach ($friendids as $id) {
        $friends[] = User::findOrFail($id);
    }

    return $friends;
}

So I can do this in my view:

@foreach ($user->getFriends() as $friend)
    <p>Friend ID: {{ $friend->id }}</p>
    <p>Friend Username: {{ $friend->username }}</p>
@endforeach

But I think I can't use findOrFail in the user model or what am I doing wrong?

Upvotes: 8

Views: 44742

Answers (3)

Pastor Dur&#225;n A.
Pastor Dur&#225;n A.

Reputation: 374

To use the findOrFail($id) method, you should invoke the object type you want to get. Example:

foreach ($friendids as $id) {
        $friends[] = User::findOrFail($id);
    }

Upvotes: 15

user5203771
user5203771

Reputation:

I made 2 simple mistakes:

1) I removed User object from findOrFail()when looking for the mistake I made

2) I had specified user id's (friends) that did not exist in the databse, causing an error

I also improved the code a bit, by adding an optional parameter to get only x amount of users:

// App/User.php
public function getFriends($friends_to_get = null) {
    $friendids = explode(',', $this->friends);
    $friends = [];

    $i = 0;
    foreach ($friendids as $id) {
        if (is_numeric($id)) {
            $friends[] = User::findOrFail($id);
        }

        if (isset($friends_to_get) && $i < $friends_to_get) {
            ++$i;
        }

        if (isset($friends_to_get) && $i == $friends_to_get) {
            break;
        }
    }

    return $friends;
}

Now you can do something like this in your view:

@foreach ($user->getFriends() as $friend)
    <p>Friend ID: {{ $friend->id }}</p>
    <p>Friend Username: {{ $friend->username }}
@endforeach

Or if you want to get, for example, 6 friends only, you can do: $user->getFriends(6)

In my case, $user is the user of who's profile I'm currently viewing. If you want, you could also get your friends only, by doing Auth::user()->getFriends()

/Edit: Added is_numeric check in the foreach loop. This way you don't have to worry about first and last element in the column having an extra comma. Since explode adds an extra value to the array, if there's a comma in the end of the friends column. Now you can just add or remove x, from/to the column every time and not worry about fetching an object, that does not exist.

Upvotes: 1

Amo
Amo

Reputation: 2944

Although there's an existing answer, I wanted to provide an alternative solution that I personally feel is a better long-term solution.

Firstly, saving friends as an comma separated list isn't going to scale very well. It also massively limits the ability for you to do things such as 'friends of friends', and other more complex queries.

Really, you should have two tables, users and friends.

User model

public function acceptedFriends()
{
    return $this->hasMany('App\Friend')->where('accepted', true);
}

public function pendingFriends()
{
    return $this->hasMany('App\Friend')->where('accepted', false);
}

Now, when a friend request is rejected, you can simply delete the record in the Friends table.

Loading a user with their friends:

$user = User::find($id)->with('acceptedFriends')->firstOrFail();

Loading a user's friend requests:

$users = Friends::where('accepted', false)->where('target_user', $userId)->get();

You might want to also check out https://stackoverflow.com/a/25057320/972370. It's written by someone who is very well known in the Laravel community for advanced Eloquent usage.

Upvotes: 4

Related Questions