簡體   English   中英

PHP遞歸菜單多維數組生成器

[英]PHP recursive menu multi-dimensional array generator

我在一些代碼上苦苦掙扎...我的菜單布局數組:

$navigationMenu = [
    SECTION_OVERVIEW => [
        'hide' => TRUE,
        'id' => 'overview_button',
        'order' => 0,
        'content/overview.php' => [

            SECTION_CABINET => [
                'hide' => TRUE,
                'id' => 'cabinet_button',
                'content/cabinet.php' => [

                    SECTION_AMP_PSU => [
                        'hide' => TRUE,
                        'id' => 'amps_psu_button',
                        'ampNoIndicator' => TRUE,
                        'order' => 3,
                        'content/amp_psu.php' => [

                            SECTION_AMPS_OFF => [
                                'hide' => false,
                                'id' => 'amps_off_button',
                                'ampNoIndicator' => TRUE,
                                'class' => 'red',
                                'order' => 4,
                            ],

                            SECTION_AMPS_ALARMS => [
                                'id' => 'amps_alarms',
                                'ampNoIndicator' => TRUE,
                                'order' => 5,
                                'content/amp_alarms.php' => NULL
                            ]
                        ]
                    ],
                    'POOP' => [
                        'hide' => false,
                        'id' => 'amps_psu_button',
                        'ampNoIndicator' => TRUE,
                        'order' => 3,
                        'content/amp_psu.php' => NULL
                    ]
                ]
            ]
        ]
    ],
    SECTION_SYSCONFIG => [
        'id' => 'sysConfig',
        'order' => 1,
        'content/system_configuration.php' => NULL,
    ],

    SECTION_SYS => [
        'id' => 'system',
        'order' => 2,
        'content/system.php' => NULL,
    ],

    BACK_BUTTON => [
        'id' => 'backBtn',
        'order' => 100,
        'prev' => NULL,
    ],

    RESCAN_BUTTON => [
        'id' => 'rescan',
        'order' => 101,
    ]
];

我有一個生成菜單的類。

class Navigation {
    private $doc;
    private $xpath;
    private $rootNode;

    /**
     *  Initialize navigation.
     */
    public function __construct() {
        global $navigationMenu;
        $menu = $navigationMenu;
        $this->doc = new DOMDocument();
        $this->doc->appendChild($this->buildMenu($menu));
        $this->xpath = new DOMXpath($this->doc);
    }

    /**
     *  Build Menu
     *  @param  $menu       array       see $menu array at the begining of the class
     *  @param  $depth      int         maintain a depth count for nested UL menu
     *  @param  $nestingUL  bool        false (default): does not output menu in a nested UL config
     *                                  true: nested UL config
     *  
     *  @return DOMElement              function returns DOM element of UL
     */
    private function buildMenu($menu, $depth = 0, $nestingUL = false) {
        $ulNode = $this->doc->createElement('ul');

        if (!$depth) {
            $ulNode->setAttribute('id', 'primary-nav');
            $this->rootNode = $ulNode;
        }

        $this->appendtoNode($menu, $depth, $nestingUL, $ulNode);

        return $ulNode;
    }

    /**
     *  Append menu items to a node (either UL or LI)
     *  
     *  @param  $menu                   array       array of menu items list
     *  @param  $depth                  array       depth count for nested UL menu
     *  @param  $nestingUL              bool        false: no nesting UL; true: nesting UL
     *  @param  $node                   DOMElement  passing node variable
     *  @param  $showElementOverride    bool        override skipping hidden elements
     *  
     */
    private function appendtoNode($menu, $depth, $nestingUL, $node, $showElementOverride = false) {
        foreach ($menu as $itemText => $item) {
            if ((empty($item['hide']) || !($item['hide']) || $showElementOverride)) {
                $node->appendChild($this->buildMenuItem($itemText, $item, $depth, $nestingUL));
            }

            else if (array_key_exists('hide', $item) && $item['hide']) {
                $newArr = $this->hiddenArraySkipNext($menu);
                $this->appendtoNode($newArr, $depth, $nestingUL, $node, $showElementOverride);
            }
        }
        return;
    }

  /**
   *  Build menu item.
   *  
   *  @param   $itemText        string          (button/menu label)
   *  @param   $item            array           (button modifiers array)
   *  @param   $depth           int             (maintaining depth count (only for creating a nested UL))
   *  @param   $nesting         bool            (true if nesting is required; false if no nesting)
   */  
    private function buildMenuItem($itemText, $item, $depth, $nesting) {
        $id = '';
        $spanclassAttr = array('navButton-color');
        $order = '';
        $url = '';
        $ampNo = '';
        $childMenu = false;

        // prepare node structure
           $liNode = $this->doc->createElement('li');
         $spanNode = $this->doc->createElement('span');
        $glareNode = $this->doc->createElement('span');     // spare span tag used to carry the glare class attribute
            $pNode = $this->doc->createElement('p');

        // initialize node attributes
        $liNode->setAttribute('class', 'navButton');
        $glareNode->setAttribute('class', 'glare');         // spare span tag with "glare" class attribute

        // iterate item properties
        foreach ($item as $key => $value) {
            switch ($key) {
                case 'hide':
                    break;
                case 'id':
                    $id = $value;
                    break;
                case 'ampNoIndicator':
                    $ampNo = $value;
                    break;
                case 'class':
                    $spanclassAttr[] = $value;
                    break;
                case 'order':
                    $order = $value;
                    break;
                default:
                    $url = $key;
                    $childMenu = $value;
            }
        }

        // map iterated items to nodes
        $liNode->setAttribute('id', $id);

        if ($spanclassAttr) {
            $spanNode->setAttribute('class', implode(' ', $spanclassAttr));
        }

        $pNode->nodeValue = $itemText;
        $spanNode->appendChild($pNode);
        $liNode->appendChild($spanNode);
        $liNode->appendChild($glareNode);

        if (is_array($childMenu) && $nesting) {
            $liNode->appendChild($this->buildMenu($childMenu, $depth + 1, $nesting));
        }
        else if (is_array($childMenu) && !$nesting) {
            $this->appendtoNode($childMenu, $depth, $nesting, $liNode);
        }
        return $liNode;
    }

    /**
     *  Iterating menu array
     *  
     *  @param  $item           menu array
     *  @return array | bool    return the nested array, else return false
     */
    private function hiddenArraySkipNext($arr) {
        $output = $arr;
        foreach ($arr as $tempArr) {
            if (array_key_exists('hide', $tempArr) && $tempArr['hide']) {
                foreach ($tempArr as $key => $value) {
                    if (is_array($value)) {
                        $output = $value;
                        $this->hiddenArraySkipNext($output);
                    }
                }
            }
            else if (!array_key_exists('hide', $tempArr) || (array_key_exists('hide', $tempArr) && !$tempArr['hide'])) {
                return $output;
            }
        }
        return $output;
    }

    /**
    * Get menu.
    */
    public function getMenu() {
        return $this->doc->saveHTML();
    }
}

因此,該類的目的是能夠生成$ navigationMenu的嵌套UL或非嵌套UL(請參閱我通過buildMenu,appendtoNode等使用的$ nestingUL / $ nesting參數的用法)。 我還希望能夠覆蓋$ navigationMenu中的所有“隱藏”鍵(請參閱appendtoNode()函數中的$ showElementOverride)。 當陣列處於我已設置的配置中時,菜單按計划顯示。 但是,如果我想在菜單上進行擴展,則會遇到問題。

在下面的此陣列配置中,我的SECTION_AMPS_OFF和SECTION_AMPS_ALARMS輸出兩次。

$navigationMenu = [
    SECTION_OVERVIEW => [
        'hide' => TRUE,
        'id' => 'overview_button',
        'order' => 0,
        'content/overview.php' => [

            SECTION_CABINET => [
                'hide' => TRUE,
                'id' => 'cabinet_button',
                'content/cabinet.php' => [

                    SECTION_AMP_PSU => [
                        'hide' => TRUE,
                        'id' => 'amps_psu_button',
                        'ampNoIndicator' => TRUE,
                        'order' => 3,
                        'content/amp_psu.php' => [

                            SECTION_AMPS_OFF => [
                                'hide' => false,
                                'id' => 'amps_off_button',
                                'ampNoIndicator' => TRUE,
                                'class' => 'red',
                                'order' => 4,
                            ],

                            SECTION_AMPS_ALARMS => [
                                'id' => 'amps_alarms',
                                'ampNoIndicator' => TRUE,
                                'order' => 5,
                                'content/amp_alarms.php' => NULL
                            ]
                        ]
                    ],
                    'POOP' => [
                        'hide' => true,
                        'id' => 'amps_psu_button',
                        'ampNoIndicator' => TRUE,
                        'order' => 3,
                        'content/amp_psu.php' => NULL
                    ]
                ]
            ]
        ]
    ],
    SECTION_SYSCONFIG => [
        'id' => 'sysConfig',
        'order' => 1,
        'content/system_configuration.php' => NULL,
    ],

    SECTION_SYS => [
        'id' => 'system',
        'order' => 2,
        'content/system.php' => NULL,
    ],

    BACK_BUTTON => [
        'id' => 'backBtn',
        'order' => 100,
        'prev' => NULL,
    ],

    RESCAN_BUTTON => [
        'id' => 'rescan',
        'order' => 101,
    ]
];

而且,當我按如下所示配置菜單時,我收到關於允許的內存大小用盡的致命錯誤。

$navigationMenu = [
    SECTION_OVERVIEW => [
        'hide' => TRUE,
        'id' => 'overview_button',
        'order' => 0,
        'content/overview.php' => [

            SECTION_CABINET => [
                'hide' => TRUE,
                'id' => 'cabinet_button',
                'content/cabinet.php' => [

                    SECTION_AMP_PSU => [
                        'hide' => TRUE,
                        'id' => 'amps_psu_button',
                        'ampNoIndicator' => TRUE,
                        'order' => 3,
                        'content/amp_psu.php' => [

                            SECTION_AMPS_OFF => [
                                'hide' => true,
                                'id' => 'amps_off_button',
                                'ampNoIndicator' => TRUE,
                                'class' => 'red',
                                'order' => 4,
                            ],

                            SECTION_AMPS_ALARMS => [
                                'id' => 'amps_alarms',
                                'ampNoIndicator' => TRUE,
                                'order' => 5,
                                'content/amp_alarms.php' => NULL
                            ]
                        ]
                    ],
                    'POOP' => [
                        'hide' => false,
                        'id' => 'amps_psu_button',
                        'ampNoIndicator' => TRUE,
                        'order' => 3,
                        'content/amp_psu.php' => NULL
                    ]
                ]
            ]
        ]
    ],
    SECTION_SYSCONFIG => [
        'id' => 'sysConfig',
        'order' => 1,
        'content/system_configuration.php' => NULL,
    ],

    SECTION_SYS => [
        'id' => 'system',
        'order' => 2,
        'content/system.php' => NULL,
    ],

    BACK_BUTTON => [
        'id' => 'backBtn',
        'order' => 100,
        'prev' => NULL,
    ],

    RESCAN_BUTTON => [
        'id' => 'rescan',
        'order' => 101,
    ]
];

我很確定解決方案不會擴展內存限制。 最終目標是能夠循環遍歷數組,並吐出任何未隱藏的導航菜單按鈕(嵌套的或非嵌套的UL),只要$ showElementOverride未設置為TRUE。 如果父數組被隱藏,則可以顯示子數組,只要它不是嵌套的UL。 我尚未解決該問題,因為我一直在嘗試解決hiddenArraySkipNext()函數。 在過去的幾天里,我一直在為此苦苦掙扎,因此一定會感激不盡!

重寫了我的buildMenu(),appendtoNode()和hiddenArraySkipNext()函數:

private function buildMenu($menu, $depth = 0, $nestingUL = true, $showElementOverride = false) {
    $ulNode = $this->doc->createElement('ul');

    if (!$depth) {
        $ulNode->setAttribute('id', 'primary-nav');
        $this->rootNode = $ulNode;
    }

    $this->appendtoNode($menu, $depth, $nestingUL, $ulNode, $showElementOverride);

    return $ulNode;
}

private function appendtoNode($menu, $depth, $nestingUL, $node, $showElementOverride = false) {
    foreach ($menu as $itemText => $item) {
        if (empty($item['hide']) || !($item['hide']) || $showElementOverride) {
            $node->appendChild($this->buildMenuItem($itemText, $item, $depth, $nestingUL));
        }

        else if ((array_key_exists('hide', $item) && $item['hide']) && !$nestingUL) {
            $tempMenu = $this->hiddenArraySkipNext($item);

            if (is_array($tempMenu)) $this->appendtoNode($tempMenu, $depth, $nestingUL, $node, $showElementOverride);
        }
    }
    return;
}

private function hiddenArraySkipNext($arr = array()) {
    $output = array();
    foreach ($arr as $tempArr) {
        $output = $tempArr;
        if (is_array($tempArr) && !empty($tempArr)) {
            foreach ($tempArr as $val) {
                if (is_array($val) && array_key_exists('hide', $val) && $val['hide']) {
                    $this->hiddenArraySkipNext($val);   
                }
            }
        }
    }
    return $output;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM