[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/administrator/components/com_menus/src/Model/ -> MenusModel.php (source)

   1  <?php
   2  
   3  /**
   4   * @package     Joomla.Administrator
   5   * @subpackage  com_menus
   6   *
   7   * @copyright   (C) 2009 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\Component\Menus\Administrator\Model;
  12  
  13  use Joomla\CMS\Helper\ModuleHelper;
  14  use Joomla\CMS\Language\LanguageHelper;
  15  use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
  16  use Joomla\CMS\MVC\Model\ListModel;
  17  use Joomla\Database\ParameterType;
  18  
  19  // phpcs:disable PSR1.Files.SideEffects
  20  \defined('_JEXEC') or die;
  21  // phpcs:enable PSR1.Files.SideEffects
  22  
  23  /**
  24   * Menu List Model for Menus.
  25   *
  26   * @since  1.6
  27   */
  28  class MenusModel extends ListModel
  29  {
  30      /**
  31       * Constructor.
  32       *
  33       * @param   array                $config   An optional associative array of configuration settings.
  34       * @param   MVCFactoryInterface  $factory  The factory.
  35       *
  36       * @see     \Joomla\CMS\MVC\Model\BaseDatabaseModel
  37       * @since   3.2
  38       */
  39      public function __construct($config = array(), MVCFactoryInterface $factory = null)
  40      {
  41          if (empty($config['filter_fields'])) {
  42              $config['filter_fields'] = array(
  43                  'id', 'a.id',
  44                  'title', 'a.title',
  45                  'menutype', 'a.menutype',
  46                  'client_id', 'a.client_id',
  47              );
  48          }
  49  
  50          parent::__construct($config, $factory);
  51      }
  52  
  53      /**
  54       * Overrides the getItems method to attach additional metrics to the list.
  55       *
  56       * @return  mixed  An array of data items on success, false on failure.
  57       *
  58       * @since   1.6.1
  59       */
  60      public function getItems()
  61      {
  62          // Get a storage key.
  63          $store = $this->getStoreId('getItems');
  64  
  65          // Try to load the data from internal storage.
  66          if (!empty($this->cache[$store])) {
  67              return $this->cache[$store];
  68          }
  69  
  70          // Load the list items.
  71          $items = parent::getItems();
  72  
  73          // If empty or an error, just return.
  74          if (empty($items)) {
  75              return array();
  76          }
  77  
  78          // Getting the following metric by joins is WAY TOO SLOW.
  79          // Faster to do three queries for very large menu trees.
  80  
  81          // Get the menu types of menus in the list.
  82          $db = $this->getDatabase();
  83          $menuTypes = array_column((array) $items, 'menutype');
  84  
  85          $query = $db->getQuery(true)
  86              ->select(
  87                  [
  88                      $db->quoteName('m.menutype'),
  89                      'COUNT(DISTINCT ' . $db->quoteName('m.id') . ') AS ' . $db->quoteName('count_published'),
  90                  ]
  91              )
  92              ->from($db->quoteName('#__menu', 'm'))
  93              ->where($db->quoteName('m.published') . ' = :published')
  94              ->whereIn($db->quoteName('m.menutype'), $menuTypes, ParameterType::STRING)
  95              ->group($db->quoteName('m.menutype'))
  96              ->bind(':published', $published, ParameterType::INTEGER);
  97  
  98          $db->setQuery($query);
  99  
 100          // Get the published menu counts.
 101          try {
 102              $published      = 1;
 103              $countPublished = $db->loadAssocList('menutype', 'count_published');
 104          } catch (\RuntimeException $e) {
 105              $this->setError($e->getMessage());
 106  
 107              return false;
 108          }
 109  
 110          // Get the unpublished menu counts.
 111          try {
 112              $published        = 0;
 113              $countUnpublished = $db->loadAssocList('menutype', 'count_published');
 114          } catch (\RuntimeException $e) {
 115              $this->setError($e->getMessage());
 116  
 117              return false;
 118          }
 119  
 120          // Get the trashed menu counts.
 121          try {
 122              $published    = -2;
 123              $countTrashed = $db->loadAssocList('menutype', 'count_published');
 124          } catch (\RuntimeException $e) {
 125              $this->setError($e->getMessage());
 126  
 127              return false;
 128          }
 129  
 130          // Inject the values back into the array.
 131          foreach ($items as $item) {
 132              $item->count_published   = $countPublished[$item->menutype] ?? 0;
 133              $item->count_unpublished = $countUnpublished[$item->menutype] ?? 0;
 134              $item->count_trashed     = $countTrashed[$item->menutype] ?? 0;
 135          }
 136  
 137          // Add the items to the internal cache.
 138          $this->cache[$store] = $items;
 139  
 140          return $this->cache[$store];
 141      }
 142  
 143      /**
 144       * Method to build an SQL query to load the list data.
 145       *
 146       * @return  string  An SQL query
 147       *
 148       * @since   1.6
 149       */
 150      protected function getListQuery()
 151      {
 152          // Create a new query object.
 153          $db       = $this->getDatabase();
 154          $query    = $db->getQuery(true);
 155          $clientId = (int) $this->getState('client_id');
 156  
 157          // Select all fields from the table.
 158          $query->select(
 159              $this->getState(
 160                  'list.select',
 161                  [
 162                      $db->quoteName('a.id'),
 163                      $db->quoteName('a.menutype'),
 164                      $db->quoteName('a.title'),
 165                      $db->quoteName('a.description'),
 166                      $db->quoteName('a.client_id'),
 167                  ]
 168              )
 169          )
 170              ->from($db->quoteName('#__menu_types', 'a'))
 171              ->where(
 172                  [
 173                      $db->quoteName('a.id') . ' > 0',
 174                      $db->quoteName('a.client_id') . ' = :clientId',
 175                  ]
 176              )
 177              ->bind(':clientId', $clientId, ParameterType::INTEGER);
 178  
 179          // Filter by search in title or menutype
 180          if ($search = trim($this->getState('filter.search', ''))) {
 181              $search = '%' . str_replace(' ', '%', $search) . '%';
 182              $query->extendWhere(
 183                  'AND',
 184                  [
 185                      $db->quoteName('a.title') . ' LIKE :search1' ,
 186                      $db->quoteName('a.menutype') . ' LIKE :search2',
 187                  ],
 188                  'OR'
 189              )
 190                  ->bind([':search1', ':search2'], $search);
 191          }
 192  
 193          // Add the list ordering clause.
 194          $query->order($db->escape($this->getState('list.ordering', 'a.id')) . ' ' . $db->escape($this->getState('list.direction', 'ASC')));
 195  
 196          return $query;
 197      }
 198  
 199      /**
 200       * Method to auto-populate the model state.
 201       *
 202       * Note. Calling getState in this method will result in recursion.
 203       *
 204       * @param   string  $ordering   An optional ordering field.
 205       * @param   string  $direction  An optional direction (asc|desc).
 206       *
 207       * @return  void
 208       *
 209       * @since   1.6
 210       */
 211      protected function populateState($ordering = 'a.title', $direction = 'asc')
 212      {
 213          $search   = $this->getUserStateFromRequest($this->context . '.search', 'filter_search');
 214          $this->setState('filter.search', $search);
 215  
 216          $clientId = (int) $this->getUserStateFromRequest($this->context . '.client_id', 'client_id', 0, 'int');
 217          $this->setState('client_id', $clientId);
 218  
 219          // List state information.
 220          parent::populateState($ordering, $direction);
 221      }
 222  
 223      /**
 224       * Gets the extension id of the core mod_menu module.
 225       *
 226       * @return  integer
 227       *
 228       * @since   2.5
 229       */
 230      public function getModMenuId()
 231      {
 232          $clientId = (int) $this->getState('client_id');
 233          $db       = $this->getDatabase();
 234          $query    = $db->getQuery(true)
 235              ->select($db->quoteName('e.extension_id'))
 236              ->from($db->quoteName('#__extensions', 'e'))
 237              ->where(
 238                  [
 239                      $db->quoteName('e.type') . ' = ' . $db->quote('module'),
 240                      $db->quoteName('e.element') . ' = ' . $db->quote('mod_menu'),
 241                      $db->quoteName('e.client_id') . ' = :clientId',
 242                  ]
 243              )
 244              ->bind(':clientId', $clientId, ParameterType::INTEGER);
 245          $db->setQuery($query);
 246  
 247          return $db->loadResult();
 248      }
 249  
 250      /**
 251       * Gets a list of all mod_mainmenu modules and collates them by menutype
 252       *
 253       * @return  array
 254       *
 255       * @since   1.6
 256       */
 257      public function &getModules()
 258      {
 259          $model = $this->bootComponent('com_menus')
 260              ->getMVCFactory()->createModel('Menu', 'Administrator', ['ignore_request' => true]);
 261          $result = $model->getModules();
 262  
 263          return $result;
 264      }
 265  
 266      /**
 267       * Returns the missing module languages.
 268       *
 269       * @return  array
 270       *
 271       * @since   _DEPLOY_VERSION__
 272       */
 273      public function getMissingModuleLanguages(): array
 274      {
 275          // Check custom administrator menu modules
 276          if (!ModuleHelper::isAdminMultilang()) {
 277              return [];
 278          }
 279  
 280          $languages = LanguageHelper::getInstalledLanguages(1, true);
 281          $langCodes = [];
 282  
 283          foreach ($languages as $language) {
 284              if (isset($language->metadata['nativeName'])) {
 285                  $languageName = $language->metadata['nativeName'];
 286              } else {
 287                  $languageName = $language->metadata['name'];
 288              }
 289  
 290              $langCodes[$language->metadata['tag']] = $languageName;
 291          }
 292  
 293          $db    = $this->getDatabase();
 294          $query = $db->getQuery(true);
 295  
 296          $query->select($db->quoteName('m.language'))
 297              ->from($db->quoteName('#__modules', 'm'))
 298              ->where(
 299                  [
 300                      $db->quoteName('m.module') . ' = ' . $db->quote('mod_menu'),
 301                      $db->quoteName('m.published') . ' = 1',
 302                      $db->quoteName('m.client_id') . ' = 1',
 303                  ]
 304              )
 305              ->group($db->quoteName('m.language'));
 306  
 307          $mLanguages = $db->setQuery($query)->loadColumn();
 308  
 309          // Check if we have a mod_menu module set to All languages or a mod_menu module for each admin language.
 310          if (!in_array('*', $mLanguages) && count($langMissing = array_diff(array_keys($langCodes), $mLanguages))) {
 311              return array_intersect_key($langCodes, array_flip($langMissing));
 312          }
 313  
 314          return [];
 315      }
 316  }


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