私は最終的に自分で問題を解決しました。
//traverse the network binary tree to fetch the next available upline to place the user under
function get_next_free_upline($pref, $sponsor_id)
{
$ref_id = $sponsor_id;
$get_next = TRUE;
$level = 1;
$lft = $this->get_pointers($ref_id, 'lft');
$rgt = $this->get_pointers($ref_id, 'rgt');
$offset = $this->get_offset($lft, $rgt);
while ($get_next !== FALSE)
{
$query = $this->db->query
(' SELECT node.*, (COUNT(parent.upline_id) - ' . $offset . ') AS level
FROM tree AS node
CROSS JOIN tree AS parent
WHERE (node.lft BETWEEN parent.lft AND parent.rgt AND
node.lft > ' . $lft .' AND node.rgt < ' . $rgt . ')
GROUP BY node.id
having level = ' . $level . '
ORDER BY node.lft
');
$result = $query->result();
//check if this upline has less than 2 downlines
//if yes, assign the user_id to upline and return
if ($query->num_rows() < 2)
{
$upline_id = $sponsor_id;
$get_next = FALSE;
}
else
{ //loop through all members under the current sponsor id
//to know where to spill over the referred member
foreach ($result as $row):
$sponsor_id = $row->id;
//check all occurences of this level member as an upline
$this->db->select('*');
$this->db->from('tree');
$this->db->where('upline_id', $sponsor_id);
$inner_query = $this->db->get();
if ($inner_query->num_rows() < 2)
{
$upline_id = $sponsor_id;
$get_next = FALSE;
break;
}
endforeach;
//increase the level number and loop back
$level = $level + 1;
$get_next = TRUE;
}
}
return $upline_id;
}