2

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.

www-data
  • 244
  • 2
  • 9

2 Answers2

2

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.

shudder
  • 2,076
  • 2
  • 20
  • 21
  • Pretty close! Still figuring out DOCUMENTS entry exception and adding children node to all even when empty. If this could be achived in one function this answer would be awesome! Thanks a lot. – www-data Aug 06 '17 at 14:29
  • Thank you so much brother, your approach is really good skilled! Here's the minor edit to get this working in JUST ONE recursive function. https://pastebin.com/Wbz1MwKU You deserve a donate man, a million thanks. – www-data Aug 06 '17 at 16:47
  • @www-data I'll put that into answer. Be careful though, because it depends on record order in database (it's the only way you could resolve that empty `DOCUMENTS` node anyway). Think about going into [`Adjacency List Model`](http://www.mysqltutorial.org/mysql-adjacency-list-tree/) – shudder Aug 06 '17 at 17:14
  • +1 for noting that the object are passed by reference and having it all done in one function, nicely done. – Michel Aug 06 '17 at 23:18
1

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

Michel
  • 950
  • 14
  • 23
  • Thanks for your answer, but I'm practically where I begun. No children key is being replace with path segment name. https://pastebin.com/V5TjSpZz – www-data Aug 06 '17 at 13:40
  • I used your sql to create the table and I run the code from [gist](https://gist.github.com/lequer/d93449b604aafee7ae4827777061a8ae) to get exactly your expected result. Did you change your table or the query? – Michel Aug 06 '17 at 14:03
  • Hi Michael, sorry for the misleading, its working great! Thanks a lot. – www-data Aug 06 '17 at 14:12
  • Did I write Michael? sorry Michel. The only problem I see is the ordering of the members being "slug" at the end, this could trigger a malformed json perhaps. Thanks. – www-data Aug 06 '17 at 14:17
  • I modified pruneTree to the following, in order to keep the proper keys ordering and avoid slugs being assigned as arrays. https://pastebin.com/BbVChDjM Thanks again. – www-data Aug 06 '17 at 14:28
  • 1
    @www-data Happy to help. yes my answer does not cover all cases or any other requirements you may have and is only one way to do it. Modify at will :) – Michel Aug 06 '17 at 14:51
  • Thank you Michel, and thanks to StackOverflow one of the finest expression of internet and the spirit to share knowledge. – www-data Aug 06 '17 at 15:41