PageRenderTime 68ms CodeModel.GetById 44ms RepoModel.GetById 1ms app.codeStats 0ms

/libraries/joomla/application/categories.php

https://bitbucket.org/izubizarreta/https-bitbucket.org-bityvip
PHP | 993 lines | 417 code | 113 blank | 463 comment | 76 complexity | a8e6f6771015405ec007ed7de2862e4a MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.0, JSON, GPL-2.0, BSD-3-Clause, LGPL-2.1, MIT
  1. <?php
  2. /**
  3. * @package Joomla.Platform
  4. * @subpackage Application
  5. *
  6. * @copyright Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
  7. * @license GNU General Public License version 2 or later; see LICENSE
  8. */
  9. defined('JPATH_PLATFORM') or die;
  10. /**
  11. * JCategories Class.
  12. *
  13. * @package Joomla.Platform
  14. * @subpackage Application
  15. * @since 11.1
  16. */
  17. class JCategories
  18. {
  19. /**
  20. * Array to hold the object instances
  21. *
  22. * @var array
  23. * @since 11.1
  24. */
  25. public static $instances = array();
  26. /**
  27. * Array of category nodes
  28. *
  29. * @var mixed
  30. * @since 11.1
  31. */
  32. protected $_nodes;
  33. /**
  34. * Array of checked categories -- used to save values when _nodes are null
  35. *
  36. * @var array
  37. * @since 11.1
  38. */
  39. protected $_checkedCategories;
  40. /**
  41. * Name of the extension the categories belong to
  42. *
  43. * @var string
  44. * @since 11.1
  45. */
  46. protected $_extension = null;
  47. /**
  48. * Name of the linked content table to get category content count
  49. *
  50. * @var string
  51. * @since 11.1
  52. */
  53. protected $_table = null;
  54. /**
  55. * Name of the category field
  56. *
  57. * @var string
  58. * @since 11.1
  59. */
  60. protected $_field = null;
  61. /**
  62. * Name of the key field
  63. *
  64. * @var string
  65. * @since 11.1
  66. */
  67. protected $_key = null;
  68. /**
  69. * Name of the items state field
  70. *
  71. * @var string
  72. * @since 11.1
  73. */
  74. protected $_statefield = null;
  75. /**
  76. * Array of options
  77. *
  78. * @var array
  79. * @since 11.1
  80. */
  81. protected $_options = null;
  82. /**
  83. * Class constructor
  84. *
  85. * @param array $options Array of options
  86. *
  87. * @since 11.1
  88. */
  89. public function __construct($options)
  90. {
  91. $this->_extension = $options['extension'];
  92. $this->_table = $options['table'];
  93. $this->_field = (isset($options['field']) && $options['field']) ? $options['field'] : 'catid';
  94. $this->_key = (isset($options['key']) && $options['key']) ? $options['key'] : 'id';
  95. $this->_statefield = (isset($options['statefield'])) ? $options['statefield'] : 'state';
  96. $options['access'] = (isset($options['access'])) ? $options['access'] : 'true';
  97. $options['published'] = (isset($options['published'])) ? $options['published'] : 1;
  98. $this->_options = $options;
  99. return true;
  100. }
  101. /**
  102. * Returns a reference to a JCategories object
  103. *
  104. * @param string $extension Name of the categories extension
  105. * @param array $options An array of options
  106. *
  107. * @return JCategories JCategories object
  108. *
  109. * @since 11.1
  110. */
  111. public static function getInstance($extension, $options = array())
  112. {
  113. $hash = md5($extension . serialize($options));
  114. if (isset(self::$instances[$hash]))
  115. {
  116. return self::$instances[$hash];
  117. }
  118. $parts = explode('.', $extension);
  119. $component = 'com_' . strtolower($parts[0]);
  120. $section = count($parts) > 1 ? $parts[1] : '';
  121. $classname = ucfirst(substr($component, 4)) . ucfirst($section) . 'Categories';
  122. if (!class_exists($classname))
  123. {
  124. $path = JPATH_SITE . '/components/' . $component . '/helpers/category.php';
  125. if (is_file($path))
  126. {
  127. include_once $path;
  128. }
  129. else
  130. {
  131. return false;
  132. }
  133. }
  134. self::$instances[$hash] = new $classname($options);
  135. return self::$instances[$hash];
  136. }
  137. /**
  138. * Loads a specific category and all its children in a JCategoryNode object
  139. *
  140. * @param mixed $id an optional id integer or equal to 'root'
  141. * @param boolean $forceload True to force the _load method to execute
  142. *
  143. * @return mixed JCategoryNode object or null if $id is not valid
  144. *
  145. * @since 11.1
  146. */
  147. public function get($id = 'root', $forceload = false)
  148. {
  149. if ($id !== 'root')
  150. {
  151. $id = (int) $id;
  152. if ($id == 0)
  153. {
  154. $id = 'root';
  155. }
  156. }
  157. // If this $id has not been processed yet, execute the _load method
  158. if ((!isset($this->_nodes[$id]) && !isset($this->_checkedCategories[$id])) || $forceload)
  159. {
  160. $this->_load($id);
  161. }
  162. // If we already have a value in _nodes for this $id, then use it.
  163. if (isset($this->_nodes[$id]))
  164. {
  165. return $this->_nodes[$id];
  166. }
  167. // If we processed this $id already and it was not valid, then return null.
  168. elseif (isset($this->_checkedCategories[$id]))
  169. {
  170. return null;
  171. }
  172. return false;
  173. }
  174. /**
  175. * Load method
  176. *
  177. * @param integer $id Id of category to load
  178. *
  179. * @return void
  180. *
  181. * @since 11.1
  182. */
  183. protected function _load($id)
  184. {
  185. $db = JFactory::getDbo();
  186. $app = JFactory::getApplication();
  187. $user = JFactory::getUser();
  188. $extension = $this->_extension;
  189. // Record that has this $id has been checked
  190. $this->_checkedCategories[$id] = true;
  191. $query = $db->getQuery(true);
  192. // Right join with c for category
  193. $query->select('c.*');
  194. $case_when = ' CASE WHEN ';
  195. $case_when .= $query->charLength('c.alias');
  196. $case_when .= ' THEN ';
  197. $c_id = $query->castAsChar('c.id');
  198. $case_when .= $query->concatenate(array($c_id, 'c.alias'), ':');
  199. $case_when .= ' ELSE ';
  200. $case_when .= $c_id . ' END as slug';
  201. $query->select($case_when);
  202. $query->from('#__categories as c');
  203. $query->where('(c.extension=' . $db->Quote($extension) . ' OR c.extension=' . $db->Quote('system') . ')');
  204. if ($this->_options['access'])
  205. {
  206. $query->where('c.access IN (' . implode(',', $user->getAuthorisedViewLevels()) . ')');
  207. }
  208. if ($this->_options['published'] == 1)
  209. {
  210. $query->where('c.published = 1');
  211. }
  212. $query->order('c.lft');
  213. // s for selected id
  214. if ($id != 'root')
  215. {
  216. // Get the selected category
  217. $query->where('s.id=' . (int) $id);
  218. if ($app->isSite() && $app->getLanguageFilter())
  219. {
  220. $query->leftJoin('#__categories AS s ON (s.lft < c.lft AND s.rgt > c.rgt AND c.language in (' . $db->Quote(JFactory::getLanguage()->getTag()) . ',' . $db->Quote('*') . ')) OR (s.lft >= c.lft AND s.rgt <= c.rgt)');
  221. }
  222. else
  223. {
  224. $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)');
  225. }
  226. }
  227. else
  228. {
  229. if ($app->isSite() && $app->getLanguageFilter())
  230. {
  231. $query->where('c.language in (' . $db->Quote(JFactory::getLanguage()->getTag()) . ',' . $db->Quote('*') . ')');
  232. }
  233. }
  234. $subQuery = ' (SELECT cat.id as id FROM #__categories AS cat JOIN #__categories AS parent ' .
  235. 'ON cat.lft BETWEEN parent.lft AND parent.rgt WHERE parent.extension = ' . $db->quote($extension) .
  236. ' AND parent.published != 1 GROUP BY cat.id) ';
  237. $query->leftJoin($subQuery . 'AS badcats ON badcats.id = c.id');
  238. $query->where('badcats.id is null');
  239. // i for item
  240. if (isset($this->_options['countItems']) && $this->_options['countItems'] == 1)
  241. {
  242. if ($this->_options['published'] == 1)
  243. {
  244. $query->leftJoin(
  245. $db->quoteName($this->_table) . ' AS i ON i.' . $db->quoteName($this->_field) . ' = c.id AND i.' . $this->_statefield . ' = 1'
  246. );
  247. }
  248. else
  249. {
  250. $query->leftJoin($db->quoteName($this->_table) . ' AS i ON i.' . $db->quoteName($this->_field) . ' = c.id');
  251. }
  252. $query->select('COUNT(i.' . $db->quoteName($this->_key) . ') AS numitems');
  253. }
  254. // Group by
  255. $query->group('c.id, c.asset_id, c.access, c.alias, c.checked_out, c.checked_out_time,
  256. c.created_time, c.created_user_id, c.description, c.extension, c.hits, c.language, c.level,
  257. c.lft, c.metadata, c.metadesc, c.metakey, c.modified_time, c.note, c.params, c.parent_id,
  258. c.path, c.published, c.rgt, c.title, c.modified_user_id');
  259. // Get the results
  260. $db->setQuery($query);
  261. $results = $db->loadObjectList('id');
  262. $childrenLoaded = false;
  263. if (count($results))
  264. {
  265. // Foreach categories
  266. foreach ($results as $result)
  267. {
  268. // Deal with root category
  269. if ($result->id == 1)
  270. {
  271. $result->id = 'root';
  272. }
  273. // Deal with parent_id
  274. if ($result->parent_id == 1)
  275. {
  276. $result->parent_id = 'root';
  277. }
  278. // Create the node
  279. if (!isset($this->_nodes[$result->id]))
  280. {
  281. // Create the JCategoryNode and add to _nodes
  282. $this->_nodes[$result->id] = new JCategoryNode($result, $this);
  283. // If this is not root and if the current node's parent is in the list or the current node parent is 0
  284. if ($result->id != 'root' && (isset($this->_nodes[$result->parent_id]) || $result->parent_id == 1))
  285. {
  286. // Compute relationship between node and its parent - set the parent in the _nodes field
  287. $this->_nodes[$result->id]->setParent($this->_nodes[$result->parent_id]);
  288. }
  289. // If the node's parent id is not in the _nodes list and the node is not root (doesn't have parent_id == 0),
  290. // then remove the node from the list
  291. if (!(isset($this->_nodes[$result->parent_id]) || $result->parent_id == 0))
  292. {
  293. unset($this->_nodes[$result->id]);
  294. continue;
  295. }
  296. if ($result->id == $id || $childrenLoaded)
  297. {
  298. $this->_nodes[$result->id]->setAllLoaded();
  299. $childrenLoaded = true;
  300. }
  301. }
  302. elseif ($result->id == $id || $childrenLoaded)
  303. {
  304. // Create the JCategoryNode
  305. $this->_nodes[$result->id] = new JCategoryNode($result, $this);
  306. if ($result->id != 'root' && (isset($this->_nodes[$result->parent_id]) || $result->parent_id))
  307. {
  308. // Compute relationship between node and its parent
  309. $this->_nodes[$result->id]->setParent($this->_nodes[$result->parent_id]);
  310. }
  311. if (!isset($this->_nodes[$result->parent_id]))
  312. {
  313. unset($this->_nodes[$result->id]);
  314. continue;
  315. }
  316. if ($result->id == $id || $childrenLoaded)
  317. {
  318. $this->_nodes[$result->id]->setAllLoaded();
  319. $childrenLoaded = true;
  320. }
  321. }
  322. }
  323. }
  324. else
  325. {
  326. $this->_nodes[$id] = null;
  327. }
  328. }
  329. }
  330. /**
  331. * Helper class to load Categorytree
  332. *
  333. * @package Joomla.Platform
  334. * @subpackage Application
  335. * @since 11.1
  336. */
  337. class JCategoryNode extends JObject
  338. {
  339. /**
  340. * Primary key
  341. *
  342. * @var integer
  343. * @since 11.1
  344. */
  345. public $id = null;
  346. /**
  347. * The id of the category in the asset table
  348. *
  349. * @var integer
  350. * @since 11.1
  351. */
  352. public $asset_id = null;
  353. /**
  354. * The id of the parent of category in the asset table, 0 for category root
  355. *
  356. * @var integer
  357. * @since 11.1
  358. */
  359. public $parent_id = null;
  360. /**
  361. * The lft value for this category in the category tree
  362. *
  363. * @var integer
  364. * @since 11.1
  365. */
  366. public $lft = null;
  367. /**
  368. * The rgt value for this category in the category tree
  369. *
  370. * @var integer
  371. * @since 11.1
  372. */
  373. public $rgt = null;
  374. /**
  375. * The depth of this category's position in the category tree
  376. *
  377. * @var integer
  378. * @since 11.1
  379. */
  380. public $level = null;
  381. /**
  382. * The extension this category is associated with
  383. *
  384. * @var integer
  385. * @since 11.1
  386. */
  387. public $extension = null;
  388. /**
  389. * The menu title for the category (a short name)
  390. *
  391. * @var string
  392. * @since 11.1
  393. */
  394. public $title = null;
  395. /**
  396. * The the alias for the category
  397. *
  398. * @var string
  399. * @since 11.1
  400. */
  401. public $alias = null;
  402. /**
  403. * Description of the category.
  404. *
  405. * @var string
  406. * @since 11.1
  407. */
  408. public $description = null;
  409. /**
  410. * The publication status of the category
  411. *
  412. * @var boolean
  413. * @since 11.1
  414. */
  415. public $published = null;
  416. /**
  417. * Whether the category is or is not checked out
  418. *
  419. * @var boolean
  420. * @since 11.1
  421. */
  422. public $checked_out = 0;
  423. /**
  424. * The time at which the category was checked out
  425. *
  426. * @var time
  427. * @since 11.1
  428. */
  429. public $checked_out_time = 0;
  430. /**
  431. * Access level for the category
  432. *
  433. * @var integer
  434. * @since 11.1
  435. */
  436. public $access = null;
  437. /**
  438. * JSON string of parameters
  439. *
  440. * @var string
  441. * @since 11.1
  442. */
  443. public $params = null;
  444. /**
  445. * Metadata description
  446. *
  447. * @var string
  448. * @since 11.1
  449. */
  450. public $metadesc = null;
  451. /**
  452. * Key words for meta data
  453. *
  454. * @var string
  455. * @since 11.1
  456. */
  457. public $metakey = null;
  458. /**
  459. * JSON string of other meta data
  460. *
  461. * @var string
  462. * @since 11.1
  463. */
  464. public $metadata = null;
  465. public $created_user_id = null;
  466. /**
  467. * The time at which the category was created
  468. *
  469. * @var time
  470. * @since 11.1
  471. */
  472. public $created_time = null;
  473. public $modified_user_id = null;
  474. /**
  475. * The time at which the category was modified
  476. *
  477. * @var time
  478. * @since 11.1
  479. */
  480. public $modified_time = null;
  481. /**
  482. * Nmber of times the category has been viewed
  483. *
  484. * @var integer
  485. * @since 11.1
  486. */
  487. public $hits = null;
  488. /**
  489. * The language for the category in xx-XX format
  490. *
  491. * @var time
  492. * @since 11.1
  493. */
  494. public $language = null;
  495. /**
  496. * Number of items in this category or descendants of this category
  497. *
  498. * @var integer
  499. * @since 11.1
  500. */
  501. public $numitems = null;
  502. /**
  503. * Number of children items
  504. *
  505. * @var
  506. * @since 11.1
  507. */
  508. public $childrennumitems = null;
  509. /**
  510. * Slug fo the category (used in URL)
  511. *
  512. * @var string
  513. * @since 11.1
  514. */
  515. public $slug = null;
  516. /**
  517. * Array of assets
  518. *
  519. * @var array
  520. * @since 11.1
  521. */
  522. public $assets = null;
  523. /**
  524. * Parent Category object
  525. *
  526. * @var object
  527. * @since 11.1
  528. */
  529. protected $_parent = null;
  530. /**
  531. * @var Array of Children
  532. * @since 11.1
  533. */
  534. protected $_children = array();
  535. /**
  536. * Path from root to this category
  537. *
  538. * @var array
  539. * @since 11.1
  540. */
  541. protected $_path = array();
  542. /**
  543. * Category left of this one
  544. *
  545. * @var integer
  546. * @since 11.1
  547. */
  548. protected $_leftSibling = null;
  549. /**
  550. * Category right of this one
  551. *
  552. * @var
  553. * @since 11.1
  554. */
  555. protected $_rightSibling = null;
  556. /**
  557. * true if all children have been loaded
  558. *
  559. * @var boolean
  560. * @since 11.1
  561. */
  562. protected $_allChildrenloaded = false;
  563. /**
  564. * Constructor of this tree
  565. *
  566. * @var
  567. * @since 11.1
  568. */
  569. protected $_constructor = null;
  570. /**
  571. * Class constructor
  572. *
  573. * @param array $category The category data.
  574. * @param JCategoryNode &$constructor The tree constructor.
  575. *
  576. * @since 11.1
  577. */
  578. public function __construct($category = null, &$constructor = null)
  579. {
  580. if ($category)
  581. {
  582. $this->setProperties($category);
  583. if ($constructor)
  584. {
  585. $this->_constructor = &$constructor;
  586. }
  587. return true;
  588. }
  589. return false;
  590. }
  591. /**
  592. * Set the parent of this category
  593. *
  594. * If the category already has a parent, the link is unset
  595. *
  596. * @param mixed &$parent JCategoryNode for the parent to be set or null
  597. *
  598. * @return void
  599. *
  600. * @since 11.1
  601. */
  602. public function setParent(&$parent)
  603. {
  604. if ($parent instanceof JCategoryNode || is_null($parent))
  605. {
  606. if (!is_null($this->_parent))
  607. {
  608. $key = array_search($this, $this->_parent->_children);
  609. unset($this->_parent->_children[$key]);
  610. }
  611. if (!is_null($parent))
  612. {
  613. $parent->_children[] = & $this;
  614. }
  615. $this->_parent = & $parent;
  616. if ($this->id != 'root')
  617. {
  618. if ($this->parent_id != 1)
  619. {
  620. $this->_path = $parent->getPath();
  621. }
  622. $this->_path[] = $this->id . ':' . $this->alias;
  623. }
  624. if (count($parent->_children) > 1)
  625. {
  626. end($parent->_children);
  627. $this->_leftSibling = prev($parent->_children);
  628. $this->_leftSibling->_rightsibling = &$this;
  629. }
  630. }
  631. }
  632. /**
  633. * Add child to this node
  634. *
  635. * If the child already has a parent, the link is unset
  636. *
  637. * @param JNode &$child The child to be added.
  638. *
  639. * @return void
  640. *
  641. * @since 11.1
  642. */
  643. public function addChild(&$child)
  644. {
  645. if ($child instanceof JCategoryNode)
  646. {
  647. $child->setParent($this);
  648. }
  649. }
  650. /**
  651. * Remove a specific child
  652. *
  653. * @param integer $id ID of a category
  654. *
  655. * @return void
  656. *
  657. * @since 11.1
  658. */
  659. public function removeChild($id)
  660. {
  661. $key = array_search($this, $this->_parent->_children);
  662. unset($this->_parent->_children[$key]);
  663. }
  664. /**
  665. * Get the children of this node
  666. *
  667. * @param boolean $recursive False by default
  668. *
  669. * @return array The children
  670. *
  671. * @since 11.1
  672. */
  673. public function &getChildren($recursive = false)
  674. {
  675. if (!$this->_allChildrenloaded)
  676. {
  677. $temp = $this->_constructor->get($this->id, true);
  678. if ($temp)
  679. {
  680. $this->_children = $temp->getChildren();
  681. $this->_leftSibling = $temp->getSibling(false);
  682. $this->_rightSibling = $temp->getSibling(true);
  683. $this->setAllLoaded();
  684. }
  685. }
  686. if ($recursive)
  687. {
  688. $items = array();
  689. foreach ($this->_children as $child)
  690. {
  691. $items[] = $child;
  692. $items = array_merge($items, $child->getChildren(true));
  693. }
  694. return $items;
  695. }
  696. return $this->_children;
  697. }
  698. /**
  699. * Get the parent of this node
  700. *
  701. * @return mixed JNode or null
  702. *
  703. * @since 11.1
  704. */
  705. public function &getParent()
  706. {
  707. return $this->_parent;
  708. }
  709. /**
  710. * Test if this node has children
  711. *
  712. * @return boolean True if there is a child
  713. *
  714. * @since 11.1
  715. */
  716. public function hasChildren()
  717. {
  718. return count($this->_children);
  719. }
  720. /**
  721. * Test if this node has a parent
  722. *
  723. * @return boolean True if there is a parent
  724. *
  725. * @since 11.1
  726. */
  727. public function hasParent()
  728. {
  729. return $this->getParent() != null;
  730. }
  731. /**
  732. * Function to set the left or right sibling of a category
  733. *
  734. * @param object $sibling JCategoryNode object for the sibling
  735. * @param boolean $right If set to false, the sibling is the left one
  736. *
  737. * @return void
  738. *
  739. * @since 11.1
  740. */
  741. public function setSibling($sibling, $right = true)
  742. {
  743. if ($right)
  744. {
  745. $this->_rightSibling = $sibling;
  746. }
  747. else
  748. {
  749. $this->_leftSibling = $sibling;
  750. }
  751. }
  752. /**
  753. * Returns the right or left sibling of a category
  754. *
  755. * @param boolean $right If set to false, returns the left sibling
  756. *
  757. * @return mixed JCategoryNode object with the sibling information or
  758. * NULL if there is no sibling on that side.
  759. *
  760. * @since 11.1
  761. */
  762. public function getSibling($right = true)
  763. {
  764. if (!$this->_allChildrenloaded)
  765. {
  766. $temp = $this->_constructor->get($this->id, true);
  767. $this->_children = $temp->getChildren();
  768. $this->_leftSibling = $temp->getSibling(false);
  769. $this->_rightSibling = $temp->getSibling(true);
  770. $this->setAllLoaded();
  771. }
  772. if ($right)
  773. {
  774. return $this->_rightSibling;
  775. }
  776. else
  777. {
  778. return $this->_leftSibling;
  779. }
  780. }
  781. /**
  782. * Returns the category parameters
  783. *
  784. * @return JRegistry
  785. *
  786. * @since 11.1
  787. */
  788. public function getParams()
  789. {
  790. if (!($this->params instanceof JRegistry))
  791. {
  792. $temp = new JRegistry;
  793. $temp->loadString($this->params);
  794. $this->params = $temp;
  795. }
  796. return $this->params;
  797. }
  798. /**
  799. * Returns the category metadata
  800. *
  801. * @return JRegistry A JRegistry object containing the metadata
  802. *
  803. * @since 11.1
  804. */
  805. public function getMetadata()
  806. {
  807. if (!($this->metadata instanceof JRegistry))
  808. {
  809. $temp = new JRegistry;
  810. $temp->loadString($this->metadata);
  811. $this->metadata = $temp;
  812. }
  813. return $this->metadata;
  814. }
  815. /**
  816. * Returns the category path to the root category
  817. *
  818. * @return array
  819. *
  820. * @since 11.1
  821. */
  822. public function getPath()
  823. {
  824. return $this->_path;
  825. }
  826. /**
  827. * Returns the user that created the category
  828. *
  829. * @param boolean $modified_user Returns the modified_user when set to true
  830. *
  831. * @return JUser A JUser object containing a userid
  832. *
  833. * @since 11.1
  834. */
  835. public function getAuthor($modified_user = false)
  836. {
  837. if ($modified_user)
  838. {
  839. return JFactory::getUser($this->modified_user_id);
  840. }
  841. return JFactory::getUser($this->created_user_id);
  842. }
  843. /**
  844. * Set to load all children
  845. *
  846. * @return void
  847. *
  848. * @since 11.1
  849. */
  850. public function setAllLoaded()
  851. {
  852. $this->_allChildrenloaded = true;
  853. foreach ($this->_children as $child)
  854. {
  855. $child->setAllLoaded();
  856. }
  857. }
  858. /**
  859. * Returns the number of items.
  860. *
  861. * @param boolean $recursive If false number of children, if true number of descendants
  862. *
  863. * @return integer Number of children or descendants
  864. *
  865. * @since 11.1
  866. */
  867. public function getNumItems($recursive = false)
  868. {
  869. if ($recursive)
  870. {
  871. $count = $this->numitems;
  872. foreach ($this->getChildren() as $child)
  873. {
  874. $count = $count + $child->getNumItems(true);
  875. }
  876. return $count;
  877. }
  878. return $this->numitems;
  879. }
  880. }