'Round robin assign user

I am having a hard time finding a solution. If anyone could help me would be a great help. Let's say I have a user table like:

id name
1 john
2 brian
3 eddy
4 mia

and pivot table for group_user:

groupid userid
1 1
1 2
1 3
2 2
2 3
2 4

And when a new meeting is created(after fill up a form), I want to assign them a user in every meeting like this in meeting table:

meetingid groupid userid
1 1 1
2 1 2
3 1 3
4 1 1
5 1 2
6 2 2
7 2 3
8 2 4
9 2 2
10 2 3

This is my model: User.php

class User extends Authenticatable
{
    use SoftDeletes;
    use HasApiTokens;
    use HasFactory;
    use HasProfilePhoto;
    use Notifiable;
    use TwoFactorAuthenticatable;

    /**
     * The attributes that are mass assignable.
     *
     * @var string[]
     */
    protected $fillable = [
        'name',
        'email',
        'password',
        'role'
    ];
    protected $dates = ['deleted_at'];
    public function grp()
    {
    return $this->belongsToMany(Group::class);
    }

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array
     */
    protected $hidden = [
        'password',
        'remember_token',
        'two_factor_recovery_codes',
        'two_factor_secret',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

    /**
     * The accessors to append to the model's array form.
     *
     * @var array
     */
    protected $appends = [
        'profile_photo_url',
    ];
}

Group.php

class Group extends Model
{
    use SoftDeletes;
    use HasFactory;
    public $timestamps=true;
    protected $dates = ['deleted_at'];
    public function creators()
    {
    return $this->belongsToMany(User::class);
    }
}

Meeting.php

class Meeting extends Model
{
    use HasFactory;
    public function gr()
    {
    return $this->belongsTo('App\Models\Group','groupID');
    }
}

So, for every meeting created for the group, one user in that group will be auto assigned to that meeting in round robin algorithm. If my details is not enough please tell me, I will try my best to provide it. Thanks in advance.

EDIT: what if i want to declare in this public function? it is possible?

public function addsession(Request $req)
    {
       $mod = null;
    $latestUserId=Meeting::where('groupID', $req->groupID)
    ->latest('id')
    ->first()
    ?->meetingModerator;

    //the first meeting or all the users have already had their turn
    $firstUserId=DB::table('group_user')
    ->where('group_id', $req->groupID)
    ->orderBy('user_id')
    ->first()
    ?->user_id;

    //second time meeting is being held
    if ($latestUserId) {
    $nextUserId=DB::table('group_user')
        ->where('group_id', $req->groupID)
        ->where('user_id', ">", $latestUserId)
        ->orderBy('user_id')
        ->first()
        ?->user_id;
    $mod = $nextUserId;
    } else {
    $mod = $firstUserId;
    }
        
        $data = new Meeting;
        $data->groupID = $req->groupID;
        $data->meetingDate = $req->meetingDate;
        $data->meetingTime = $req->meetingTime;
        $data->meetingDesc = $req->meetingDesc;
        $data->meetingLink = $req->meetingLink;
        $data->meetingModerator = $mod;
        $file = $req->meetingNotes;
        $filename = time().'.'.$file->getClientOriginalExtension();
        $req->meetingNotes->move('assets/file',$filename);
        $data->meetingNotes=$filename;
        $data->save();
return redirect('redirect');
}


Solution 1:[1]

I would probably do this by fetching the user ID for the latest meeting for that specific group:

private function getLatestUserId(int $groupid): ?int
{
    return Meeting::where('groupid', $groupid)
        ->latest('meetingid')
        ->first()
        ?->user_id;
}

Then using that user ID I would figure out who is the next user in that group:

private function getNextUserId(int $groupid, int $latestUserId): ?int
{
    return DB::table('group_user')
        ->where('groupid', $groupid)
        ->where('user_id', ">", $latestUserId)
        ->orderBy('user_id')
        ->first()
        ?->user_id;
}

If this is the first meeting or all the users have already had their turn, I would start with the first user in that group:

private function getFirstUserId($groupid): ?int
{
    return DB::table('group_user')
        ->where('groupid', $groupid)
        ->orderBy('user_id')
        ->first()
        ?->user_id;
}

As for where this would happen, I would have a service class injected in to the controller. This service class would be responsible for handling the logic for creating and updating Meetings.

Edit:

How all this would look together:

public function getMeetingUserId(int $groupid): ?int
{
    $latestUserId = $this->getLatestUserId($groupid);
    if ($latestUserId === null) {
        // First time the meeting is being held
        return $this->getFirstUserId($groupid);
    }

    $nextUserId = $this->getNextUserId($groupid, $latestUserId);
    if ($nextUserId === null) {
        // All users have had their turn, starting over
        return $this->getFirstUserId($groupid);
    }

    return $nextUserId;
}

Edit 2:

I recommend doing it like in the example above on the first edit, but ...

$mod = null;

$latestUserId=Meeting::where('groupID', $req->groupID)
    ->latest('meetingid')
    ->first()
    ?->user_id;

$firstUserId=DB::table('group_user')
    ->where('group_id', $req->groupID)
    ->orderBy('user_id')
    ->first()
    ?->user_id;

if ($latestUserId) {
    $nextUserId=DB::table('group_user')
        ->where('group_id', $req->groupID)
        ->where('user_id', ">", $latestUserId)
        ->orderBy('user_id')
        ->first()
        ?->user_id;
    $mod = $nextUserId;
} else {
    $mod = $firstUserId;
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1