Daniel White
Daniel White

Reputation: 3377

Recursive function not returning all children

I have a database set up with an infinite amount of questions and child questions. So you can ask something like, "what payment solution do you accept". Then child answers might be, "CC Processing" and "check". Then "CC Processing" might have children, "Do you accept visa and mastercard". etc.

enter image description here

===

I have a php function and recursive function set up in Laravel 5.1 to grab the information i need and create a "tree" array:

public function create($id)
{
    //BUILD THE TREE
    $tree = array();
    //GET TOP LEVEL ITEMS
    $top_level = Questions::where('parentId', 0)->where('industryId', $id)->get()->toArray();

    foreach($top_level as $top){

        $branch = array();
        $branch['id'] = $top['id'];
        $branch['industryId'] = $top['industryId'];
        $branch['question'] = $top['question'];
        $branch['parentId'] = $top['parentId'];
        $branch['endPoint'] = $top['endPoint'];
        $branch['order'] = $top['order'];

        $children = Questions::where('parentId', $top['id'])->get()->toArray();

        //CHECK FOR CHILDREN
        if(count($children > 0)) {

            //THERE ARE CHILDREN PASS THEM TO A RECURSIVE FUNCTION TO GET LIST
            $branch['children'] = $this->getChildren($children);

        }else {
            //THERE ARE NO CHILDREN SET TO EMPTY ARRAY
            $branch['children'] = array();
        }

        $tree[] = $branch;

    }

    //Send the question tree to the view...
    $data['questions'] = $tree;

    //Grab the industry
    $data['industry'] = Industries::where('id', $id)->get();

    return $data['questions'];
    //return view('questions.create', $data);
}

public function getChildren($children) {

    foreach($children as $child){
        $child_branch = array();
        $child_branch['id'] = $child['id'];
        $child_branch['industryId'] = $child['industryId'];
        $child_branch['question'] = $child['question'];
        $child_branch['parentId'] = $child['parentId'];
        $child_branch['endPoint'] = $child['endPoint'];
        $child_branch['order'] = $child['order'];

        $children = Questions::where('parentId', $child['id'])->get()->toArray();
        //CHECK FOR CHILDREN
        if(count($children > 0)) {
            //THERE ARE CHILDREN PASS THEM TO THIS FUNCTION (RECURSION) TO GET LIST
            $child_branch['children'] = $this->getChildren($children);
        }else {
            //THERE ARE NO CHILDREN SET TO EMPTY ARRAY
            $child_branch['children'] = array();
        }

        return $child_branch;
    }
}

my "tree" array is returning the following:

    [
{
"id": 18,
"question": "How Do you Accept Payments?",
"parentId": 0,
"endPoint": 0,
"order": 0,
"children": {
"id": 19,
"industryId": 1,
"question": "Card Station",
"parentId": 18,
"endPoint": 0,
"order": 0,
"children": {
"id": 25,
"industryId": 1,
"question": "What type of card station?",
"parentId": 19,
"endPoint": 0,
"order": 0,
"children": null
}
}
},
{
"id": 21,
"question": "What?",
"parentId": 0,
"endPoint": 0,
"order": 0,
"children": {
"id": 22,
"industryId": 1,
"question": "Testing This",
"parentId": 21,
"endPoint": 0,
"order": 0,
"children": null
}
}
]

It is missing some of the children. I feel like I'm ALMOST there but I just can't put together the final pieces.

Based on my database screenshot above, i should get a parent of "How do you accept payments, with the id 18". Then my children array should ACTUALLY be: "card station", "manually" and "test". Then "card station" should have the children, "what type of card station".

Any ideas on the missing link here are appreciated.

Upvotes: 1

Views: 798

Answers (1)

Steven Moseley
Steven Moseley

Reputation: 16325

Here you go - in your getChildren method, you were returning the first "child_branch" in the loop, which essentially skipped out.

You can see in my first edit, I'm instead constructing a $branch array and returning that. In later edits, I'm actually taking the input array, altering it in the loop, and returning it at the end. I was able to restrict the input array to your desired format using a select method call in your query.

I took the liberty of DRY-ing up your code a little by making the "trunk" just another branch (reusing getChildren):

public function getQuestions($parentId, $industryId=null)
{
    $query = Questions::where('parentId', $parentId);
    if ($industry) {
        $query->where('industryId', $id);
    }
    return $query->select('id', 'industryId', 'question', 'parentId', 'endPoint', 'order')->get()->toArray();
}

public function create($id)
{
    //BUILD THE TREE
    $tree = array();
    //GET TOP LEVEL ITEMS
    $trunk = $this->getQuestions(0, $id);
    $tree = $this->getBranch($trunk);

    //Send the question tree to the view...
    $data['questions'] = $tree;

    //Grab the industry
    $data['industry'] = Industries::where('id', $id)->get();

    return $data['questions'];
    //return view('questions.create', $data);
}

public function getBranch($twigs) {
    foreach ($twigs as $twig) {
        // Check for children
        $children = $this->getQuestions($twig['id']);
        $twig['children'] = count($children) ? $this->getBranch($children) : array();
    }
    return $twigs;
}

Upvotes: 2

Related Questions