www-data
www-data

Reputation: 244

I'm having problems to alter an array using recursive functions by reference

Need help from some expert with array references. It's been one day banging my head against the wall. I need to translate a series of paths into data/children structure. I have these records from MySQL.

+----+---------------------------------+------------------------------------------------------------------------+
| id | folder                          | path_string                                                            |
+----+---------------------------------+------------------------------------------------------------------------+
|  1 | installfolder                   | INSTALLATION PARTNERS                                                  |
|  2 | installCOIfolder                | INSTALLATION PARTNERS/DOCUMENTS/COI                                    |
|  3 | installDeliveryTicketsfolder    | INSTALLATION PARTNERS/DOCUMENTS/DELIVERY TICKETS                       |
|  4 | installPdfPackagefolder         | INSTALLATION PARTNERS/PDF INSTALLATION PACKAGE                         |
|  5 | installPunchListfolder          | INSTALLATION PARTNERS/PDF INSTALLATION PACKAGE/PDF PUNCHLIST FLOORPLAN |
|  6 | installSitePhotosfolder         | INSTALLATION PARTNERS/SITE PHOTOS                                      |
|  7 | installChangeOrdersfolder       | INSTALLATION PARTNERS/DOCUMENTS/CHANGE ORDERS                          |
|  8 | installCompletionfolder         | INSTALLATION PARTNERS/SITE PHOTOS/COMPLETION                           |
|  9 | installDamagesandWarrantyfolder | INSTALLATION PARTNERS/SITE PHOTOS/DAMAGES & WARRANTY                   |
| 10 | installMarketingfolder          | INSTALLATION PARTNERS/SITE PHOTOS/MARKETING                            |
| 11 | installProgressfolder           | INSTALLATION PARTNERS/SITE PHOTOS/MARKETING                            |
| 12 | meadowsfolder                   | MEADOWS PROJECT DOCUMENTS                                              |
| 13 | meadowsChangeOrdersfolder       | MEADOWS PROJECT DOCUMENTS/CHANGE ORDERS                                |
| 14 | meadowsPunchListfolder          | MEADOWS PROJECT DOCUMENTS/PUNCHLIST                                    |
| 15 | meadowsPunchListItemsfolder     | MEADOWS PROJECT DOCUMENTS/PUNCHLIST ITEMS                              |
+----+---------------------------------+------------------------------------------------------------------------+


DROP TABLE IF EXISTS `validation_paths`;
CREATE TABLE `validation_paths` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `folder` varchar(100) NOT NULL,
  `path_string` varchar(400) DEFAULT NULL,
  `box_id_referer` varchar(100) DEFAULT NULL,
  `title` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `validation_paths` (`id`, `folder`, `path_string`, `box_id_referer`, `title`) VALUES
(1, 'installfolder',    'INSTALLATION PARTNERS',    '', 'Installation Folder'),
(2, 'installCOIfolder', 'INSTALLATION PARTNERS/DOCUMENTS/COI',  '', 'COI Folder'),
(3, 'installDeliveryTicketsfolder', 'INSTALLATION PARTNERS/DOCUMENTS/DELIVERY TICKETS', '', 'Delivery Tickets'),
(4, 'installPdfPackagefolder',  'INSTALLATION PARTNERS/PDF INSTALLATION PACKAGE',   '', 'PDF Installation Packages'),
(5, 'installPunchListfolder',   'INSTALLATION PARTNERS/PDF INSTALLATION PACKAGE/PDF PUNCHLIST FLOORPLAN',   '', 'PDF Floorplans'),
(6, 'installSitePhotosfolder',  'INSTALLATION PARTNERS/SITE PHOTOS',    '', 'Site Photos'),
(7, 'installChangeOrdersfolder',    'INSTALLATION PARTNERS/DOCUMENTS/CHANGE ORDERS',    '', 'Change Orders'),
(8, 'installCompletionfolder',  'INSTALLATION PARTNERS/SITE PHOTOS/COMPLETION', '', 'Completion'),
(9, 'installDamagesandWarrantyfolder',  'INSTALLATION PARTNERS/SITE PHOTOS/DAMAGES & WARRANTY', '', 'Damages & Warranty'),
(10,    'installMarketingfolder',   'INSTALLATION PARTNERS/SITE PHOTOS/MARKETING',  '', 'Marketing'),
(11,    'installProgressfolder',    'INSTALLATION PARTNERS/SITE PHOTOS/MARKETING',  '', 'Progress'),
(12,    'meadowsfolder',    'MEADOWS PROJECT DOCUMENTS',    '', 'Meadows Documents'),
(13,    'meadowsChangeOrdersfolder',    'MEADOWS PROJECT DOCUMENTS/CHANGE ORDERS',  '', 'Meadows Change Orders'),
(14,    'meadowsPunchListfolder',   'MEADOWS PROJECT DOCUMENTS/PUNCHLIST',  '', 'Meadows Punchlists'),
(15,    'meadowsPunchListItemsfolder',  'MEADOWS PROJECT DOCUMENTS/PUNCHLIST ITEMS',    '', 'Meadows Punchlist Items');

The goal is to get this.

stdClass Object
(
    [children] => Array
        (
            [0] => stdClass Object
                (
                    [slug] => installfolder
                    [text] => INSTALLATION PARTNERS
                    [children] => Array
                        (
                            [0] => stdClass Object
                                (
                                    [slug] => installCOIfolder
                                    [text] => DOCUMENTS
                                    [children] => Array
                                        (
                                            [0] => stdClass Object
                                                (
                                                    [slug] => installCOIfolder
                                                    [text] => COI
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                            [1] => stdClass Object
                                                (
                                                    [slug] => installDeliveryTicketsfolder
                                                    [text] => DELIVERY TICKETS
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                            [2] => stdClass Object
                                                (
                                                    [slug] => installChangeOrdersfolder
                                                    [text] => CHANGE ORDERS
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                        )

                                )

                            [1] => stdClass Object
                                (
                                    [slug] => installPdfPackagefolder
                                    [text] => PDF INSTALLATION PACKAGE
                                    [children] => Array
                                        (
                                            [0] => stdClass Object
                                                (
                                                    [slug] => installPunchListfolder
                                                    [text] => PDF PUNCHLIST FLOORPLAN
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                        )

                                )

                            [2] => stdClass Object
                                (
                                    [slug] => installSitePhotosfolder
                                    [text] => SITE PHOTOS
                                    [children] => Array
                                        (
                                            [0] => stdClass Object
                                                (
                                                    [slug] => installCompletionfolder
                                                    [text] => COMPLETION
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                            [1] => stdClass Object
                                                (
                                                    [slug] => installDamagesandWarrantyfolder
                                                    [text] => DAMAGES & WARRANTY
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                            [2] => stdClass Object
                                                (
                                                    [slug] => installMarketingfolder
                                                    [text] => MARKETING
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                        )

                                )

                        )

                )

            [1] => stdClass Object
                (
                    [slug] => meadowsfolder
                    [text] => MEADOWS PROJECT DOCUMENTS
                    [children] => Array
                        (
                            [0] => stdClass Object
                                (
                                    [slug] => meadowsChangeOrdersfolder
                                    [text] => CHANGE ORDERS
                                    [children] => Array
                                        (
                                        )

                                )

                            [1] => stdClass Object
                                (
                                    [slug] => meadowsPunchListfolder
                                    [text] => PUNCHLIST
                                    [children] => Array
                                        (
                                        )

                                )

                            [2] => stdClass Object
                                (
                                    [slug] => meadowsPunchListItemsfolder
                                    [text] => PUNCHLIST ITEMS
                                    [children] => Array
                                        (
                                        )

                                )

                        )

                )

        )

)

Now what I am trying to do. I merge this structure using two recursive functions. Here's the first.

function buildTree(array &$array, $parents, $value, $glue = '/')
{
    if (!is_array($parents)) {
        $parents = explode($glue, (string) $parents);
    }

    $ref = &$array;

    foreach ($parents as $key => $parent) {
        if (isset($ref) && !is_array($ref)) {
            $ref = [];
        }

        $ref = &$ref[$parent];
    }

    $ref = $value;
}

$query = "SELECT * FROM validation_paths";

$results = $db->query($query);

$tree = array();

if (!empty($results)){ 
    foreach ($results as $folder){
        buildTree($tree,$folder['path_string'] . '/slug',$folder['folder']);
        buildTree($tree,$folder['path_string'] . '/text',$folder['path_string']);
    }
}   

pruneTree($tree);
echo '<pre>';
print_r($tree);

From which I get the following

Array
(
    [INSTALLATION PARTNERS] => Array
        (
            [slug] => installfolder
            [text] => INSTALLATION PARTNERS
            [DOCUMENTS] => Array
                (
                    [COI] => Array
                        (
                            [slug] => installCOIfolder
                            [text] => INSTALLATION PARTNERS/DOCUMENTS/COI
                        )

                    [DELIVERY TICKETS] => Array
                        (
                            [slug] => installDeliveryTicketsfolder
                            [text] => INSTALLATION PARTNERS/DOCUMENTS/DELIVERY TICKETS
                        )

                    [CHANGE ORDERS] => Array
                        (
                            [slug] => installChangeOrdersfolder
                            [text] => INSTALLATION PARTNERS/DOCUMENTS/CHANGE ORDERS
                        )

                )

            [PDF INSTALLATION PACKAGE] => Array
                (
                    [slug] => installPdfPackagefolder
                    [text] => INSTALLATION PARTNERS/PDF INSTALLATION PACKAGE
                    [PDF PUNCHLIST FLOORPLAN] => Array
                        (
                            [slug] => installPunchListfolder
                            [text] => INSTALLATION PARTNERS/PDF INSTALLATION PACKAGE/PDF PUNCHLIST FLOORPLAN
                        )

                )

            [SITE PHOTOS] => Array
                (
                    [slug] => installSitePhotosfolder
                    [text] => INSTALLATION PARTNERS/SITE PHOTOS
                    [COMPLETION] => Array
                        (
                            [slug] => installCompletionfolder
                            [text] => INSTALLATION PARTNERS/SITE PHOTOS/COMPLETION
                        )

                    [DAMAGES & WARRANTY] => Array
                        (
                            [slug] => installDamagesandWarrantyfolder
                            [text] => INSTALLATION PARTNERS/SITE PHOTOS/DAMAGES & WARRANTY
                        )

                    [MARKETING] => Array
                        (
                            [slug] => installProgressfolder
                            [text] => INSTALLATION PARTNERS/SITE PHOTOS/MARKETING
                        )

                )

        )

    [MEADOWS PROJECT DOCUMENTS] => Array
        (
            [slug] => meadowsfolder
            [text] => MEADOWS PROJECT DOCUMENTS
            [CHANGE ORDERS] => Array
                (
                    [slug] => meadowsChangeOrdersfolder
                    [text] => MEADOWS PROJECT DOCUMENTS/CHANGE ORDERS
                )

            [PUNCHLIST] => Array
                (
                    [slug] => meadowsPunchListfolder
                    [text] => MEADOWS PROJECT DOCUMENTS/PUNCHLIST
                )

            [PUNCHLIST ITEMS] => Array
                (
                    [slug] => meadowsPunchListItemsfolder
                    [text] => MEADOWS PROJECT DOCUMENTS/PUNCHLIST ITEMS
                )

        )

)

Then I got stucked. I use this recursive function to alter this structure to my needs but with no good results.

Here is the function.

function has_array($arr){
    foreach($arr as $k=>$v){
        if(is_array($v)) {
           return $v;  
        }
    }
    return false;
}


function get_text($txt,$pos=1){
    $parts = explode("/",$txt);
    if(count($parts)){
        return $parts[count($parts)-$pos];
    }
    return $parts;                 
}

function pruneTree(&$nodes) {

    //$nodes = array_values($nodes);

    if(empty($nodes["slug"]) AND $first = has_array($nodes)){
        $nodes["slug"] = $first["slug"];
    }

    $text = get_text($nodes["text"]);
    if(empty($nodes["text"]) AND $first = has_array($nodes)){
        $text = get_text($first["text"],2);
    }

    $nodes["text"] = $text;
    $nodes["children"] = [];

    foreach ($nodes as $key => &$node) {
        if(is_array($node) AND count($node)){
            pruneTree($node);
        }
    }
}    

From which I get

Array
(
    [INSTALLATION PARTNERS] => Array
        (
            [slug] => installfolder
            [text] => INSTALLATION PARTNERS
            [DOCUMENTS] => Array
                (
                    [COI] => Array
                        (
                            [slug] => installCOIfolder
                            [text] => COI
                            [children] => Array
                                (
                                )

                        )

                    [DELIVERY TICKETS] => Array
                        (
                            [slug] => installDeliveryTicketsfolder
                            [text] => DELIVERY TICKETS
                            [children] => Array
                                (
                                )

                        )

                    [CHANGE ORDERS] => Array
                        (
                            [slug] => installChangeOrdersfolder
                            [text] => CHANGE ORDERS
                            [children] => Array
                                (
                                )

                        )

                    [slug] => installCOIfolder
                    [text] => DOCUMENTS
                    [children] => Array
                        (
                        )

                )

            [PDF INSTALLATION PACKAGE] => Array
                (
                    [slug] => installPdfPackagefolder
                    [text] => PDF INSTALLATION PACKAGE
                    [PDF PUNCHLIST FLOORPLAN] => Array
                        (
                            [slug] => installPunchListfolder
                            [text] => PDF PUNCHLIST FLOORPLAN
                            [children] => Array
                                (
                                )

                        )

                    [children] => Array
                        (
                        )

                )

            [SITE PHOTOS] => Array
                (
                    [slug] => installSitePhotosfolder
                    [text] => SITE PHOTOS
                    [COMPLETION] => Array
                        (
                            [slug] => installCompletionfolder
                            [text] => COMPLETION
                            [children] => Array
                                (
                                )

                        )

                    [DAMAGES & WARRANTY] => Array
                        (
                            [slug] => installDamagesandWarrantyfolder
                            [text] => DAMAGES & WARRANTY
                            [children] => Array
                                (
                                )

                        )

                    [MARKETING] => Array
                        (
                            [slug] => installProgressfolder
                            [text] => MARKETING
                            [children] => Array
                                (
                                )

                        )

                    [children] => Array
                        (
                        )

                )

            [children] => Array
                (
                )

        )

    [MEADOWS PROJECT DOCUMENTS] => Array
        (
            [slug] => meadowsfolder
            [text] => MEADOWS PROJECT DOCUMENTS
            [CHANGE ORDERS] => Array
                (
                    [slug] => meadowsChangeOrdersfolder
                    [text] => CHANGE ORDERS
                    [children] => Array
                        (
                        )

                )

            [PUNCHLIST] => Array
                (
                    [slug] => meadowsPunchListfolder
                    [text] => PUNCHLIST
                    [children] => Array
                        (
                        )

                )

            [PUNCHLIST ITEMS] => Array
                (
                    [slug] => meadowsPunchListItemsfolder
                    [text] => PUNCHLIST ITEMS
                    [children] => Array
                        (
                        )

                )

            [children] => Array
                (
                )

        )

    [slug] => installfolder
    [text] => 
    [children] => Array
        (
        )

)

Can anyone give me a hint in the right direction? Thanks.

Upvotes: 2

Views: 109

Answers (2)

shudder
shudder

Reputation: 2101

Since objects are passed as references themselves you need only a way to find the right one using path segment (relation data). Easiest way would be use these paths as indexes which you may refer to in consequent iterations. Try this function:

function buildTree($data) {
    $tree = new StdClass;
    $index = [];
    foreach ($data as $item) {
        $node = $tree;
        $path = '';
        foreach (explode('/', $item['path_string']) as $segment) {
            $path .= empty($path) ? $segment : '/' . $segment;
            if (!isset($index[$path])) {
                $index[$path] = new stdClass;
                $index[$path]->slug = $item['folder'];
                $index[$path]->text = $segment;
                $index[$path]->children = [];
                $node->children[] = $index[$path]
            }
            $node = $index[$path];
        }
    }

    return $tree;
}

In your example there's no data for INSTALLATION PARTNERS/DOCUMENTS, so it will remain empty node (children only). If it's not a mistake provide some info, because I don't know how to resolve its properties so it could match expected result.

Upvotes: 2

Michel
Michel

Reputation: 960

First there would be other ways to do this but to keep your workflow, I would modify the buildTree function to store all data required. To do so you can use this answer from 'Using a string path to set nested array data':

function set_nested_array_value(&$array, $path, &$value, $delimiter = '/') {
    $pathParts = explode($delimiter, $path);

    $current = &$array;
    foreach($pathParts as $key) {
        $current = &$current[$key];
    }

    $backup = $current;
    $current = $value;

    return $backup;
}

Now you can call this function and use the value to store your slug, I use ['folder'=>$path['folder']] in this case, so now you have:

function buildTree($results){
    $data = [];
    foreach($results as $path){
        $r = [];
        $v = ['folder'=>$path['folder']];
        $res = set_nested_array_value($r, $path['path_string'], $v);
        $data = array_merge_recursive($data, $r);
   }  
   return $data;
}

Then modify pruneTree to create the stdClass object with their children:

function pruneTree( $array){
    $result = []; $i = 0;

    foreach($array as $key=>$node){
       $r = [];
       // set the slug if it exists
        if(isset( $node['folder'])){
            $r['slug'] = $node['folder'];
            unset($node['folder']);
        }
        $r['text']  = $key;
        // set the children through recursion
        $r['children'] = pruneTree($node);

        // when the node does not have slug (ie: DOCUMENTS)
        // set the slug of the first child - to match expected results.
        if(!isset($r['slug']) && isset($r['children'][0])){
            $r['slug'] =  $r['children'][0]->slug;
        }
        // transform to object - to match expected results.
        $result[$i] =(object) $r;  
        $i++;
    }

    return $result;
}

And now to match your expected results, you can do:

$r = [
    'children' => pruneTree(buildTree($results))
];
print_r((object)$r); 

here's the gist

Upvotes: 1

Related Questions