Ivan
Ivan

Reputation: 5248

Recursive looping returns 500 Internal Server Error

I'm getting a 500 Internal server error when recursive is called in loop. Only then I get a 500 error.

When I remove recursive in loop everything work good:

Code:

public function getRecrusiveReferals($userID) {
    $sql = "SELECT user_id, username, refered_by FROM users WHERE refered_by = ?";
    $referals = $this->db->query($sql, $userID);
    $list = $this->buildReferalsTree($referals->result_array());
    return $list;
}

private function buildReferalsTree(array $referals, $parentID = 0) {
    $data = array();

    foreach ($referals as $item) {
        if($item['refered_by']) {
            $children = $this->buildReferalsTree($referals, $parentID);

            if($children) {
                $item['children'] = array();
            }
        }
        $data[] = $item;
    }
    return $data;
}

Upvotes: 1

Views: 998

Answers (3)

trincot
trincot

Reputation: 350252

You'll want to pass a new value for the parent argument, not the same over and over again. Like this:

$children = $this->buildReferalsTree($referals, $item['user_id']);

Then in the loop you need to also filter by the parent ID:

if($item['refered_by'] = $parentID)

... so you will only link items that are "children" of that ID.

Furthermore, your original call should also specify the parentID, since you select only a specific referred_by subset of your table:

$list = $this->buildReferalsTree($referals->result_array(), $userID);

However, this will give an uninteresting result, since you only selected records with the same referred_by value, so there is not much to build a tree from. Instead, you could select all records from that table, and then still pass $userID to buildReferalsTree which will then have all the other records available for following the chains of referrals. So here is the code to select all records:

$sql = "SELECT user_id, username, refered_by FROM users";
$referals = $this->db->query($sql);

Finally, there is also an error in the inner if block where you currently assign an empty array to $item['children']. You should instead assign the result from the recursive call, like this:

if($children) {
    $item['children'] = $children;
}

Taking this all together, the code would look like this:

public function getRecrusiveReferals($userID) {
    $sql = "SELECT user_id, username, refered_by FROM users";
    $referals = $this->db->query($sql);
    $list = $this->buildReferalsTree($referals->result_array(), $userID);
    return $list;
}

private function buildReferalsTree(array $referals, $parentID = 0) {
    $data = array();
    foreach ($referals as $item) {
        if ($item['refered_by'] == $parentID) {
            $children = $this->buildReferalsTree($referals, $item['user_id']);
            if($children) {
                $item['children'] = $children;
            }
        }
        $data[] = $item;
    }
    return $data;
}

This could still give an infinite recursion if your data has cycles in terms of referrals. Given the meaning of a referral, this should however not be the case.

Upvotes: 0

Mikz
Mikz

Reputation: 700

As Jay Rajput said, you've got infinite recursion there. I think that the call

$children = $this->buildReferalsTree($referals, $parentID);

should pass not the $referals, but another array, built based on 'refered_by' element of $item. So basically you need to create another private method, that extracts new $referals. You must be still aware that this code won't be errorprone, and if two items refer each other you will still end with an infinite recursion.

What you're trying to accomplish is quite a challenge, especially when you're using relational database. You definitely would like to look at the 'nested set' concept in relational databases.

Upvotes: 0

Jay Rajput
Jay Rajput

Reputation: 1888

Your code has a infinite recursive loop causing your script to be killed by PHP when the recursion reaches the limit set by PHP for the recursion depth.

This code is called again and again with the same set of arguments:

 $children = $this->buildReferalsTree($referals, $parentID);

For recursive function to terminate, there should be a condition which should define when the recursion ends, I do not see that in your code.

Upvotes: 1

Related Questions