[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * @package Joomla.Administrator 5 * @subpackage mod_menu 6 * 7 * @copyright (C) 2006 Open Source Matters, Inc. <https://www.joomla.org> 8 * @license GNU General Public License version 2 or later; see LICENSE.txt 9 */ 10 11 namespace Joomla\Module\Menu\Administrator\Menu; 12 13 use Joomla\CMS\Application\CMSApplication; 14 use Joomla\CMS\Component\ComponentHelper; 15 use Joomla\CMS\Language\Associations; 16 use Joomla\CMS\Language\Text; 17 use Joomla\CMS\Menu\AdministratorMenuItem; 18 use Joomla\CMS\Table\Table; 19 use Joomla\CMS\Uri\Uri; 20 use Joomla\Component\Menus\Administrator\Helper\MenusHelper; 21 use Joomla\Registry\Registry; 22 use Joomla\Utilities\ArrayHelper; 23 24 // phpcs:disable PSR1.Files.SideEffects 25 \defined('_JEXEC') or die; 26 // phpcs:enable PSR1.Files.SideEffects 27 28 /** 29 * Tree based class to render the admin menu 30 * 31 * @since 1.5 32 */ 33 class CssMenu 34 { 35 /** 36 * The root of the menu 37 * 38 * @var AdministratorMenuItem 39 * 40 * @since 4.0.0 41 */ 42 protected $root; 43 44 /** 45 * An array of AdministratorMenuItem nodes 46 * 47 * @var AdministratorMenuItem[] 48 * 49 * @since 4.0.0 50 */ 51 protected $nodes = []; 52 53 /** 54 * The module options 55 * 56 * @var Registry 57 * 58 * @since 3.8.0 59 */ 60 protected $params; 61 62 /** 63 * The menu bar state 64 * 65 * @var boolean 66 * 67 * @since 3.8.0 68 */ 69 protected $enabled; 70 71 /** 72 * The application 73 * 74 * @var boolean 75 * 76 * @since 4.0.0 77 */ 78 protected $application; 79 80 /** 81 * A counter for unique IDs 82 * 83 * @var integer 84 * 85 * @since 4.0.0 86 */ 87 protected $counter = 0; 88 89 /** 90 * CssMenu constructor. 91 * 92 * @param CMSApplication $application The application 93 * 94 * @since 4.0.0 95 */ 96 public function __construct(CMSApplication $application) 97 { 98 $this->application = $application; 99 $this->root = new AdministratorMenuItem(); 100 } 101 102 /** 103 * Populate the menu items in the menu tree object 104 * 105 * @param Registry $params Menu configuration parameters 106 * @param bool $enabled Whether the menu should be enabled or disabled 107 * 108 * @return AdministratorMenuItem Root node of the menu tree 109 * 110 * @since 3.7.0 111 */ 112 public function load($params, $enabled) 113 { 114 $this->params = $params; 115 $this->enabled = $enabled; 116 $menutype = $this->params->get('menutype', '*'); 117 118 if ($menutype === '*') { 119 $name = $this->params->get('preset', 'default'); 120 $this->root = MenusHelper::loadPreset($name); 121 } else { 122 $this->root = MenusHelper::getMenuItems($menutype, true); 123 124 // Can we access everything important with this menu? Create a recovery menu! 125 if ( 126 $this->enabled 127 && $this->params->get('check', 1) 128 && $this->check($this->root, $this->params) 129 ) { 130 $this->params->set('recovery', true); 131 132 // In recovery mode, load the preset inside a special root node. 133 $this->root = new AdministratorMenuItem(['level' => 0]); 134 $heading = new AdministratorMenuItem(['title' => 'MOD_MENU_RECOVERY_MENU_ROOT', 'type' => 'heading']); 135 $this->root->addChild($heading); 136 137 MenusHelper::loadPreset('default', true, $heading); 138 139 $this->preprocess($this->root); 140 141 $this->root->addChild(new AdministratorMenuItem(['type' => 'separator'])); 142 143 // Add link to exit recovery mode 144 $uri = clone Uri::getInstance(); 145 $uri->setVar('recover_menu', 0); 146 147 $this->root->addChild(new AdministratorMenuItem(['title' => 'MOD_MENU_RECOVERY_EXIT', 'type' => 'url', 'link' => $uri->toString()])); 148 149 return $this->root; 150 } 151 } 152 153 $this->preprocess($this->root); 154 155 return $this->root; 156 } 157 158 /** 159 * Method to render a given level of a menu using provided layout file 160 * 161 * @param string $layoutFile The layout file to be used to render 162 * @param AdministratorMenuItem $node Node to render the children of 163 * 164 * @return void 165 * 166 * @since 3.8.0 167 */ 168 public function renderSubmenu($layoutFile, $node) 169 { 170 if (is_file($layoutFile)) { 171 $children = $node->getChildren(); 172 173 foreach ($children as $current) { 174 $current->level = $node->level + 1; 175 176 // This sets the scope to this object for the layout file and also isolates other `include`s 177 require $layoutFile; 178 } 179 } 180 } 181 182 /** 183 * Check the flat list of menu items for important links 184 * 185 * @param AdministratorMenuItem $node The menu items array 186 * @param Registry $params Module options 187 * 188 * @return boolean Whether to show recovery menu 189 * 190 * @since 3.8.0 191 */ 192 protected function check($node, Registry $params) 193 { 194 $me = $this->application->getIdentity(); 195 $authMenus = $me->authorise('core.manage', 'com_menus'); 196 $authModules = $me->authorise('core.manage', 'com_modules'); 197 198 if (!$authMenus && !$authModules) { 199 return false; 200 } 201 202 $items = $node->getChildren(true); 203 $types = array_column($items, 'type'); 204 $elements = array_column($items, 'element'); 205 $rMenu = $authMenus && !\in_array('com_menus', $elements); 206 $rModule = $authModules && !\in_array('com_modules', $elements); 207 $rContainer = !\in_array('container', $types); 208 209 if ($rMenu || $rModule || $rContainer) { 210 $recovery = $this->application->getUserStateFromRequest('mod_menu.recovery', 'recover_menu', 0, 'int'); 211 212 if ($recovery) { 213 return true; 214 } 215 216 $missing = array(); 217 218 if ($rMenu) { 219 $missing[] = Text::_('MOD_MENU_IMPORTANT_ITEM_MENU_MANAGER'); 220 } 221 222 if ($rModule) { 223 $missing[] = Text::_('MOD_MENU_IMPORTANT_ITEM_MODULE_MANAGER'); 224 } 225 226 if ($rContainer) { 227 $missing[] = Text::_('MOD_MENU_IMPORTANT_ITEM_COMPONENTS_CONTAINER'); 228 } 229 230 $uri = clone Uri::getInstance(); 231 $uri->setVar('recover_menu', 1); 232 233 $table = Table::getInstance('MenuType'); 234 $menutype = $params->get('menutype'); 235 236 $table->load(array('menutype' => $menutype)); 237 238 $menutype = $table->get('title', $menutype); 239 $message = Text::sprintf('MOD_MENU_IMPORTANT_ITEMS_INACCESSIBLE_LIST_WARNING', $menutype, implode(', ', $missing), $uri); 240 241 $this->application->enqueueMessage($message, 'warning'); 242 } 243 244 return false; 245 } 246 247 /** 248 * Filter and perform other preparatory tasks for loaded menu items based on access rights and module configurations for display 249 * 250 * @param AdministratorMenuItem $parent A menu item to process 251 * 252 * @return array 253 * 254 * @since 3.8.0 255 */ 256 protected function preprocess($parent) 257 { 258 $user = $this->application->getIdentity(); 259 $language = $this->application->getLanguage(); 260 261 $noSeparator = true; 262 $children = $parent->getChildren(); 263 264 /** 265 * Trigger onPreprocessMenuItems for the current level of backend menu items. 266 * $children is an array of AdministratorMenuItem objects. A plugin can traverse the whole tree, 267 * but new nodes will only be run through this method if their parents have not been processed yet. 268 */ 269 $this->application->triggerEvent('onPreprocessMenuItems', array('com_menus.administrator.module', $children, $this->params, $this->enabled)); 270 271 foreach ($children as $item) { 272 $itemParams = $item->getParams(); 273 274 // Exclude item with menu item option set to exclude from menu modules 275 if ($itemParams->get('menu_show', 1) == 0) { 276 $parent->removeChild($item); 277 continue; 278 } 279 280 $item->scope = $item->scope ?? 'default'; 281 $item->icon = $item->icon ?? ''; 282 283 // Whether this scope can be displayed. Applies only to preset items. Db driven items should use un/published state. 284 if (($item->scope === 'help' && $this->params->get('showhelp', 1) == 0) || ($item->scope === 'edit' && !$this->params->get('shownew', 1))) { 285 $parent->removeChild($item); 286 continue; 287 } 288 289 if (substr($item->link, 0, 8) === 'special:') { 290 $special = substr($item->link, 8); 291 292 if ($special === 'language-forum') { 293 $item->link = 'index.php?option=com_admin&view=help&layout=langforum'; 294 } elseif ($special === 'custom-forum') { 295 $item->link = $this->params->get('forum_url'); 296 } 297 } 298 299 $uri = new Uri($item->link); 300 $query = $uri->getQuery(true); 301 302 /** 303 * If component is passed in the link via option variable, we set $item->element to this value for further 304 * processing. It is needed for links from menu items of third party extensions link to Joomla! core 305 * components like com_categories, com_fields... 306 */ 307 if ($option = $uri->getVar('option')) { 308 $item->element = $option; 309 } 310 311 // Exclude item if is not enabled 312 if ($item->element && !ComponentHelper::isEnabled($item->element)) { 313 $parent->removeChild($item); 314 continue; 315 } 316 317 /* 318 * Multilingual Associations if the site is not set as multilingual and/or Associations is not enabled in 319 * the Language Filter plugin 320 */ 321 322 if ($item->element === 'com_associations' && !Associations::isEnabled()) { 323 $parent->removeChild($item); 324 continue; 325 } 326 327 // Exclude Mass Mail if disabled in global configuration 328 if ($item->scope === 'massmail' && ($this->application->get('mailonline', 1) == 0 || $this->application->get('massmailoff', 0) == 1)) { 329 $parent->removeChild($item); 330 continue; 331 } 332 333 // Exclude item if the component is not authorised 334 $assetName = $item->element; 335 336 if ($item->element === 'com_categories') { 337 $assetName = $query['extension'] ?? 'com_content'; 338 } elseif ($item->element === 'com_fields') { 339 // Only display Fields menus when enabled in the component 340 $createFields = null; 341 342 if (isset($query['context'])) { 343 $createFields = ComponentHelper::getParams(strstr($query['context'], '.', true))->get('custom_fields_enable', 1); 344 } 345 346 if (!$createFields) { 347 $parent->removeChild($item); 348 continue; 349 } 350 351 list($assetName) = isset($query['context']) ? explode('.', $query['context'], 2) : array('com_fields'); 352 } elseif ($item->element === 'com_cpanel' && $item->link === 'index.php') { 353 continue; 354 } elseif ( 355 $item->link === 'index.php?option=com_cpanel&view=help' 356 || $item->link === 'index.php?option=com_cpanel&view=cpanel&dashboard=help' 357 ) { 358 if ($this->params->get('showhelp', 1)) { 359 continue; 360 } 361 362 // Exclude help menu item if set such in mod_menu 363 $parent->removeChild($item); 364 continue; 365 } elseif ($item->element === 'com_workflow') { 366 // Only display Workflow menus when enabled in the component 367 $workflow = null; 368 369 if (isset($query['extension'])) { 370 $parts = explode('.', $query['extension']); 371 372 $workflow = ComponentHelper::getParams($parts[0])->get('workflow_enabled') && $user->authorise('core.manage.workflow', $parts[0]); 373 } 374 375 if (!$workflow) { 376 $parent->removeChild($item); 377 continue; 378 } 379 380 list($assetName) = isset($query['extension']) ? explode('.', $query['extension'], 2) : array('com_workflow'); 381 } elseif (\in_array($item->element, array('com_config', 'com_privacy', 'com_actionlogs'), true) && !$user->authorise('core.admin')) { 382 // Special case for components which only allow super user access 383 $parent->removeChild($item); 384 continue; 385 } elseif ($item->element === 'com_joomlaupdate' && !$user->authorise('core.admin')) { 386 $parent->removeChild($item); 387 continue; 388 } elseif ( 389 ($item->link === 'index.php?option=com_installer&view=install' || $item->link === 'index.php?option=com_installer&view=languages') 390 && !$user->authorise('core.admin') 391 ) { 392 continue; 393 } elseif ($item->element === 'com_admin') { 394 if (isset($query['view']) && $query['view'] === 'sysinfo' && !$user->authorise('core.admin')) { 395 $parent->removeChild($item); 396 continue; 397 } 398 } elseif ($item->link === 'index.php?option=com_messages&view=messages' && !$user->authorise('core.manage', 'com_users')) { 399 $parent->removeChild($item); 400 continue; 401 } 402 403 if ($assetName && !$user->authorise(($item->scope === 'edit') ? 'core.create' : 'core.manage', $assetName)) { 404 $parent->removeChild($item); 405 continue; 406 } 407 408 // Exclude if link is invalid 409 if (is_null($item->link) || !\in_array($item->type, array('separator', 'heading', 'container')) && trim($item->link) === '') { 410 $parent->removeChild($item); 411 continue; 412 } 413 414 // Process any children if exists 415 if ($item->hasChildren()) { 416 $this->preprocess($item); 417 } 418 419 // Populate automatic children for container items 420 if ($item->type === 'container') { 421 $exclude = (array) $itemParams->get('hideitems') ?: array(); 422 $components = MenusHelper::getMenuItems('main', false, $exclude); 423 424 // We are adding the nodes first to preprocess them, then sort them and add them again. 425 foreach ($components->getChildren() as $c) { 426 $item->addChild($c); 427 } 428 429 $this->preprocess($item); 430 $children = ArrayHelper::sortObjects($item->getChildren(), 'text', 1, false, true); 431 432 foreach ($children as $c) { 433 $item->addChild($c); 434 } 435 } 436 437 // Exclude if there are no child items under heading or container 438 if (\in_array($item->type, array('heading', 'container')) && !$item->hasChildren() && empty($item->components)) { 439 $parent->removeChild($item); 440 continue; 441 } 442 443 // Remove repeated and edge positioned separators, It is important to put this check at the end of any logical filtering. 444 if ($item->type === 'separator') { 445 if ($noSeparator) { 446 $parent->removeChild($item); 447 continue; 448 } 449 450 $noSeparator = true; 451 } else { 452 $noSeparator = false; 453 } 454 455 // Ok we passed everything, load language at last only 456 if ($item->element) { 457 $language->load($item->element . '.sys', JPATH_ADMINISTRATOR) || 458 $language->load($item->element . '.sys', JPATH_ADMINISTRATOR . '/components/' . $item->element); 459 } 460 461 if ($item->type === 'separator' && $itemParams->get('text_separator') == 0) { 462 $item->title = ''; 463 } 464 465 $item->text = Text::_($item->title); 466 } 467 468 // If last one was a separator remove it too. 469 $last = end($parent->getChildren()); 470 471 if ($last && $last->type === 'separator' && $last->getSibling(false) && $last->getSibling(false)->type === 'separator') { 472 $parent->removeChild($last); 473 } 474 } 475 476 /** 477 * Method to get the CSS class name for an icon identifier or create one if 478 * a custom image path is passed as the identifier 479 * 480 * @param AdministratorMenuItem $node Node to get icon data from 481 * 482 * @return string CSS class name 483 * 484 * @since 3.8.0 485 */ 486 public function getIconClass($node) 487 { 488 $identifier = $node->class; 489 490 // Top level is special 491 if (trim($identifier) == '') { 492 return null; 493 } 494 495 // We were passed a class name 496 if (substr($identifier, 0, 6) == 'class:') { 497 $class = substr($identifier, 6); 498 } else { 499 // We were passed background icon url. Build the CSS class for the icon 500 if ($identifier == null) { 501 return null; 502 } 503 504 $class = preg_replace('#\.[^.]*$#', '', basename($identifier)); 505 $class = preg_replace('#\.\.[^A-Za-z0-9\.\_\- ]#', '', $class); 506 } 507 508 $html = 'icon-' . $class . ' icon-fw'; 509 510 return $html; 511 } 512 513 /** 514 * Create unique identifier 515 * 516 * @return string 517 * 518 * @since 4.0.0 519 */ 520 public function getCounter() 521 { 522 $this->counter++; 523 524 return $this->counter; 525 } 526 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |