PageRenderTime 40ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/libraries/joomla/application/categories.php

https://github.com/3den/J-MediaGalleries
PHP | 645 lines | 380 code | 54 blank | 211 comment | 72 complexity | 844ab6b8b17b87ff77f7d8daa2f6d87b MD5 | raw file
  1. <?php
  2. /**
  3. * @version $Id: categories.php 19205 2010-10-22 19:50:48Z 3dentech $
  4. * @copyright Copyright (C) 2005 - 2010 Open Source Matters, Inc. All rights reserved.
  5. * @license GNU General Public License version 2 or later; see LICENSE.txt
  6. */
  7. // No direct access
  8. defined('JPATH_BASE') or die;
  9. /**
  10. * JCategories Class.
  11. *
  12. * @package Joomla.Framework
  13. * @subpackage Application
  14. * @since 1.6
  15. */
  16. class JCategories
  17. {
  18. /**
  19. * Array to hold the object instances
  20. *
  21. * @param array
  22. */
  23. static $instances = array();
  24. /**
  25. * Array of category nodes
  26. *
  27. * @var mixed
  28. */
  29. protected $_nodes;
  30. /**
  31. * Array of checked categories -- used to save values when _nodes are null
  32. *
  33. * @var array
  34. */
  35. protected $_checkedCategories;
  36. /**
  37. * Name of the extension the categories belong to
  38. *
  39. * @var string
  40. */
  41. protected $_extension = null;
  42. /**
  43. * Name of the linked content table to get category content count
  44. *
  45. * @var string
  46. */
  47. protected $_table = null;
  48. /**
  49. * Name of the category field
  50. *
  51. * @var string
  52. */
  53. protected $_field = null;
  54. /**
  55. * Name of the key field
  56. *
  57. * @var string
  58. */
  59. protected $_key = null;
  60. /**
  61. * Name of the items state field
  62. */
  63. protected $_statefield = null;
  64. /**
  65. * Array of options
  66. *
  67. * @var array
  68. */
  69. protected $_options = null;
  70. /**
  71. * Class constructor
  72. *
  73. * @access public
  74. * @return boolean True on success
  75. */
  76. public function __construct($options)
  77. {
  78. $this->_extension = $options['extension'];
  79. $this->_table = $options['table'];
  80. $this->_field = (isset($options['field'])&&$options['field'])?$options['field']:'catid';
  81. $this->_key = (isset($options['key'])&&$options['key'])?$options['key']:'id';
  82. $this->_statefield = (isset($options['statefield'])) ? $options['statefield'] : 'state';
  83. $options['access'] = (isset($options['access'])) ? $options['access'] : 'true';
  84. $options['published'] = (isset($options['published'])) ? $options['published'] : 1;
  85. $this->_options = $options;
  86. return true;
  87. }
  88. /**
  89. * Returns a reference to a JCategories object
  90. *
  91. * @param $extension Name of the categories extension
  92. * @param $options An array of options
  93. * @return object
  94. */
  95. public static function getInstance($extension, $options = array())
  96. {
  97. $hash = md5($extension.serialize($options));
  98. if (isset(self::$instances[$hash]))
  99. {
  100. return self::$instances[$hash];
  101. }
  102. $parts = explode('.',$extension);
  103. $component = 'com_'.strtolower($parts[0]);
  104. $section = count($parts) > 1 ? $parts[1] : '';
  105. $classname = ucfirst(substr($component,4)).ucfirst($section).'Categories';
  106. if (!class_exists($classname))
  107. {
  108. $path = JPATH_SITE.DS.'components'.DS.$component.DS.'helpers'.DS.'category.php';
  109. if (is_file($path))
  110. {
  111. require_once $path;
  112. } else {
  113. return false;
  114. }
  115. }
  116. self::$instances[$hash] = new $classname($options);
  117. return self::$instances[$hash];
  118. }
  119. /**
  120. * Loads a specific category and all its children in a JCategoryNode object
  121. *
  122. * @param an optional id integer or equal to 'root'
  123. * @return JCategoryNode|null
  124. */
  125. public function get($id = 'root', $forceload = false)
  126. {
  127. if ($id !== 'root')
  128. {
  129. $id = (int) $id;
  130. if ($id == 0)
  131. {
  132. $id = 'root';
  133. }
  134. }
  135. // If this $id has not been processed yet, execute the _load method
  136. if ((!isset($this->_nodes[$id]) && !isset($this->_checkedCategories[$id])) || $forceload)
  137. {
  138. $this->_load($id);
  139. }
  140. // If we already have a value in _nodes for this $id, then use it
  141. if(isset($this->_nodes[$id]))
  142. {
  143. return $this->_nodes[$id];
  144. }
  145. // If we processed this $id already and it was not valid, then return null
  146. elseif (isset($this->_checkedCategories[$id]))
  147. {
  148. return null;
  149. }
  150. return false;
  151. }
  152. protected function _load($id)
  153. {
  154. $db = JFactory::getDbo();
  155. $app = JFactory::getApplication();
  156. $user = JFactory::getUser();
  157. $extension = $this->_extension;
  158. // Record that this $id has been checked
  159. $this->_checkedCategories[$id] = true;
  160. $query = new JDatabaseQuery;
  161. // right join with c for category
  162. $query->select('c.*');
  163. $query->select('CASE WHEN CHAR_LENGTH(c.alias) THEN CONCAT_WS(":", c.id, c.alias) ELSE c.id END as slug');
  164. $query->from('#__categories as c');
  165. $query->where('(c.extension='.$db->Quote($extension).' OR c.extension='.$db->Quote('system').')');
  166. if($this->_options['access'])
  167. {
  168. $query->where('c.access IN ('.implode(',', $user->authorisedLevels()).')');
  169. }
  170. if($this->_options['published'] == 1)
  171. {
  172. $query->where('c.published = 1');
  173. }
  174. $query->order('c.lft');
  175. // s for selected id
  176. if ($id!='root')
  177. {
  178. // Get the selected category
  179. $query->leftJoin('#__categories AS s ON (s.lft <= c.lft AND s.rgt >= c.rgt) OR (s.lft > c.lft AND s.rgt < c.rgt)');
  180. $query->where('s.id='.(int)$id);
  181. }
  182. $subQuery = ' (SELECT cat.id as id FROM #__categories AS cat JOIN #__categories AS parent ' .
  183. 'ON cat.lft BETWEEN parent.lft AND parent.rgt WHERE parent.extension = ' . $db->quote($extension) .
  184. ' AND parent.published != 1 GROUP BY cat.id) ';
  185. $query->leftJoin($subQuery . 'AS badcats ON badcats.id = c.id');
  186. $query->where('badcats.id is null');
  187. // i for item
  188. if(isset($this->_options['countItems']) && $this->_options['countItems'] == 1)
  189. {
  190. if($this->_options['published'] == 1)
  191. {
  192. $query->leftJoin($db->nameQuote($this->_table).' AS i ON i.'.$db->nameQuote($this->_field).' = c.id AND i.'.$this->_statefield.' = 1');
  193. } else {
  194. $query->leftJoin($db->nameQuote($this->_table).' AS i ON i.'.$db->nameQuote($this->_field).' = c.id');
  195. }
  196. $query->select('COUNT(i.'.$db->nameQuote($this->_key).') AS numitems');
  197. }
  198. // Group by
  199. $query->group('c.id');
  200. // Filter by language
  201. if ($app->isSite() && $app->getLanguageFilter()) {
  202. $query->where('(' . ($id!='root' ? 'c.id=s.id OR ':'') .'c.language in (' . $db->Quote(JFactory::getLanguage()->getTag()) . ',' . $db->Quote('*') . '))');
  203. }
  204. // Get the results
  205. $db->setQuery($query);
  206. $results = $db->loadObjectList('id');
  207. $childrenLoaded = false;
  208. if (count($results))
  209. {
  210. // foreach categories
  211. foreach($results as $result)
  212. {
  213. // Deal with root category
  214. if($result->id == 1)
  215. {
  216. $result->id = 'root';
  217. }
  218. // Deal with parent_id
  219. if($result->parent_id == 1)
  220. {
  221. $result->parent_id = 'root';
  222. }
  223. // Create the node
  224. if (!isset($this->_nodes[$result->id]))
  225. {
  226. // Create the JCategoryNode and add to _nodes
  227. $this->_nodes[$result->id] = new JCategoryNode($result, $this);
  228. // If this is not root, and if the current nodes parent is in the list or the current node parent is 0
  229. if($result->id != 'root' && (isset($this->_nodes[$result->parent_id]) || $result->parent_id == 0))
  230. {
  231. // Compute relationship between node and its parent - set the parent in the _nodes field
  232. $this->_nodes[$result->id]->setParent($this->_nodes[$result->parent_id]);
  233. }
  234. // if the node's parent id is not in the _nodes list and the node is not root (doesn't have parent_id == 0),
  235. // then remove this nodes from the list
  236. if(!(isset($this->_nodes[$result->parent_id]) || $result->parent_id == 0))
  237. {
  238. unset($this->_nodes[$result->id]);
  239. continue;
  240. }
  241. if($result->id == $id || $childrenLoaded)
  242. {
  243. $this->_nodes[$result->id]->setAllLoaded();
  244. $childrenLoaded = true;
  245. }
  246. }
  247. elseif($result->id == $id || $childrenLoaded)
  248. {
  249. // Create the JCategoryNode
  250. $this->_nodes[$result->id] = new JCategoryNode($result, $this);
  251. if($result->id != 'root' && (isset($this->_nodes[$result->parent_id]) || $result->parent_id))
  252. {
  253. // Compute relationship between node and its parent
  254. $this->_nodes[$result->id]->setParent($this->_nodes[$result->parent_id]);
  255. }
  256. if(!isset($this->_nodes[$result->parent_id]))
  257. {
  258. unset($this->_nodes[$result->id]);
  259. continue;
  260. }
  261. if($result->id == $id || $childrenLoaded)
  262. {
  263. $this->_nodes[$result->id]->setAllLoaded();
  264. $childrenLoaded = true;
  265. }
  266. }
  267. }
  268. }
  269. else
  270. {
  271. $this->_nodes[$id] = null;
  272. }
  273. }
  274. }
  275. /**
  276. * Helper class to load Categorytree
  277. * @author Hannes
  278. * @since 1.6
  279. */
  280. class JCategoryNode extends JObject
  281. {
  282. /** @var int Primary key */
  283. public $id = null;
  284. public $asset_id = null;
  285. public $parent_id = null;
  286. public $lft = null;
  287. public $rgt = null;
  288. public $level = null;
  289. public $extension = null;
  290. /** @var string The menu title for the category (a short name)*/
  291. public $title = null;
  292. /** @var string The the alias for the category*/
  293. public $alias = null;
  294. /** @var string */
  295. public $description = null;
  296. /** @var boolean */
  297. public $published = null;
  298. /** @var boolean */
  299. public $checked_out = 0;
  300. /** @var time */
  301. public $checked_out_time = 0;
  302. /** @var int */
  303. public $access = null;
  304. /** @var string */
  305. public $params = null;
  306. public $metadesc = null;
  307. public $metakey = null;
  308. public $metadata = null;
  309. public $created_user_id = null;
  310. public $created_time = null;
  311. public $modified_user_id = null;
  312. public $modified_time = null;
  313. public $hits = null;
  314. public $language = null;
  315. public $numitems = null;
  316. public $childrennumitems = null;
  317. public $slug = null;
  318. public $assets = null;
  319. /**
  320. * @var Parent Category
  321. */
  322. protected $_parent = null;
  323. /**
  324. * @var Array of Children
  325. */
  326. protected $_children = array();
  327. /**
  328. * @var Path from root to this category
  329. */
  330. protected $_path = array();
  331. /**
  332. * @var Category left of this one
  333. */
  334. protected $_leftSibling = null;
  335. /**
  336. * @var Category right of this one
  337. */
  338. protected $_rightSibling = null;
  339. /**
  340. * @var boolean true if all children have been loaded
  341. */
  342. protected $_allChildrenloaded = false;
  343. /**
  344. * @var Constructor of this tree
  345. */
  346. protected $_constructor = null;
  347. /**
  348. * Class constructor
  349. * @param $category
  350. * @return unknown_type
  351. */
  352. public function __construct($category = null, &$constructor = null)
  353. {
  354. if ($category)
  355. {
  356. $this->setProperties($category);
  357. if($constructor)
  358. {
  359. $this->_constructor = &$constructor;
  360. }
  361. return true;
  362. }
  363. return false;
  364. }
  365. /**
  366. * Set the parent of this category
  367. *
  368. * If the category already has a parent, the link is unset
  369. *
  370. * @param JCategoryNode|null the parent to be setted
  371. */
  372. function setParent(&$parent)
  373. {
  374. if ($parent instanceof JCategoryNode || is_null($parent))
  375. {
  376. if (!is_null($this->_parent))
  377. {
  378. $key = array_search($this, $this->_parent->_children);
  379. unset($this->_parent->_children[$key]);
  380. }
  381. if (!is_null($parent))
  382. {
  383. $parent->_children[] = & $this;
  384. }
  385. $this->_parent = & $parent;
  386. if($this->id != 'root')
  387. {
  388. $this->_path = $parent->getPath();
  389. $this->_path[] = $this->id.':'.$this->alias;
  390. }
  391. if(count($parent->_children) > 1)
  392. {
  393. end($parent->_children);
  394. $this->_leftSibling = prev($parent->_children);
  395. $this->_leftSibling->_rightsibling = &$this;
  396. }
  397. }
  398. }
  399. /**
  400. * Add child to this node
  401. *
  402. * If the child already has a parent, the link is unset
  403. *
  404. * @param JNode the child to be added
  405. */
  406. function addChild(&$child)
  407. {
  408. if ($child instanceof JCategoryNode)
  409. {
  410. $child->setParent($this);
  411. }
  412. }
  413. /**
  414. * Remove a specific child
  415. *
  416. * @param int ID of a category
  417. */
  418. function removeChild($id)
  419. {
  420. $key = array_search($this, $this->_parent->_children);
  421. unset($this->_parent->_children[$key]);
  422. }
  423. /**
  424. * Get the children of this node
  425. *
  426. * @return array the children
  427. */
  428. function &getChildren($recursive = false)
  429. {
  430. if(!$this->_allChildrenloaded)
  431. {
  432. $temp = $this->_constructor->get($this->id, true);
  433. $this->_children = $temp->getChildren();
  434. $this->_leftSibling = $temp->getSibling(false);
  435. $this->_rightSibling = $temp->getSibling(true);
  436. $this->setAllLoaded();
  437. }
  438. if($recursive)
  439. {
  440. $items = array();
  441. foreach($this->_children as $child)
  442. {
  443. $items[] = $child;
  444. $items = array_merge($items, $child->getChildren(true));
  445. }
  446. return $items;
  447. }
  448. return $this->_children;
  449. }
  450. /**
  451. * Get the parent of this node
  452. *
  453. * @return JNode|null the parent
  454. */
  455. function &getParent()
  456. {
  457. return $this->_parent;
  458. }
  459. /**
  460. * Test if this node has children
  461. *
  462. * @return bool
  463. */
  464. function hasChildren()
  465. {
  466. return count($this->_children);
  467. }
  468. /**
  469. * Test if this node has a parent
  470. *
  471. * @return bool
  472. */
  473. function hasParent()
  474. {
  475. return $this->getParent() != null;
  476. }
  477. /**
  478. * Function to set the left or right sibling
  479. * of a category
  480. *
  481. * @param JCategoryNode $sibling sibling
  482. * @param boolean $right if set to false, the sibling is the left one
  483. * @return void
  484. */
  485. function setSibling($sibling, $right = true)
  486. {
  487. if($right)
  488. {
  489. $this->_rightSibling = $sibling;
  490. } else {
  491. $this->_leftSibling = $sibling;
  492. }
  493. }
  494. /**
  495. * Returns the right or left sibling of a category
  496. *
  497. * @param boolean $right if set to false, returns the left sibling
  498. * @return JCategoryNode|null
  499. */
  500. function getSibling($right = true)
  501. {
  502. if(!$this->_allChildrenloaded)
  503. {
  504. $temp = $this->_constructor->get($this->id, true);
  505. $this->_children = $temp->getChildren();
  506. $this->_leftSibling = $temp->getSibling(false);
  507. $this->_rightSibling = $temp->getSibling(true);
  508. $this->setAllLoaded();
  509. }
  510. if($right)
  511. {
  512. return $this->_rightSibling;
  513. } else {
  514. return $this->_leftSibling;
  515. }
  516. }
  517. /**
  518. * Returns the category parameters
  519. *
  520. * @return JRegistry
  521. */
  522. function getParams()
  523. {
  524. if(!$this->params instanceof JRegistry)
  525. {
  526. $temp = new JRegistry();
  527. $temp->loadJSON($this->params);
  528. $this->params = $temp;
  529. }
  530. return $this->params;
  531. }
  532. /**
  533. * Returns the category metadata
  534. *
  535. * @return JRegistry
  536. */
  537. function getMetadata()
  538. {
  539. if(!($this->metadata instanceof JRegistry))
  540. {
  541. $temp = new JRegistry();
  542. $temp->loadJSON($this->metadata);
  543. $this->metadata = $temp;
  544. }
  545. return $this->metadata;
  546. }
  547. /**
  548. * Returns the category path to the root category
  549. *
  550. * @return array
  551. */
  552. function getPath()
  553. {
  554. return $this->_path;
  555. }
  556. /**
  557. * Returns the user that authored the category
  558. *
  559. * @param boolean $modified_user Returns the modified_user when set to true
  560. * @return JUser
  561. */
  562. function getAuthor($modified_user = false)
  563. {
  564. if($modified_user)
  565. {
  566. return JFactory::getUser($this->modified_user_id);
  567. }
  568. return JFactory::getUser($this->created_user_id);
  569. }
  570. function setAllLoaded()
  571. {
  572. $this->_allChildrenloaded = true;
  573. foreach($this->_children as $child)
  574. {
  575. $child->setAllLoaded();
  576. }
  577. }
  578. function getNumItems($recursive = false)
  579. {
  580. if($recursive)
  581. {
  582. $count = $this->numitems;
  583. foreach($this->getChildren() as $child)
  584. {
  585. $count = $count + $child->getNumItems(true);
  586. }
  587. return $count;
  588. }
  589. return $this->numitems;
  590. }
  591. }