Commit | Line | Data |
---|---|---|
796fdcf2 MS |
1 | <?php |
2 | namespace wcf\data\category; | |
3 | use wcf\system\category\CategoryHandler; | |
4 | use wcf\system\exception\SystemException; | |
5 | ||
6 | /** | |
7 | * Represents a tree of category nodes. | |
8 | * | |
9 | * @author Matthias Schmidt | |
c839bd49 | 10 | * @copyright 2001-2018 WoltLab GmbH |
796fdcf2 | 11 | * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php> |
e71525e4 | 12 | * @package WoltLabSuite\Core\Data\Category |
796fdcf2 MS |
13 | */ |
14 | class CategoryNodeTree implements \IteratorAggregate { | |
83aa1dc1 | 15 | /** |
b2aa772d | 16 | * list of ids of categories which will not be included in the node tree |
83aa1dc1 MS |
17 | * @var integer[] |
18 | */ | |
19 | protected $excludedCategoryIDs = []; | |
20 | ||
21 | /** | |
22 | * if true, disabled categories are also included in the node tree | |
23 | * @var boolean | |
24 | */ | |
25 | protected $includeDisabledCategories = false; | |
26 | ||
dcf94cd3 | 27 | /** |
734662c9 | 28 | * maximum depth considered when building the node tree |
893aace3 | 29 | * @var integer |
dcf94cd3 AE |
30 | */ |
31 | protected $maxDepth = -1; | |
32 | ||
796fdcf2 MS |
33 | /** |
34 | * name of the category node class | |
35 | * @var string | |
36 | */ | |
734662c9 | 37 | protected $nodeClassName = CategoryNode::class; |
796fdcf2 MS |
38 | |
39 | /** | |
40 | * id of the parent category | |
41 | * @var integer | |
42 | */ | |
43 | protected $parentCategoryID = 0; | |
44 | ||
45 | /** | |
46 | * parent category node | |
734662c9 | 47 | * @var CategoryNode |
796fdcf2 MS |
48 | */ |
49 | protected $parentNode = null; | |
50 | ||
734662c9 MS |
51 | /** |
52 | * name of the category object type | |
53 | * @var string | |
54 | */ | |
55 | protected $objectType = ''; | |
56 | ||
796fdcf2 MS |
57 | /** |
58 | * Creates a new instance of CategoryNodeTree. | |
59 | * | |
60 | * @param string $objectType | |
61 | * @param integer $parentCategoryID | |
62 | * @param boolean $includeDisabledCategories | |
734662c9 | 63 | * @param integer[] $excludedCategoryIDs |
2b770bdd | 64 | * @throws SystemException |
796fdcf2 | 65 | */ |
734662c9 | 66 | public function __construct($objectType, $parentCategoryID = 0, $includeDisabledCategories = false, array $excludedCategoryIDs = []) { |
796fdcf2 MS |
67 | $this->objectType = $objectType; |
68 | $this->parentCategoryID = $parentCategoryID; | |
69 | $this->includeDisabledCategories = $includeDisabledCategories; | |
70 | $this->excludedCategoryIDs = $excludedCategoryIDs; | |
71 | ||
72 | // validate category object type | |
73 | if (CategoryHandler::getInstance()->getObjectTypeByName($this->objectType) === null) { | |
74 | throw new SystemException("Unknown category object type '".$this->objectType."'"); | |
75 | } | |
76 | } | |
77 | ||
dcf94cd3 AE |
78 | /** |
79 | * Sets the maximum depth considered when building the node tree, defaults | |
80 | * to -1 which equals infinite. | |
81 | * | |
82 | * @param integer $maxDepth | |
83 | */ | |
84 | public function setMaxDepth($maxDepth) { | |
85 | $this->maxDepth = $maxDepth; | |
86 | } | |
87 | ||
796fdcf2 MS |
88 | /** |
89 | * Builds the category node tree. | |
90 | */ | |
91 | protected function buildTree() { | |
92 | $this->parentNode = $this->getNode($this->parentCategoryID); | |
dcf94cd3 | 93 | $this->buildTreeLevel($this->parentNode, $this->maxDepth); |
796fdcf2 MS |
94 | } |
95 | ||
96 | /** | |
97 | * Builds a certain level of the tree. | |
98 | * | |
734662c9 MS |
99 | * @param CategoryNode $parentNode |
100 | * @param integer $depth | |
796fdcf2 | 101 | */ |
dcf94cd3 AE |
102 | protected function buildTreeLevel(CategoryNode $parentNode, $depth = 0) { |
103 | if ($this->maxDepth != -1 && $depth < 0) { | |
104 | return; | |
105 | } | |
106 | ||
796fdcf2 MS |
107 | foreach ($this->getChildCategories($parentNode) as $childCategory) { |
108 | $childNode = $this->getNode($childCategory->categoryID); | |
109 | ||
110 | if ($this->isIncluded($childNode)) { | |
111 | $parentNode->addChild($childNode); | |
112 | ||
113 | // build next level | |
11fa0d33 | 114 | $this->buildTreeLevel($childNode, $depth - 1); |
796fdcf2 MS |
115 | } |
116 | } | |
117 | } | |
118 | ||
119 | /** | |
120 | * Returns the category with the given id. | |
121 | * | |
122 | * @param integer $categoryID | |
734662c9 | 123 | * @return Category |
796fdcf2 MS |
124 | */ |
125 | protected function getCategory($categoryID) { | |
126 | return CategoryHandler::getInstance()->getCategory($categoryID); | |
127 | } | |
128 | ||
129 | /** | |
130 | * Returns the child categories of the given category node. | |
131 | * | |
734662c9 MS |
132 | * @param CategoryNode $parentNode |
133 | * @return Category[] | |
796fdcf2 MS |
134 | */ |
135 | protected function getChildCategories(CategoryNode $parentNode) { | |
136 | return CategoryHandler::getInstance()->getChildCategories($parentNode->categoryID, $parentNode->objectTypeID); | |
137 | } | |
138 | ||
139 | /** | |
734662c9 | 140 | * @inheritDoc |
796fdcf2 MS |
141 | */ |
142 | public function getIterator() { | |
143 | if ($this->parentNode === null) { | |
144 | $this->buildTree(); | |
145 | } | |
146 | ||
147 | return new \RecursiveIteratorIterator($this->parentNode, \RecursiveIteratorIterator::SELF_FIRST); | |
148 | } | |
149 | ||
150 | /** | |
151 | * Returns the category node for the category with the given id. | |
152 | * | |
153 | * @param integer $categoryID | |
734662c9 | 154 | * @return CategoryNode |
796fdcf2 MS |
155 | */ |
156 | protected function getNode($categoryID) { | |
157 | if (!$categoryID) { | |
734662c9 | 158 | $category = new Category(null, [ |
796fdcf2 MS |
159 | 'categoryID' => 0, |
160 | 'objectTypeID' => CategoryHandler::getInstance()->getObjectTypeByName($this->objectType)->objectTypeID | |
734662c9 | 161 | ]); |
796fdcf2 MS |
162 | } |
163 | else { | |
164 | $category = $this->getCategory($categoryID); | |
165 | } | |
166 | ||
167 | // decorate category if necessary | |
734662c9 | 168 | $decoratorClassName = call_user_func([$this->nodeClassName, 'getBaseClass']); |
157054c9 | 169 | if ($decoratorClassName != Category::class) { |
796fdcf2 MS |
170 | $category = new $decoratorClassName($category); |
171 | } | |
172 | ||
173 | return new $this->nodeClassName($category); | |
174 | } | |
175 | ||
176 | /** | |
177 | * Returns true if the given category node fulfils all relevant conditions | |
178 | * to be included in this tree. | |
179 | * | |
734662c9 | 180 | * @param CategoryNode $categoryNode |
796fdcf2 MS |
181 | * @return boolean |
182 | */ | |
183 | protected function isIncluded(CategoryNode $categoryNode) { | |
184 | return (!$categoryNode->isDisabled || $this->includeDisabledCategories) && !in_array($categoryNode->categoryID, $this->excludedCategoryIDs); | |
185 | } | |
186 | } |