[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/administrator/modules/mod_menu/src/Menu/ -> CssMenu.php (source)

   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&amp;view=help&amp;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  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer