Мне нужно построить сложную структуру меню динамически, используя запрос MySQL DB. Запрос позволяет определить пункты меню, которые пользователь имеет право использовать и просматривать. Структура меню сохраняется в результирующем наборе в классическом родительском / дочернем отношении, где каждый элемент имеет свой собственный идентификатор и полагается на свой родительский идентификатор. Parent id = 0 означает, что над этим элементом нет родителей (это корень):
MNU_ID MNU_FUNC MNU_PARENT MNU_ICON MNU_TITLE_IT MNU_TITLE_EN
----------------------------------------------------------------------------
1 FLTMGR 0 home STATO FLOTTA FLEET STATUS
2 PSTN 0 map-marker POSIZIONI POSITIONS
3 RTS 0 road PERCORSI ROUTES
4 CHRTS 0 line-charts DIAGRAMMI CHARTS
...
13 MNLS 0 book MANUALI MANUALS
14 RGLTNS 0 bank NORMATIVE REGULATIONS
16 SPD 4 tachometer VELOCITA' SPEED
17 ALT 4 area-chart ALTITUDINE ALTITUDE
18 DST 4 exchange DISTANZA DISTANCE
...
32 INSTL 13 book INSTALLAZIONE SETUP
33 BASE 32 wrench BASE BASE
34 FLPR 32 wrench SONDA CARB. FUAL PROBE
Таким образом, как вы можете видеть, элемент 33 и 34 находится под элементом 32, в то время как элемент 32 находится под элементом 13, и, наконец, элемент 13 не имеет родителя, поскольку является корневым элементом (его MNU_PARENT равен 0).
Хорошо сказав, что я разработал свой код, чтобы вернуть следующее:
Array(
[FLTMGR] => Array(
[icon] => fa fa-home
[title] => STATO FLOTTA
),
[PSTN] => Array(
[icon] => fa fa-map-marker
[title] => POSIZIONI
),
[RTS] => Array(
[icon] => fa fa-road
[title] => PERCORSI
),
[CHRTS] => Array(
[icon] => fa fa-line-charts
[title] => DIAGRAMMI
[sub] => Array(
[SPD] => Array(
[icon] => fa fa-tachometer
[title] => VELOCITÁ
),
[ALT] => Array(
[icon] => fa fa-area-chart
[title] => ALTITUDINE
),
[DST] => Array(
[icon] => fa fa-exchange
[title] => DISTANZA
),
[GSLN] => Array(
[icon] => fa fa-tint blink
[title] => CARBURANTE
)
)
),
...
[MNLS] => Array(
[icon] => fa fa-book
[title] => MANUALI
[sub] => Array(
[INSTL] => Array(
[MNU_ID] => 32
[MNU_FUNC] => INSTL
[MNU_PARENT] => 13
[icon] => fa fa-book
[title] => INSTALLAZIONE
[sub] => Array(
[0] => Array(
[MNU_ID] => 33
[MNU_FUNC] => BASE
[MNU_PARENT] => 32
[icon] => fa fa-wrench
[title] => BASE
),
[1] => Array(
[MNU_ID] => 34
[MNU_FUNC] => FLPR
[MNU_PARENT] => 32
[icon] => fa fa-wrench
[title] => SONDA CARB.
)
)
)
)
),
[RGLTNS] => Array(
[icon] => fa fa-bank
[title] => NORMATIVE
)
)
Однако, как вы можете видеть, я не могу создать правильную структуру на первом уровне. Другими словами, если вы посмотрите на элемент INSTL в MNLS, есть следующие ошибки:
Таким образом, ожидаемая структура должна быть следующей:
Array(
[FLTMGR] => Array(
[icon] => fa fa-home
[title] => STATO FLOTTA
),
[PSTN] => Array(
[icon] => fa fa-map-marker
[title] => POSIZIONI
[RTS] => Array(
[icon] => fa fa-road
[title] => PERCORSI
),
[CHRTS] => Array(
[icon] => fa fa-line-charts
[title] => DIAGRAMMI
[sub] => Array(
[SPD] => Array(
[icon] => fa fa-tachometer
[title] => VELOCITÁ
),
[ALT] => Array(
[icon] => fa fa-area-chart
[title] => ALTITUDINE
),
[DST] => Array(
[icon] => fa fa-exchange
[title] => DISTANZA
),
[GSLN] => Array(
[icon] => fa fa-tint blink
[title] => CARBURANTE
)
)
),
...
[MNLS] => Array(
[icon] => fa fa-book
[title] => MANUALI
[sub] => Array(
[INSTL] => Array(
[icon] => fa fa-book
[title] => INSTALLAZIONE
[sub] => Array(
[BASE] => Array(
[icon] => fa fa-wrench
[title] => BASE
),
[FLPR] => Array(
[icon] => fa fa-wrench
[title] => SONDA CARB.
)
)
)
)
),
[RGLTNS] => Array(
[icon] => fa fa-bank
[title] => NORMATIVE
)
)
А теперь код:
// $MenuDB contains the Menu structure returned by the DB
// Build the basic structure
$new = array();
foreach ($MenuDB as $a){
$new[$a['MNU_PARENT']][] = $a;
}
// Calls the recursive function CreateTree
$tree = createTree($new, $new[0]);
// Make final correction (remove unwanted items and replace index with keys)
$b=replaceKeys($tree);
print_r($b);
exit();
function replaceKeys(array $input) {
foreach($input as $key => &$val){ // Scan the input array, each element will go in $val, the key will be $key
$input[$val['MNU_FUNC']]=$input[$key]; // Replace index with key, the key is the value of the field MNU_FUNC
if(is_numeric($key)) unset($input[$key]); // Remove the item with numeric key (index) and leave the item with non-numeric index (key)
unset($val['MNU_ID']); // Remove ID
unset($val['MNU_PARENT']); // Remove Parent
unset($val['MNU_FUNC']); // Remove Function
if(isset($val['sub'])) { // avoid to work with undefined items
if (is_array($val['sub'])) { // check if there are childs inside the 'sub' item
$val['sub'] = replaceKeys($val['sub']); // if we have childs, do it again recursively
unset($val['url']); // remove url element if we have childs
unset($val['url_target']); // remove url_target element if we have childs
}
}
}
return $input;
}
function createTree(&$list, $parent){
$tree = array();
foreach ($parent as $k=>$l){
if(isset($list[$l['MNU_ID']])){
$l['sub'] = createTree($list, $list[$l['MNU_ID']]);
}
$tree[] = $l;
}
return $tree;
}
Несмотря на мои усилия, я не могу понять, где ошибка.
Есть ли альтернатива моему рабочему процессу?
Вы можете использовать только одну рекурсивную функцию:
function makeTree($array, $parent) {
$return = [];
foreach ($array as $key => $value) {
if ($value['MNU_PARENT'] == $parent) {
$return[$value['MNU_FUNC']] = [
'icon' => 'fa fa-' . $value['MNU_ICON'],
'title' => $value['MNU_TITLE_IT'],
];
$subs = false;
foreach ($array as $search) {
if ($search['MNU_PARENT'] == $value['MNU_ID']) {
$subs = true;
}
}
if ($subs === true) {
$return[$value['MNU_FUNC']]['subs'] = makeTree($array, $value['MNU_ID']);
}
}
}
return $return;
}
$new = makeTree($arr, 0);
этот код решил проблему:
$new = array();
foreach ($MenuDB as $a){
$new[$a['MNU_PARENT']][] = $a;
}
$tree = createTree($new, $new[0]);
print_r($tree).PHP_EOL;
exit();function createTree(&$list, $parent){
$tree = array();
foreach ($parent as $k=>$l){
if(isset($list[$l['MNU_ID']])){ // check if current element has childs
$l['sub'] = createTree($list, $list[$l['MNU_ID']]); // build child structure inside 'sub'
unset($l['url']); // remove the 'url' item for elements having childs
unset($l['url_target']); // remove the 'url_target' item for elements having childs
}
unset($l['MNU_ID']); // remove the 'MNU_ID' item not needed anymore
unset($l['MNU_PARENT']); // remove the 'MNU_PARENT' item not needed anymore
//$tree[] = $l;
$tree[$l['MNU_FUNC']]=$l; // while $tree[] = $l; will transfer the elements array to $tree using index, this one will will transfer the elements array to $tree using the key $l['MNU_FUNC']
unset($tree[$l['MNU_FUNC']]['MNU_FUNC']); // remove the 'MNU_FUNC' item not needed anymore
}
return $tree;
}
Это короче и даже толще! replaceKeys
больше не нужно, мы можем сделать все вещи внутри createTree
,