johnRivs
johnRivs

Reputation: 164

Recursive relationship with scope

A user has a sponsor:

public function sponsor()
{
    return $this->belongsTo(User::class, 'sponsor_id');
}

A user has referrals:

public function referrals()
{
    return $this->hasMany(User::class, 'sponsor_id');
}

A user is considered capped when they have 2 or more referrals:

public function activeReferrals()
{
    return $this->referrals()->whereActive(true);
}

public function isCapped()
{
    return $this->activeReferrals()->count() >= 2;
}

A user can give points. By default, the sponsor will receive them, but if the sponsor is capped, I want the points to go to a sponsor's referral that is NOT capped. If all the referrals are capped, then it does the same thing with the level below (the referral's referrals).

If I go user by user making database calls for each one, it's gonna take a long time. How can I write a scope that makes recursive calls until it finds the first active referral in the tree that's not capped?

This is what I'm trying to do:

Upvotes: 0

Views: 374

Answers (1)

prateekkathal
prateekkathal

Reputation: 3572

Please give this a try... I believe this will work for you :)

public function scopeNotCappedActiveReferrals($query, $count) {
  return $query->withCount(['referrals' => function($q) {
    $q->where('active', true);
  }])->where('referrals_count', '<', $count);
}

For the second part...

// Finally you can call it with
public function allReferrals() {
  $users = User::notCappedActiveReferrals(2)->get();

  $allUsers = $this->findNotCappedActiveReferralsRecurrsively($users);
}

// Do not place this function in the model,
// place it in your Controller or Service or Repo or blahblah...
// Also, not tested... but should work :)
protected function findNotCappedActiveReferralsRecurrsively($users) {
  if(!count($user)) {
    return $users;
  }

  foreach($users as $user) {
    $moreUsers = $user->notCappedActiveReferrals(2)->get();

    return $users->merge($this->findNotCappedActiveReferralsRecurrsively($moreUsers));
  }
}

Hope this is what you need :)

Upvotes: 1

Related Questions