[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
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 }
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 |