Построение структуры меню родительского / дочернего массива из результата запроса SQL

Мне нужно построить сложную структуру меню динамически, используя запрос 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, есть следующие ошибки:

  1. Элемент MNU_ID, MNU_FUNC, MNU_PARENT не должен быть там (см. Другие)
  2. Элементы под ‘sub’ имеют те же ошибки в 1.
  3. Пункты под ‘sub’ должны быть идентифицированы по BASE, FLPR, а не по 0 и 1

Таким образом, ожидаемая структура должна быть следующей:

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

Несмотря на мои усилия, я не могу понять, где ошибка.
Есть ли альтернатива моему рабочему процессу?

3

Решение

Вы можете использовать только одну рекурсивную функцию:

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

Другие решения

этот код решил проблему:

$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,

0

По вопросам рекламы [email protected]