2017-08-06 88 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

嗨邁克爾,對不起,誤導,其工作很好!非常感謝。 –