Родительское дочернее дерево с идентификаторами, распределенными по нескольким массивам / таблицам
Я унаследовал структуру таблицы, которую никогда не видел для родительского / дочернего дерева. Это не типичная проблема родительского / дочернего дерева в массиве.
Он включает в себя 3 массива; Компании, подразделения, пользователи
Несколько правил
- Всегда есть корневой узел, который является компанией
- Подразделение может быть подузлом компании или подразделения
- Компания может быть подузлом компании или подразделения
- Пользователи никогда не имеют никаких подузлов
Вещи, которые я пробовал
Я искал как сумасшедший, чтобы увидеть, должен ли кто-то еще делать что-то подобное и ничего не нашел. Я пошел по пути рекурсивной функции и эталонного метода, начиная с массива компании. Но как только мне нужно начать присоединять компании или подразделения в качестве детей, а затем проверять, есть ли в этом подразделении какие-либо дочерние компании или подразделения, я полностью теряюсь в том, как это сделать на любой глубине.
Конечный результат, который я ищу
Это структура массива. Посмотрите эту картинку для полной структуры.
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...
Компания Массив
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
)
)
Разделы
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
)
)
пользователей
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
)
)
2 ответа
Это решение, которое я придумал. Не самый элегантный, но работает. Спасибо RST за помощь.
build_tree () в основном строит столько же дерева при первом проходе функции. В конце функции, если в массивах компании / подразделений / пользователей все еще есть данные, она будет рекурсивно вызывать себя.
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;
}
Результат
[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
)
)
)
)
)
Это то, что я имел в виду. Я бы изменил две вещи, но это только я.
Начните с клиентов, потому что их родители уже присутствуют, в подразделении или компаниях. Затем обработайте подразделения, потому что их родители также уже присутствуют в компаниях, и если нет, то это разделение может быть добавлено как родительское.
Обработка этого способа приведет к удалению большого количества поисков, которые вы делаете, вы можете просто проверить индексы массива, чтобы увидеть, присутствует ли родительский элемент.
Я не слишком люблю if, elseif, elseif
структур. Я бы изменил это на
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