Search code examples
phprecursionhierarchical-datavirtuemart

How to export product full categories path from a hierarchical tree?


My starting point is one array with categories ids and their parents ids, from Virtuemart categories table, like this:

Array
(
    [0] => Array
        (
            [id] => 1
            [parent_id] => 0
            [name] => Category A
        )

    [1] => Array
        (
            [id] => 2
            [parent_id] => 1
            [name] => Subcategory A1
        )

    [2] => Array
        (
            [id] => 3
            [parent_id] => 2
            [name] => Sub-Subcategory A1
        )

    [3] => Array
        (
            [id] => 4
            [parent_id] => 1
            [name] => Subcategory A2
        )

    [4] => Array
        (
            [id] => 5
            [parent_id] => 0
            [name] => Category B
        )

    [5] => Array
        (
            [id] => 6
            [parent_id] => 5
            [name] => Subcategory B
        )

)

I need to have a string with each last category child full path separated by / (slash) between children and by , (comma) between first level parents

My output should be:

Category A/Subcategory A1/Sub-Subcategory A1,Category A/Subcategory A2,Category B/Subcategory B

[EDIT] I could transform starter array to this one

Array
(
    [0] => Array
        (
            [id] => 1
            [parent_id] => 0
            [name] => Category A
            [children] => Array
                (
                    [0] => Array
                        (
                            [id] => 2
                            [parent_id] => 1
                            [name] => Subcategory A1
                            [children] => Array
                                (
                                    [0] => Array
                                        (
                                            [id] => 3
                                            [parent_id] => 2
                                            [name] => Sub-Subcategory A1
                                        )

                                )

                        )

                    [1] => Array
                        (
                            [id] => 4
                            [parent_id] => 1
                            [name] => Subcategory A2

                        )

                )

        )

    [1] => Array
        (
            [id] => 5
            [parent_id] => 0
            [name] => Category B
            [children] => Array
                (
                    [0] => Array
                        (
                            [id] => 6
                            [parent_id] => 5
                            [name] => Subcategory B1

                        )

                )

        )

)

Solution

  • Given the next array :

    $array = Array(
        "0" => Array
            (
            "id" => 1,
            "parent_id" => 0,
            "name" => "Category A"
        ),
        "1" => Array
            (
            "id" => 2,
            "parent_id" => 1,
            "name" => "Subcategory A1"
        ),
        "2" => Array
            (
            "id" => 3,
            "parent_id" => 2,
            "name" => "Sub-Subcategory A1"
        ),
        "3" => Array
            (
            "id" => 4,
            "parent_id" => 1,
            "name" => "Subcategory A2"
        ),
        "4" => Array
            (
            "id" => 5,
            "parent_id" => 0,
            "name" => "Category B"
        ),
        "5" => Array
            (
            "id" => 6,
            "parent_id" => 5,
            "name" => "Subcategory B"
        )
    );
    

    Something like that :

    $tabOfElements = array();
    foreach($array as $element){
        $tabOfElements[$element['id']] = (isset($tabOfElements[$element['parent_id']])?$tabOfElements[$element['parent_id']].'/':'').$element['name'];
    }
    $stringOfCategories = implode(',',$tabOfElements);
    

    should do what you need. Note : this works only if parents categories are always BEFORE their children in the array.

    EDIT :

    To get only all last category child path, you can do :

    $tabOfElements = array();
    $elementsToDelete = array();
    foreach($array as $element){
        $tabOfElements[$element['id']] = (isset($tabOfElements[$element['parent_id']])?$tabOfElements[$element['parent_id']].'/':'').$element['name'];       
        if(isset($tabOfElements[$element['parent_id']]) && !isset($elementsToDelete[$element['parent_id']])){
            $elementsToDelete[$element['parent_id']] = $element['parent_id'];
        }
    }
    $finalArray = array_diff_key($tabOfElements, $elementsToDelete);
    $stringOfCategories = implode(',',$finalArray);
    

    This would give you :

    Category A/Subcategory A1/Sub-Subcategory A1,Category A/Subcategory A2,Category B/Subcategory B
    

    EDIT 2 : With the second array you've given, you can go with a recursive function like :

    function recursiveFunction($elementArray, $parentString = ''){
        if(isset($elementArray['children']) && !empty($elementArray['children'])){
            foreach($elementArray['children'] as $keyChild=>$child){
                $resultString .= recursiveFunction($child, $parentString.$elementArray['name'].'/').(($keyChild<count($elementArray['children'])-1)?',':'');
            }
            return $resultString;
        }else{
            return $parentString.$elementArray['name'];
        }
    }
    
    $tabOfPaths = array();
    foreach($array as $elementArray){
        $tabOfPaths[] = recursiveFunction($elementArray);
    }
    $stringOfPaths = implode(',',$tabOfPaths);
    echo $stringOfPaths;
    

    Hope it helps.