2017-08-06 40 views
2

需要数组引用的专家的帮助。有一天,我的头撞在墙上。我需要将一系列路径翻译成数据/儿童结构。我有来自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'); 

目标是得到这个。

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 
             (
             ) 

           ) 

         ) 

       ) 

     ) 

) 

现在我正在尝试做什么。我使用两个递归函数来合并这个结构。这是第一个。

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); 

从中我得到以下

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 
       ) 

     ) 

) 

然后我stucked。我使用这个递归函数来改变这个结构来满足我的需求,但没有好的结果。

这是功能。

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); 
     } 
    } 
}  

从中我得到

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 
     (
     ) 

) 

谁能给我一个提示,在正确的方向?谢谢。

回答

2

由于对象作为引用传递自己只需要一种方法来找到使用路径段(关系数据)是正确的。最简单的方法是使用这些路径作为索引,您可以在随后的迭代中引用它们。试试这个功能:

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; 
} 

在您的例子有没有数据INSTALLATION PARTNERS/DOCUMENTS,所以它仍将是空节点(独生子女)。如果提供一些信息并不是一个错误,因为我不知道如何解决它的属性,所以它可以匹配预期的结果。

+0

非常接近!仍然计算出DOCUMENTS条目异常并向所有人添加子节点,即使是空的。如果这可以在一个函数中实现,这个答案会很棒!非常感谢。 –

+0

非常感谢你的兄弟,你的方法真的很好熟练!下面是在JUST ONE递归函数中进行的小修改。 https://pastebin.com/Wbz1MwKU 你值得捐一个人,万分感谢。 –

+0

@ www-data我会把它回答。要小心,因为它取决于数据库中的记录顺序(这是唯一可以解决这个空“DOCUMENTS”节点的方法)。考虑进入['Adjacency List Model']](http://www.mysqltutorial.org/mysql-adjacency-list-tree/) – shudder

1

首先会有其他的方法可以做到这一点,但让您的工作流程,我会修改buildTree功能来存储所需的所有数据。要做到这一点,你可以使用这个答案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; 
} 

现在你可以调用这个函数,并使用该值来存储您的蛞蝓,我在这种情况下使用['folder'=>$path['folder']],所以现在你有:

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; 
} 

然后修改pruneTree与子女创建stdClass的对象:

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; 
} 

现在以符合您的预期效果,你可以这样做:

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

这里的gist

+0

谢谢您的回答,但我几乎在那里我开始。没有儿童钥匙正在被路径段名称取代。 https://pastebin.com/V5TjSpZz –

+0

我用你的SQL创建表,我从运行[要点](https://gist.github.com/lequer/d93449b604aafee7ae4827777061a8ae)代码即可获得准确的预期的结果。你有没有改变你的表格或查询? – Michel

+0

嗨迈克尔,对不起,误导,其工作很好!非常感谢。 –