1

I have written a loop which first checks for whether, in this case, a Category has any Subcategories based on a field in the database called 'category_id' in the subcategory table.

What I would like it to do here on is recursively check Subcategories to see if there are any Subcategories with the 'parent_id' set to the respective id. What the check needs to do is add to an array (see code snippet below for a better explanation).

Firstly to illustrate an example structure:

Main Category
- Sub category level 1 (identified by 'category_id' matching 'id' of Main Category)
- - Sub category level 2 (identified by 'parent_id' matching 'id' of Sub category level 1
- - - Sub category level 3 (identified by 'parent_id' matching 'id' of Sub category level 2

This is intended to continue indefinitely. Here is an example of a non-recursive function which performs the task correctly:

$final = [];

    foreach($values as $k => $v) {
        $check = collect(Subcategory::where('category_id', $v['id'])->get());
        $v['subcategory'] = 0;
        $final[] = $v;
        if (count($check) > 0) {
            foreach($check as $c) {
                $val = $c->toArray();
                $val['name'] = '- '.$val['name'];
                $val['subcategory'] = 1;
                $final[] = $val;
                /* recursive here onward */
                $check2 = collect(Subcategory::where('parent_id', $c['id'])->get());
                if (count($check2) > 0) {
                    foreach($check2 as $c) {
                        $val = $c->toArray();
                        $val['name'] = '- - '.$val['name'];
                        $final[] = $val;
                        $check3 = collect(Subcategory::where('parent_id', $c['id'])->get());
                        if (count($check3) > 0) {
                            foreach($check3 as $c) {
                                $val = $c->toArray();
                                $val['name'] = '- - - '.$val['name'];
                                $final[] = $val;
                            }
                        }
                    }
                }
            }
        }
    }

I can't work out how to make this recursive despite seeing the repeated sections. Could anyone suggest a recursive function that would consistently perform what is below "recursive here onward" in the code snippet until the check returns 0?

1
  • 1
    short explanation: wrap the foreach(){} in a function and call this functions inside if(count($check)>0) { } with $check as param. Commented Sep 15, 2017 at 17:02

1 Answer 1

1

Usually what you want from a recursive function is to make a new calculation using data acquired on the previous step and also you may need the recursive level you are in.

In your case, the data you need to provide your function is the category id and the recursion level.

So I would suggest you try something like the code below:

function getSubCategories($id, $level) {
    $check = collect(Subcategory::where('category_id', $id)->get());
    $subCategories = array();
    foreach ($check as $c) {
        $val = $c->toArray();
        $subCategories[] = array(
            'id' => $val['id'],
            'name' => str_repeat('- ', $level) .$val['name'],
            'level' => $level,
            'subIds' => getSubCategories($val['id'], ++$level)
        );
    }
    return $subCategories;
}
// Call the function.
$categories = array(
    'id' => 1,
    'name' => 'name',
    'level' => 0,
    'subIds' => getSubCategories(1, 1)
);

Finally you can use another recursive function to print your data, like this one:

function printR($category) {
    print $category['name'] . $category['level'] . "\n";
    foreach ($category['subIds'] as $sub) {
        printR($sub);
    }
}
printR($categories);
Sign up to request clarification or add additional context in comments.

1 Comment

Excellent - this is exactly what I was looking for to steer in the correct direction. Modified it a bit to fit what i'm working on and works perfectly. Thanks

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.