PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 1.3.1
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v1.3.1
5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / core / Menu / MenuAbstract.php
matomo / app / core / Menu Last commit date
Group.php 6 years ago MenuAbstract.php 6 years ago MenuAdmin.php 6 years ago MenuTop.php 6 years ago
MenuAbstract.php
367 lines
1 <?php
2 /**
3 * Piwik - free/libre analytics platform
4 *
5 * @link https://matomo.org
6 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
7 *
8 */
9 namespace Piwik\Menu;
10
11 use Piwik\Container\StaticContainer;
12 use Piwik\Plugins\SitesManager\API;
13 use Piwik\Singleton;
14 use Piwik\Plugin\Manager as PluginManager;
15
16 /**
17 * Base class for classes that manage one of Piwik's menus.
18 *
19 * There are three menus in Piwik, the main menu, the top menu and the admin menu.
20 * Each menu has a class that manages the menu's content. Each class invokes
21 * a different event to allow plugins to add new menu items.
22 *
23 * @static \Piwik\Menu\MenuAbstract getInstance()
24 */
25 abstract class MenuAbstract extends Singleton
26 {
27
28 protected $menu = null;
29 protected $menuEntries = array();
30 protected $menuEntriesToRemove = array();
31 protected $edits = array();
32 protected $renames = array();
33 protected $orderingApplied = false;
34 protected $menuIcons = array();
35 protected static $menus = array();
36
37 /**
38 * Builds the menu, applies edits, renames
39 * and orders the entries.
40 *
41 * @return Array
42 */
43 public function getMenu()
44 {
45 $this->buildMenu();
46 $this->applyEdits();
47 $this->applyRemoves();
48 $this->applyRenames();
49 $this->applyOrdering();
50 return $this->menu;
51 }
52
53 /**
54 * lets you register a menu icon for a certain menu category to replace the default arrow icon.
55 *
56 * @param string $menuName The translation key of a main menu category, eg 'Dashboard_Dashboard'
57 * @param string $iconCssClass The css class name of an icon, eg 'icon-user'
58 */
59 public function registerMenuIcon($menuName, $iconCssClass)
60 {
61 $this->menuIcons[$menuName] = $iconCssClass;
62 }
63
64 /**
65 * Returns a list of available plugin menu instances.
66 *
67 * @return \Piwik\Plugin\Menu[]
68 */
69 protected function getAllMenus()
70 {
71 if (!empty(self::$menus)) {
72 return self::$menus;
73 }
74
75 $components = PluginManager::getInstance()->findComponents('Menu', 'Piwik\\Plugin\\Menu');
76
77 self::$menus = array();
78 foreach ($components as $component) {
79 self::$menus[] = StaticContainer::get($component);
80 }
81
82 return self::$menus;
83 }
84
85 /**
86 * To use only for tests.
87 *
88 * @deprecated The whole $menus cache should be replaced by a real transient cache
89 */
90 public static function clearMenus()
91 {
92 self::$menus = array();
93 }
94
95 /**
96 * Adds a new entry to the menu.
97 *
98 * @param string $menuName The menu's category name. Can be a translation token.
99 * @param string $subMenuName The menu item's name. Can be a translation token.
100 * @param string|array $url The URL the admin menu entry should link to, or an array of query parameters
101 * that can be used to build the URL.
102 * @param int $order The order hint.
103 * @param bool|string $tooltip An optional tooltip to display or false to display the tooltip.
104 * @param bool|string $icon An icon classname, such as "icon-add". Only supported by admin menu
105 * @param bool|string $onclick Will execute the on click handler instead of executing the link. Only supported by admin menu.
106 * @since 2.7.0
107 * @api
108 */
109 public function addItem($menuName, $subMenuName, $url, $order = 50, $tooltip = false, $icon = false, $onclick = false)
110 {
111 // make sure the idSite value used is numeric (hack-y fix for #3426)
112 if (isset($url['idSite']) && !is_numeric($url['idSite'])) {
113 $idSites = API::getInstance()->getSitesIdWithAtLeastViewAccess();
114 $url['idSite'] = reset($idSites);
115 }
116
117 $this->menuEntries[] = array(
118 $menuName,
119 $subMenuName,
120 $url,
121 $order,
122 $tooltip,
123 $icon,
124 $onclick
125 );
126 }
127
128 /**
129 * Removes an existing entry from the menu.
130 *
131 * @param string $menuName The menu's category name. Can be a translation token.
132 * @param bool|string $subMenuName The menu item's name. Can be a translation token.
133 * @api
134 */
135 public function remove($menuName, $subMenuName = false)
136 {
137 $this->menuEntriesToRemove[] = array(
138 $menuName,
139 $subMenuName
140 );
141 }
142
143 /**
144 * Builds a single menu item
145 *
146 * @param string $menuName
147 * @param string $subMenuName
148 * @param string $url
149 * @param int $order
150 * @param bool|string $tooltip Tooltip to display.
151 */
152 private function buildMenuItem($menuName, $subMenuName, $url, $order = 50, $tooltip = false, $icon = false, $onclick = false)
153 {
154 if (!isset($this->menu[$menuName])) {
155 $this->menu[$menuName] = array(
156 '_hasSubmenu' => false,
157 '_order' => $order
158 );
159 }
160
161 if (empty($subMenuName)) {
162 $this->menu[$menuName]['_url'] = $url;
163 $this->menu[$menuName]['_order'] = $order;
164 $this->menu[$menuName]['_name'] = $menuName;
165 $this->menu[$menuName]['_tooltip'] = $tooltip;
166 if (!empty($this->menuIcons[$menuName])) {
167 $this->menu[$menuName]['_icon'] = $this->menuIcons[$menuName];
168 } else {
169 $this->menu[$menuName]['_icon'] = '';
170 }
171 }
172 if (!empty($subMenuName)) {
173 $this->menu[$menuName][$subMenuName]['_url'] = $url;
174 $this->menu[$menuName][$subMenuName]['_order'] = $order;
175 $this->menu[$menuName][$subMenuName]['_name'] = $subMenuName;
176 $this->menu[$menuName][$subMenuName]['_tooltip'] = $tooltip;
177 $this->menu[$menuName][$subMenuName]['_icon'] = $icon;
178 $this->menu[$menuName][$subMenuName]['_onclick'] = $onclick;
179 $this->menu[$menuName]['_hasSubmenu'] = true;
180
181 if (!array_key_exists('_tooltip', $this->menu[$menuName])) {
182 $this->menu[$menuName]['_tooltip'] = $tooltip;
183 }
184 }
185 }
186
187 /**
188 * Builds the menu from the $this->menuEntries variable.
189 */
190 private function buildMenu()
191 {
192 foreach ($this->menuEntries as $menuEntry) {
193 $this->buildMenuItem($menuEntry[0], $menuEntry[1], $menuEntry[2], $menuEntry[3], $menuEntry[4], $menuEntry[5], $menuEntry[6]);
194 }
195 }
196
197 /**
198 * Renames a single menu entry.
199 *
200 * @param $mainMenuOriginal
201 * @param $subMenuOriginal
202 * @param $mainMenuRenamed
203 * @param $subMenuRenamed
204 * @api
205 */
206 public function rename($mainMenuOriginal, $subMenuOriginal, $mainMenuRenamed, $subMenuRenamed)
207 {
208 $this->renames[] = array($mainMenuOriginal, $subMenuOriginal,
209 $mainMenuRenamed, $subMenuRenamed);
210 }
211
212 /**
213 * Edits a URL of an existing menu entry.
214 *
215 * @param $mainMenuToEdit
216 * @param $subMenuToEdit
217 * @param $newUrl
218 * @api
219 */
220 public function editUrl($mainMenuToEdit, $subMenuToEdit, $newUrl)
221 {
222 $this->edits[] = array($mainMenuToEdit, $subMenuToEdit, $newUrl);
223 }
224
225 /**
226 * Applies all edits to the menu.
227 */
228 private function applyEdits()
229 {
230 foreach ($this->edits as $edit) {
231 $mainMenuToEdit = $edit[0];
232 $subMenuToEdit = $edit[1];
233 $newUrl = $edit[2];
234
235 if ($subMenuToEdit === null) {
236 if (isset($this->menu[$mainMenuToEdit])) {
237 $menuDataToEdit = &$this->menu[$mainMenuToEdit];
238 } else {
239 $menuDataToEdit = null;
240 }
241 } else {
242 if (isset($this->menu[$mainMenuToEdit][$subMenuToEdit])) {
243 $menuDataToEdit = &$this->menu[$mainMenuToEdit][$subMenuToEdit];
244 } else {
245 $menuDataToEdit = null;
246 }
247 }
248
249 if (empty($menuDataToEdit)) {
250 $this->buildMenuItem($mainMenuToEdit, $subMenuToEdit, $newUrl);
251 } else {
252 $menuDataToEdit['_url'] = $newUrl;
253 }
254 }
255 }
256
257 private function applyRemoves()
258 {
259 foreach ($this->menuEntriesToRemove as $menuToDelete) {
260 if (empty($menuToDelete[1])) {
261 // Delete Main Menu
262 if (isset($this->menu[$menuToDelete[0]])) {
263 unset($this->menu[$menuToDelete[0]]);
264 }
265 } else {
266 // Delete Sub Menu
267 if (isset($this->menu[$menuToDelete[0]][$menuToDelete[1]])) {
268 unset($this->menu[$menuToDelete[0]][$menuToDelete[1]]);
269 }
270 }
271 }
272 }
273 /**
274 * Applies renames to the menu.
275 */
276 private function applyRenames()
277 {
278 foreach ($this->renames as $rename) {
279 $mainMenuOriginal = $rename[0];
280 $subMenuOriginal = $rename[1];
281 $mainMenuRenamed = $rename[2];
282 $subMenuRenamed = $rename[3];
283
284 // Are we changing a submenu?
285 if (!empty($subMenuOriginal)) {
286 if (isset($this->menu[$mainMenuOriginal][$subMenuOriginal])) {
287 $save = $this->menu[$mainMenuOriginal][$subMenuOriginal];
288 $save['_name'] = $subMenuRenamed;
289 unset($this->menu[$mainMenuOriginal][$subMenuOriginal]);
290 $this->menu[$mainMenuRenamed][$subMenuRenamed] = $save;
291 }
292 } // Changing a first-level element
293 elseif (isset($this->menu[$mainMenuOriginal])) {
294 $save = $this->menu[$mainMenuOriginal];
295 $save['_name'] = $mainMenuRenamed;
296 unset($this->menu[$mainMenuOriginal]);
297 $this->menu[$mainMenuRenamed] = $save;
298 }
299 }
300 }
301
302 /**
303 * Orders the menu according to their order.
304 */
305 private function applyOrdering()
306 {
307 if (empty($this->menu)
308 || $this->orderingApplied
309 ) {
310 return;
311 }
312
313 uasort($this->menu, array($this, 'menuCompare'));
314 foreach ($this->menu as $key => &$element) {
315 if (is_null($element)) {
316 unset($this->menu[$key]);
317 } elseif ($element['_hasSubmenu']) {
318 uasort($element, array($this, 'menuCompare'));
319 }
320 }
321
322 $this->orderingApplied = true;
323 }
324
325 /**
326 * Compares two menu entries. Used for ordering.
327 *
328 * @param array $itemOne
329 * @param array $itemTwo
330 * @return boolean
331 */
332 protected function menuCompare($itemOne, $itemTwo)
333 {
334 if (!is_array($itemOne) && !is_array($itemTwo)) {
335 return 0;
336 }
337
338 if (!is_array($itemOne) && is_array($itemTwo)) {
339 return -1;
340 }
341
342 if (is_array($itemOne) && !is_array($itemTwo)) {
343 return 1;
344 }
345
346 if (!isset($itemOne['_order']) && !isset($itemTwo['_order'])) {
347 return 0;
348 }
349
350 if (!isset($itemOne['_order']) && isset($itemTwo['_order'])) {
351 return -1;
352 }
353
354 if (isset($itemOne['_order']) && !isset($itemTwo['_order'])) {
355 return 1;
356 }
357
358 if ($itemOne['_order'] == $itemTwo['_order']) {
359 return strcmp(
360 @$itemOne['_name'],
361 @$itemTwo['_name']);
362 }
363
364 return ($itemOne['_order'] < $itemTwo['_order']) ? -1 : 1;
365 }
366 }
367