简体   繁体   中英

Parent child tree with ID's spread through multiple arrays/tables

I inherited a table structure that I have never seen for a parent/child tree. This is not your typical parent/child tree to array problem.

It involves 3 arrays; Companies, Divisions, Users

Few Rules

  1. There is always a root node that is a company
  2. A division can be a sub node of a company or division
  3. A company can be a sub node of a company or division
  4. Users never have any sub nodes

Things I've tried

I have searched like crazy to see if anyone else has had to do something similar and have found nothing. I went down the road of a recursive function and the reference method, starting with the company array. But once i need to start attaching the companies or divisions as children then checking if that division has any children companies or divisions, i get totally lost on how to make that go to any depth.

End result im looking for

This array structure. Look a this picture for the full structure.

Array
(
    [company_799] => Array
            (
                [companyid] => 799
                [parent_companyid] => 0
                [parent_divisionid] => 0
                [companyname] => Main Company
                [children] => Array
                    (
                        [user_3138] => Array
                            (
                                [userid] => 3138
                                [companyid] => 799
                                [company_divisionid] => 
                                [username] => test user 1
                            )
                        [division_58] => Array
                            (
                                 [divisionid] => 58
                                 [parent_companyid] => 799
                                 [parent_divisionid] => 0
                                 [division_name] => Division 1
                                 [children] => Array
                                     (
                                         [user_3139] => Array

       .. etc...

Company Array

    Array
    (
        [799] => Array
            (
                [companyid] => 799
                [parent_companyid] => 0
                [parent_divisionid] => 0
                [companyname] => Main Company
            )

        [800] => Array
            (
                [companyid] => 800
                [parent_companyid] => 799
                [parent_divisionid] => 0
                [companyname] => Sub Company 1
            )

        [801] => Array
            (
                [companyid] => 801
                [parent_companyid] => 800
                [parent_divisionid] => 0
                [companyname] => Sub Company 2
            )

        [802] => Array
            (
                [companyid] => 802
                [parent_companyid] => 0
                [parent_divisionid] => 59
                [companyname] => Sub Company of Division
            )
    )

Divisions

    Array
    (
        [58] => Array
            (
                [divisionid] => 58
                [parent_companyid] => 799
                [parent_divisionid] => 0
                [division_name] => Division 1
            )

        [60] => Array
            (
                [divisionid] => 60
                [parent_companyid] => 801
                [parent_divisionid] => 0
                [division_name] => Sub Division of Company
            )

        [59] => Array
            (
                [divisionid] => 59
                [parent_companyid] => 0
                [parent_divisionid] => 58
                [division_name] => Sub Division of division
            )
    )

Users

    Array
    (
        [3138] => Array
            (
                [userid] => 3138
                [companyid] => 799
                [parent_divisionid] => 0
                [username] => test user 1
            )

        [3139] => Array
            (
                [userid] => 3139
                [companyid] => 799
                [parent_divisionid] => 58
                [username] => test user 2
            )

        [3140] => Array
            (
                [userid] => 3140
                [companyid] => 799
                [parent_divisionid] => 59
                [username] => test user 3
            )

        [3141] => Array
            (
                [userid] => 3141
                [companyid] => 802
                [parent_divisionid] => 0
                [username] => test user 4
            )

        [3142] => Array
            (
                [userid] => 3142
                [companyid] => 800
                [parent_divisionid] => 0
                [username] => test user 5
            )
    )

This is the solution i came up with. Not the most elegant, but it works. Thank you RST for the help.

build_tree() is basicly building as much the tree on the first pass of the function. At the end of the function, if there is still data in the company/divisions/users arrays, it will recursively call itself.

public function get_tree()
{
    $arr_treedata              = array();
    $arr_treedata['tree']      = array(); // Where the final tree will be stored
    $arr_treedata['companies'] = $this->get_companies(); // From mysql table
    $arr_treedata['divisions'] = $this->get_divisions(); // From mysql table
    $arr_treedata['users']     = $this->get_users(); // From mysql table

    return $this->build_tree($arr_treedata);
}

private function build_tree($arr_treedata)
{
    // Append company nodes
    if (count($arr_treedata['companies']) > 0)
    {
        foreach ($arr_treedata['companies'] as $str_companyid => $arr_company)
        {
            $str_search_key = FALSE;
            if ($arr_company['parent_companyid'] == 0 && $arr_company['parent_divisionid'] == 0)
            {
                // Root node found
                $arr_treedata['tree'][$str_companyid] = $arr_company;
                unset($arr_treedata['companies'][$str_companyid]);
            }
            else if ($arr_company['parent_companyid'] > 0 && $arr_company['parent_divisionid'] == 0)
            {
                // Company is a child of a company
                $str_search_key = 'company_'.$arr_company['parent_companyid'];
            }
            else if ($arr_company['parent_companyid'] == 0 && $arr_company['parent_divisionid'] > 0)
            {
                // Company is a child of a division
                $str_search_key = 'division_'.$arr_company['parent_divisionid'];
            }

            if ($str_search_key !== FALSE)
            {
                // Search for the key
                $arr_insertdata = array('children' => array($str_companyid => $arr_company));
                $arr_newtreedata = $this->search_tree_and_insert($arr_treedata['tree'], $str_search_key, $arr_insertdata);
                if ($arr_treedata['tree'] != $arr_newtreedata)
                {
                    // Key found and new tree data detected
                    $arr_treedata['tree'] = $arr_newtreedata;
                    unset($arr_treedata['companies'][$str_companyid]);
                }
            }
        }
    }

    // Append division nodes
    if (count($arr_treedata['divisions']) > 0)
    {
        foreach ($arr_treedata['divisions'] as $str_divisionid => $arr_division)
        {
            $str_search_key = FALSE;
            if ($arr_division['parent_companyid'] != '' && $arr_division['parent_divisionid'] == '')
            {
                // Division is a child of a company
                $str_search_key = 'company_'.$arr_division['parent_companyid'];
            }
            else if ($arr_division['parent_companyid'] != '' && $arr_division['parent_divisionid'] != '')
            {
                // Division if a child of a division
                $str_search_key = 'division_'.$arr_division['parent_divisionid'];
            }

            if ($str_search_key !== FALSE)
            {
                // Search for the key
                $arr_insertdata = array('children' => array($str_divisionid => $arr_division));
                $arr_newtreedata = $this->search_tree_and_insert($arr_treedata['tree'], $str_search_key, $arr_insertdata);
                if ($arr_treedata['tree'] != $arr_newtreedata)
                {
                    // Key found and new tree data detected
                    $arr_treedata['tree'] = $arr_newtreedata;
                    unset($arr_treedata['divisions'][$str_divisionid]);
                }
            }
        }
    }

    // Append user nodes
    if (count($arr_treedata['users']) > 0)
    {
        foreach ($arr_treedata['users'] as $str_userid => $arr_user)
        {
            $str_search_key = FALSE;
            if ($arr_user['parent_companyid'] != '' && $arr_user['parent_divisionid'] == '')
            {
                // User is a child of a company
                $str_search_key = 'company_'.$arr_user['parent_companyid'];
            }
            else if ($arr_user['parent_companyid'] != '' && $arr_user['parent_divisionid'] != '')
            {
                // User if a child of a division
                $str_search_key = 'division_'.$arr_user['parent_divisionid'];
            }

            if ($str_search_key !== FALSE)
            {
                // Search for the key
                $arr_insertdata = array('children' => array($str_userid => $arr_user));
                $arr_newtreedata = $this->search_tree_and_insert($arr_treedata['tree'], $str_search_key, $arr_insertdata);
                if ($arr_treedata['tree'] != $arr_newtreedata)
                {
                    // Key found and new tree data detected
                    $arr_treedata['tree'] = $arr_newtreedata;
                    unset($arr_treedata['users'][$str_userid]);
                }
            }
        }
    }

    if (count($arr_treedata['divisions']) > 0 || count($arr_treedata['companies']) > 0 || count($arr_treedata['users']) > 0)
    {
        $arr_treedata = $this->build_tree($arr_treedata);
    }

    return $arr_treedata;
}

// Search the tree for an array key and merge the data
private function search_tree_and_insert($arr_treedata, $str_search_key, $arr_insertdata)
{
    foreach ($arr_treedata as $str_keyid => $arr_row)
    {
        if ($str_keyid == $str_search_key)
        {
            // Found key, merge in the provided data
            $arr_treedata[$str_keyid] = array_merge_recursive($arr_treedata[$str_keyid], $arr_insertdata);
        }
        else if (isset($arr_row['children']))
        {
            // Search Children
            $arr_treedata[$str_keyid]['children'] = $this->search_tree_and_insert($arr_row['children'], $str_search_key, $arr_insertdata);
        }
    }

    return $arr_treedata;
}

Result

        [company_799] => Array
            (
                [companyid] => 799
                [parent_companyid] => 0
                [parent_divisionid] => 0
                [companyname] => Main Company
                [children] => Array
                    (
                        [company_800] => Array
                            (
                                [companyid] => 800
                                [parent_companyid] => 799
                                [parent_divisionid] => 0
                                [companyname] => Sub Company 1
                                [children] => Array
                                    (
                                        [company_801] => Array
                                            (
                                                [companyid] => 801
                                                [parent_companyid] => 800
                                                [parent_divisionid] => 0
                                                [companyname] => Sub Company 2
                                                [children] => Array
                                                    (
                                                        [division_60] => Array
                                                            (
                                                                [divisionid] => 60
                                                                [parent_companyid] => 801
                                                                [parent_divisionid] => 
                                                                [division_name] => Sub Division of Company
                                                            )

                                                    )

                                            )

                                    )

                            )

                        [division_58] => Array
                            (
                                [divisionid] => 58
                                [parent_companyid] => 799
                                [parent_divisionid] => 
                                [division_name] => Division 1
                                [children] => Array
                                    (
                                        [division_59] => Array
                                            (
                                                [divisionid] => 59
                                                [parent_companyid] => 799
                                                [parent_divisionid] => 58
                                                [division_name] => Sub Division of division
                                                [children] => Array
                                                    (
                                                        [user_3140] => Array
                                                            (
                                                                [userid] => 3140
                                                                [parent_companyid] => 799
                                                                [parent_divisionid] => 59
                                                                [username] => test user 3
                                                            )

                                                        [company_802] => Array
                                                            (
                                                                [companyid] => 802
                                                                [parent_companyid] => 0
                                                                [parent_divisionid] => 59
                                                                [companyname] => Sub Company of Division
                                                            )

                                                    )

                                            )

                                        [user_3139] => Array
                                            (
                                                [userid] => 3139
                                                [parent_companyid] => 799
                                                [parent_divisionid] => 58
                                                [username] => test user 2
                                            )

                                    )

                            )

                    )

            )

That is sort of what I meant. I would change two things but that is just me.

Start with customers because their parents are already present, either in division or companies. Then handle divisions, because their parents are also already present, in companies, and if not, than this division can be added as parent.

Handling it this way would remove a lot of the searching you are doing, you can just check array indexes to see if a parent is present.

I am not too fond of if, elseif, elseif structures. I would change it to

if ( ! empty($arr_company['parent_companyid'] ) {
   // add to company 
   // other actions 
   continue;
}

if ( ! empty($arr_company['parent_divisionid'] ) {
   // add to division 
   //other actions
  continue;
}  

// no company or division parent id    
// add to tree as new division/company

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM