3 namespace wcf\data\menu\item
;
5 use wcf\system\page\PageLocationManager
;
6 use wcf\system\request\RequestHandler
;
9 * Represents a menu item node tree.
12 * @copyright 2001-2019 WoltLab GmbH
13 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
14 * @package WoltLabSuite\Core\Data\Menu\Item
17 class MenuItemNodeTree
20 * if `false`, individual menu item visibility will not be checked
23 public $checkVisibility;
35 public $menuItems = [];
41 public $menuItemStructure = [];
50 * number of visible items
53 protected $visibleItemCount = 0;
56 * Creates a new MenuItemNodeTree object.
58 * @param int $menuID menu id
59 * @param MenuItemList $menuItemList optional object to be provided when building the tree from cache
60 * @param bool $checkVisibility if `false`, individual menu item visibility will not be checked
62 public function __construct($menuID, ?MenuItemList
$menuItemList = null, $checkVisibility = true)
64 $this->menuID
= $menuID;
65 $this->checkVisibility
= $checkVisibility;
68 if ($menuItemList === null) {
69 $menuItemList = new MenuItemList();
70 $menuItemList->getConditionBuilder()->add('menu_item.menuID = ?', [$this->menuID
]);
71 $menuItemList->sqlOrderBy
= "menu_item.showOrder";
72 $menuItemList->readObjects();
75 // find possible active menu items
76 $activeMenuItems = [];
78 if (!RequestHandler
::getInstance()->isACPRequest()) {
79 $possibleLocations = PageLocationManager
::getInstance()->getLocations();
80 $length = \
count($possibleLocations);
81 for ($i = 0; $i < $length; $i++
) {
82 foreach ($menuItemList as $menuItem) {
83 if ($menuItem->pageID
== $possibleLocations[$i]['pageID'] && $menuItem->pageObjectID
== $possibleLocations[$i]['pageObjectID']) {
84 if (!isset($activeMenuItems[$i])) {
85 $activeMenuItems[$i] = [];
88 $activeMenuItems[$i][] = $menuItem->itemID
;
94 // build menu structure
95 foreach ($menuItemList as $menuItem) {
96 $this->menuItems
[$menuItem->itemID
] = $menuItem;
98 if (!isset($this->menuItemStructure
[$menuItem->parentItemID
])) {
99 $this->menuItemStructure
[$menuItem->parentItemID
] = [];
101 $this->menuItemStructure
[$menuItem->parentItemID
][] = $menuItem->itemID
;
104 // generate node tree
105 $this->node
= new MenuItemNode();
106 $this->node
->setChildren($this->generateNodeTree(null, $this->node
));
108 // mark nodes as active
109 if (!empty($activeMenuItems)) {
110 $nodeList = $this->getNodeList();
111 foreach ($activeMenuItems as $itemIDs) {
112 for ($i = 0, $length = \
count($itemIDs); $i < $length; $i++
) {
113 /** @var MenuItemNode $node */
114 foreach ($nodeList as $node) {
115 if ($node->itemID
== $itemIDs[$i]) {
116 $node->setIsActive();
118 // only one effective item can be marked as active, use the first
119 // occurrence with the highest priority and ignore everything else
129 * Generates the node tree recursively.
131 * @param int $parentID parent menu item id
132 * @param MenuItemNode $parentNode parent menu item object
133 * @return MenuItemNode[] nested menu item tree
135 protected function generateNodeTree($parentID = null, ?MenuItemNode
$parentNode = null)
139 $itemIDs = ($this->menuItemStructure
[$parentID] ??
[]);
140 foreach ($itemIDs as $itemID) {
141 $menuItem = $this->menuItems
[$itemID];
143 if ($this->checkVisibility
&& !$menuItem->isVisible()) {
147 $node = new MenuItemNode(
150 ($parentNode !== null ?
($parentNode->getDepth() +
1) : 0)
155 $node->setChildren($this->generateNodeTree($itemID, $node));
157 // increase item counter
158 $this->visibleItemCount++
;
165 * Returns the menu item node tree.
167 * @return MenuItemNode[]
169 public function getNodeTree()
171 return $this->node
->getChildren();
175 * Returns the iterable node list.
177 * @return \RecursiveIteratorIterator
179 public function getNodeList()
181 return new \
RecursiveIteratorIterator($this->node
, \RecursiveIteratorIterator
::SELF_FIRST
);
185 * Returns the number of visible items.
189 public function getVisibleItemCount()
191 return $this->visibleItemCount
;