[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/src/Categories/ -> Categories.php (source)

   1  <?php
   2  
   3  /**
   4   * Joomla! Content Management System
   5   *
   6   * @copyright  (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
   7   * @license    GNU General Public License version 2 or later; see LICENSE.txt
   8   */
   9  
  10  namespace Joomla\CMS\Categories;
  11  
  12  use Joomla\CMS\Factory;
  13  use Joomla\CMS\Language\Multilanguage;
  14  use Joomla\Database\DatabaseAwareInterface;
  15  use Joomla\Database\DatabaseAwareTrait;
  16  use Joomla\Database\DatabaseInterface;
  17  use Joomla\Database\Exception\DatabaseNotFoundException;
  18  use Joomla\Database\ParameterType;
  19  
  20  // phpcs:disable PSR1.Files.SideEffects
  21  \defined('JPATH_PLATFORM') or die;
  22  // phpcs:enable PSR1.Files.SideEffects
  23  
  24  /**
  25   * Categories Class.
  26   *
  27   * @since  1.6
  28   */
  29  class Categories implements CategoryInterface, DatabaseAwareInterface
  30  {
  31      use DatabaseAwareTrait;
  32  
  33      /**
  34       * Array to hold the object instances
  35       *
  36       * @var    Categories[]
  37       * @since  1.6
  38       */
  39      public static $instances = array();
  40  
  41      /**
  42       * Array of category nodes
  43       *
  44       * @var    CategoryNode[]
  45       * @since  1.6
  46       */
  47      protected $_nodes;
  48  
  49      /**
  50       * Array of checked categories -- used to save values when _nodes are null
  51       *
  52       * @var    boolean[]
  53       * @since  1.6
  54       */
  55      protected $_checkedCategories;
  56  
  57      /**
  58       * Name of the extension the categories belong to
  59       *
  60       * @var    string
  61       * @since  1.6
  62       */
  63      protected $_extension = null;
  64  
  65      /**
  66       * Name of the linked content table to get category content count
  67       *
  68       * @var    string
  69       * @since  1.6
  70       */
  71      protected $_table = null;
  72  
  73      /**
  74       * Name of the category field
  75       *
  76       * @var    string
  77       * @since  1.6
  78       */
  79      protected $_field = null;
  80  
  81      /**
  82       * Name of the key field
  83       *
  84       * @var    string
  85       * @since  1.6
  86       */
  87      protected $_key = null;
  88  
  89      /**
  90       * Name of the items state field
  91       *
  92       * @var    string
  93       * @since  1.6
  94       */
  95      protected $_statefield = null;
  96  
  97      /**
  98       * Array of options
  99       *
 100       * @var    array
 101       * @since  1.6
 102       */
 103      protected $_options = [];
 104  
 105      /**
 106       * Class constructor
 107       *
 108       * @param   array  $options  Array of options
 109       *
 110       * @since   1.6
 111       */
 112      public function __construct($options)
 113      {
 114          $this->_extension  = $options['extension'];
 115          $this->_table      = $options['table'];
 116          $this->_field      = isset($options['field']) && $options['field'] ? $options['field'] : 'catid';
 117          $this->_key        = isset($options['key']) && $options['key'] ? $options['key'] : 'id';
 118          $this->_statefield = isset($options['statefield']) ? $options['statefield'] : 'state';
 119  
 120          $options['access']      = isset($options['access']) ? $options['access'] : 'true';
 121          $options['published']   = isset($options['published']) ? $options['published'] : 1;
 122          $options['countItems']  = isset($options['countItems']) ? $options['countItems'] : 0;
 123          $options['currentlang'] = Multilanguage::isEnabled() ? Factory::getLanguage()->getTag() : 0;
 124  
 125          $this->_options = $options;
 126      }
 127  
 128      /**
 129       * Returns a reference to a Categories object
 130       *
 131       * @param   string  $extension  Name of the categories extension
 132       * @param   array   $options    An array of options
 133       *
 134       * @return  Categories|boolean  Categories object on success, boolean false if an object does not exist
 135       *
 136       * @since       1.6
 137       * @deprecated  5.0 Use the ComponentInterface to get the categories
 138       */
 139      public static function getInstance($extension, $options = array())
 140      {
 141          $hash = md5(strtolower($extension) . serialize($options));
 142  
 143          if (isset(self::$instances[$hash])) {
 144              return self::$instances[$hash];
 145          }
 146  
 147          $categories = null;
 148  
 149          try {
 150              $parts = explode('.', $extension, 2);
 151  
 152              $component = Factory::getApplication()->bootComponent($parts[0]);
 153  
 154              if ($component instanceof CategoryServiceInterface) {
 155                  $categories = $component->getCategory($options, \count($parts) > 1 ? $parts[1] : '');
 156              }
 157          } catch (SectionNotFoundException $e) {
 158              $categories = null;
 159          }
 160  
 161          self::$instances[$hash] = $categories;
 162  
 163          return self::$instances[$hash];
 164      }
 165  
 166      /**
 167       * Loads a specific category and all its children in a CategoryNode object.
 168       *
 169       * @param   mixed    $id         an optional id integer or equal to 'root'
 170       * @param   boolean  $forceload  True to force  the _load method to execute
 171       *
 172       * @return  CategoryNode|null  CategoryNode object or null if $id is not valid
 173       *
 174       * @since   1.6
 175       */
 176      public function get($id = 'root', $forceload = false)
 177      {
 178          if ($id !== 'root') {
 179              $id = (int) $id;
 180  
 181              if ($id == 0) {
 182                  $id = 'root';
 183              }
 184          }
 185  
 186          // If this $id has not been processed yet, execute the _load method
 187          if ((!isset($this->_nodes[$id]) && !isset($this->_checkedCategories[$id])) || $forceload) {
 188              $this->_load($id);
 189          }
 190  
 191          // If we already have a value in _nodes for this $id, then use it.
 192          if (isset($this->_nodes[$id])) {
 193              return $this->_nodes[$id];
 194          }
 195  
 196          return null;
 197      }
 198  
 199      /**
 200       * Returns the extension of the category.
 201       *
 202       * @return   string  The extension
 203       *
 204       * @since   3.9.0
 205       */
 206      public function getExtension()
 207      {
 208          return $this->_extension;
 209      }
 210  
 211      /**
 212       * Load method
 213       *
 214       * @param   integer  $id  Id of category to load
 215       *
 216       * @return  void
 217       *
 218       * @since   1.6
 219       */
 220      protected function _load($id)
 221      {
 222          try {
 223              $db = $this->getDatabase();
 224          } catch (DatabaseNotFoundException $e) {
 225              @trigger_error(sprintf('Database must be set, this will not be caught anymore in 5.0.'), E_USER_DEPRECATED);
 226              $db = Factory::getContainer()->get(DatabaseInterface::class);
 227          }
 228  
 229          $app  = Factory::getApplication();
 230          $user = Factory::getUser();
 231          $extension = $this->_extension;
 232  
 233          if ($id !== 'root') {
 234              $id = (int) $id;
 235  
 236              if ($id === 0) {
 237                  $id = 'root';
 238              }
 239          }
 240  
 241          // Record that has this $id has been checked
 242          $this->_checkedCategories[$id] = true;
 243  
 244          $query = $db->getQuery(true)
 245              ->select(
 246                  [
 247                      $db->quoteName('c.id'),
 248                      $db->quoteName('c.asset_id'),
 249                      $db->quoteName('c.access'),
 250                      $db->quoteName('c.alias'),
 251                      $db->quoteName('c.checked_out'),
 252                      $db->quoteName('c.checked_out_time'),
 253                      $db->quoteName('c.created_time'),
 254                      $db->quoteName('c.created_user_id'),
 255                      $db->quoteName('c.description'),
 256                      $db->quoteName('c.extension'),
 257                      $db->quoteName('c.hits'),
 258                      $db->quoteName('c.language'),
 259                      $db->quoteName('c.level'),
 260                      $db->quoteName('c.lft'),
 261                      $db->quoteName('c.metadata'),
 262                      $db->quoteName('c.metadesc'),
 263                      $db->quoteName('c.metakey'),
 264                      $db->quoteName('c.modified_time'),
 265                      $db->quoteName('c.note'),
 266                      $db->quoteName('c.params'),
 267                      $db->quoteName('c.parent_id'),
 268                      $db->quoteName('c.path'),
 269                      $db->quoteName('c.published'),
 270                      $db->quoteName('c.rgt'),
 271                      $db->quoteName('c.title'),
 272                      $db->quoteName('c.modified_user_id'),
 273                      $db->quoteName('c.version'),
 274                  ]
 275              );
 276  
 277          $case_when = ' CASE WHEN ';
 278          $case_when .= $query->charLength($db->quoteName('c.alias'), '!=', '0');
 279          $case_when .= ' THEN ';
 280          $c_id = $query->castAsChar($db->quoteName('c.id'));
 281          $case_when .= $query->concatenate(array($c_id, $db->quoteName('c.alias')), ':');
 282          $case_when .= ' ELSE ';
 283          $case_when .= $c_id . ' END as ' . $db->quoteName('slug');
 284  
 285          $query->select($case_when)
 286              ->where('(' . $db->quoteName('c.extension') . ' = :extension OR ' . $db->quoteName('c.extension') . ' = ' . $db->quote('system') . ')')
 287              ->bind(':extension', $extension);
 288  
 289          if ($this->_options['access']) {
 290              $groups = $user->getAuthorisedViewLevels();
 291              $query->whereIn($db->quoteName('c.access'), $groups);
 292          }
 293  
 294          if ($this->_options['published'] == 1) {
 295              $query->where($db->quoteName('c.published') . ' = 1');
 296          }
 297  
 298          $query->order($db->quoteName('c.lft'));
 299  
 300          // Note: s for selected id
 301          if ($id !== 'root') {
 302              // Get the selected category
 303              $query->from($db->quoteName('#__categories', 's'))
 304                  ->where($db->quoteName('s.id') . ' = :id')
 305                  ->bind(':id', $id, ParameterType::INTEGER);
 306  
 307              if ($app->isClient('site') && Multilanguage::isEnabled()) {
 308                  // For the most part, we use c.lft column, which index is properly used instead of c.rgt
 309                  $query->join(
 310                      'INNER',
 311                      $db->quoteName('#__categories', 'c'),
 312                      '(' . $db->quoteName('s.lft') . ' < ' . $db->quoteName('c.lft')
 313                          . ' AND ' . $db->quoteName('c.lft') . ' < ' . $db->quoteName('s.rgt')
 314                          . ' AND ' . $db->quoteName('c.language')
 315                          . ' IN (' . implode(',', $query->bindArray([Factory::getLanguage()->getTag(), '*'], ParameterType::STRING)) . '))'
 316                          . ' OR (' . $db->quoteName('c.lft') . ' <= ' . $db->quoteName('s.lft')
 317                          . ' AND ' . $db->quoteName('s.rgt') . ' <= ' . $db->quoteName('c.rgt') . ')'
 318                  );
 319              } else {
 320                  $query->join(
 321                      'INNER',
 322                      $db->quoteName('#__categories', 'c'),
 323                      '(' . $db->quoteName('s.lft') . ' <= ' . $db->quoteName('c.lft')
 324                          . ' AND ' . $db->quoteName('c.lft') . ' < ' . $db->quoteName('s.rgt') . ')'
 325                          . ' OR (' . $db->quoteName('c.lft') . ' < ' . $db->quoteName('s.lft')
 326                          . ' AND ' . $db->quoteName('s.rgt') . ' < ' . $db->quoteName('c.rgt') . ')'
 327                  );
 328              }
 329          } else {
 330              $query->from($db->quoteName('#__categories', 'c'));
 331  
 332              if ($app->isClient('site') && Multilanguage::isEnabled()) {
 333                  $query->whereIn($db->quoteName('c.language'), [Factory::getLanguage()->getTag(), '*'], ParameterType::STRING);
 334              }
 335          }
 336  
 337          // Note: i for item
 338          if ($this->_options['countItems'] == 1) {
 339              $subQuery = $db->getQuery(true)
 340                  ->select('COUNT(' . $db->quoteName($db->escape('i.' . $this->_key)) . ')')
 341                  ->from($db->quoteName($db->escape($this->_table), 'i'))
 342                  ->where($db->quoteName($db->escape('i.' . $this->_field)) . ' = ' . $db->quoteName('c.id'));
 343  
 344              if ($this->_options['published'] == 1) {
 345                  $subQuery->where($db->quoteName($db->escape('i.' . $this->_statefield)) . ' = 1');
 346              }
 347  
 348              if ($this->_options['currentlang'] !== 0) {
 349                  $subQuery->where(
 350                      $db->quoteName('i.language')
 351                          . ' IN (' . implode(',', $query->bindArray([$this->_options['currentlang'], '*'], ParameterType::STRING)) . ')'
 352                  );
 353              }
 354  
 355              $query->select('(' . $subQuery . ') AS ' . $db->quoteName('numitems'));
 356          }
 357  
 358          // Get the results
 359          $db->setQuery($query);
 360          $results = $db->loadObjectList('id');
 361          $childrenLoaded = false;
 362  
 363          if (\count($results)) {
 364              // Foreach categories
 365              foreach ($results as $result) {
 366                  // Deal with root category
 367                  if ($result->id == 1) {
 368                      $result->id = 'root';
 369                  }
 370  
 371                  // Deal with parent_id
 372                  if ($result->parent_id == 1) {
 373                      $result->parent_id = 'root';
 374                  }
 375  
 376                  // Create the node
 377                  if (!isset($this->_nodes[$result->id])) {
 378                      // Create the CategoryNode and add to _nodes
 379                      $this->_nodes[$result->id] = new CategoryNode($result, $this);
 380  
 381                      // If this is not root and if the current node's parent is in the list or the current node parent is 0
 382                      if ($result->id !== 'root' && (isset($this->_nodes[$result->parent_id]) || $result->parent_id == 1)) {
 383                          // Compute relationship between node and its parent - set the parent in the _nodes field
 384                          $this->_nodes[$result->id]->setParent($this->_nodes[$result->parent_id]);
 385                      }
 386  
 387                      // If the node's parent id is not in the _nodes list and the node is not root (doesn't have parent_id == 0),
 388                      // then remove the node from the list
 389                      if (!(isset($this->_nodes[$result->parent_id]) || $result->parent_id == 0)) {
 390                          unset($this->_nodes[$result->id]);
 391                          continue;
 392                      }
 393  
 394                      if ($result->id == $id || $childrenLoaded) {
 395                          $this->_nodes[$result->id]->setAllLoaded();
 396                          $childrenLoaded = true;
 397                      }
 398                  } elseif ($result->id == $id || $childrenLoaded) {
 399                      // Create the CategoryNode
 400                      $this->_nodes[$result->id] = new CategoryNode($result, $this);
 401  
 402                      if ($result->id !== 'root' && (isset($this->_nodes[$result->parent_id]) || $result->parent_id)) {
 403                          // Compute relationship between node and its parent
 404                          $this->_nodes[$result->id]->setParent($this->_nodes[$result->parent_id]);
 405                      }
 406  
 407                      // If the node's parent id is not in the _nodes list and the node is not root (doesn't have parent_id == 0),
 408                      // then remove the node from the list
 409                      if (!(isset($this->_nodes[$result->parent_id]) || $result->parent_id == 0)) {
 410                          unset($this->_nodes[$result->id]);
 411                          continue;
 412                      }
 413  
 414                      if ($result->id == $id || $childrenLoaded) {
 415                          $this->_nodes[$result->id]->setAllLoaded();
 416                          $childrenLoaded = true;
 417                      }
 418                  }
 419              }
 420          } else {
 421              $this->_nodes[$id] = null;
 422          }
 423      }
 424  }


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