Add EmailLogListPage
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / data / category / Category.class.php
1 <?php
2
3 namespace wcf\data\category;
4
5 use wcf\data\IPermissionObject;
6 use wcf\data\object\type\ObjectType;
7 use wcf\data\ProcessibleDatabaseObject;
8 use wcf\data\user\User;
9 use wcf\system\category\CategoryHandler;
10 use wcf\system\category\CategoryPermissionHandler;
11 use wcf\system\category\ICategoryType;
12 use wcf\system\exception\PermissionDeniedException;
13 use wcf\system\request\IRouteController;
14 use wcf\system\WCF;
15
16 /**
17 * Represents a category.
18 *
19 * @author Matthias Schmidt
20 * @copyright 2001-2019 WoltLab GmbH
21 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
22 * @package WoltLabSuite\Core\Data\Category
23 *
24 * @property-read int $categoryID unique id of the category
25 * @property-read int $objectTypeID id of the `com.woltlab.wcf.category` object type
26 * @property-read int $parentCategoryID id of the category's parent category or `0` if it has no parent category
27 * @property-read string $title title of the category or name of language item which contains the title
28 * @property-read string $description description of the category or name of language item which contains the description
29 * @property-read int $descriptionUseHtml is `1` if html is enabled in the description, otherwise `0`
30 * @property-read int $showOrder position of the category in relation to its siblings
31 * @property-read int $time timestamp at which the comment has been created
32 * @property-read int $isDisabled is `1` if the category is disabled and thus neither accessible nor selectable, otherwise `0`
33 * @property-read array $additionalData array with additional data of the category
34 */
35 class Category extends ProcessibleDatabaseObject implements IPermissionObject, IRouteController
36 {
37 /**
38 * list of child categories of this category
39 * @var Category[]
40 */
41 protected $childCategories;
42
43 /**
44 * list of all child categories of this category
45 * @var Category[]
46 */
47 protected $allChildCategories;
48
49 /**
50 * list of all parent category generations of this category
51 * @var Category[]
52 */
53 protected $parentCategories;
54
55 /**
56 * parent category of this category
57 * @var Category
58 */
59 protected $parentCategory;
60
61 /**
62 * acl permissions of this category for the active user
63 * @deprecated
64 * @var bool[]
65 */
66 protected $permissions;
67
68 /**
69 * acl permissions of this category grouped by the id of the user they
70 * belong to
71 * @var array
72 */
73 protected $userPermissions = [];
74
75 /**
76 * fallback return value used in Category::getPermission()
77 * @var bool
78 */
79 protected $defaultPermission = false;
80
81 /**
82 * @inheritDoc
83 */
84 protected static $processorInterface = ICategoryType::class;
85
86 /**
87 * @inheritDoc
88 */
89 public function __get($name)
90 {
91 // forward 'className' property requests to object type
92 if ($name == 'className') {
93 return $this->getObjectType()->className;
94 }
95
96 $value = parent::__get($name);
97
98 // check additional data
99 if ($value === null) {
100 if (isset($this->data['additionalData'][$name])) {
101 $value = $this->data['additionalData'][$name];
102 }
103 }
104
105 return $value;
106 }
107
108 /**
109 * @inheritDoc
110 */
111 public function checkPermissions(array $permissions)
112 {
113 foreach ($permissions as $permission) {
114 if (!$this->getPermission($permission)) {
115 throw new PermissionDeniedException();
116 }
117 }
118 }
119
120 /**
121 * Returns the category object type of the category.
122 *
123 * @return ObjectType
124 */
125 public function getObjectType()
126 {
127 return CategoryHandler::getInstance()->getObjectType($this->objectTypeID);
128 }
129
130 /**
131 * Returns the direct child categories of this category.
132 *
133 * @return Category[]
134 */
135 public function getChildCategories()
136 {
137 if ($this->childCategories === null) {
138 $this->childCategories = CategoryHandler::getInstance()->getChildCategories($this->categoryID);
139 }
140
141 return $this->childCategories;
142 }
143
144 /**
145 * Returns the child categories of this category recursively.
146 *
147 * @return Category[]
148 */
149 public function getAllChildCategories()
150 {
151 if ($this->allChildCategories === null) {
152 $directChildCategories = CategoryHandler::getInstance()->getChildCategories($this->categoryID);
153 $childCategories = [];
154 foreach ($directChildCategories as $childCategory) {
155 $childCategories = \array_replace($childCategories, $childCategory->getAllChildCategories());
156 }
157
158 $this->allChildCategories = \array_replace($directChildCategories, $childCategories);
159 }
160
161 return $this->allChildCategories;
162 }
163
164 /**
165 * Returns the parent category of the category or `null` if the category has no parent category.
166 *
167 * @return Category|null
168 */
169 public function getParentCategory()
170 {
171 if ($this->parentCategoryID && $this->parentCategory === null) {
172 $this->parentCategory = CategoryHandler::getInstance()->getCategory($this->parentCategoryID);
173 }
174
175 return $this->parentCategory;
176 }
177
178 /**
179 * Returns the parent categories of this category.
180 *
181 * @return Category[]
182 */
183 public function getParentCategories()
184 {
185 if ($this->parentCategories === null) {
186 $this->parentCategories = [];
187 $parentCategory = $this;
188 while ($parentCategory = $parentCategory->getParentCategory()) {
189 $this->parentCategories[] = $parentCategory;
190 }
191
192 $this->parentCategories = \array_reverse($this->parentCategories);
193 }
194
195 return $this->parentCategories;
196 }
197
198 /**
199 * Returns true if given category is a parent category of this category.
200 *
201 * @param Category $category
202 * @return bool
203 */
204 public function isParentCategory(self $category)
205 {
206 return \in_array($category, $this->getParentCategories());
207 }
208
209 /**
210 * @inheritDoc
211 */
212 public function getPermission($permission, ?User $user = null)
213 {
214 if ($user === null) {
215 $user = WCF::getUser();
216 }
217
218 if (!isset($this->userPermissions[$user->userID])) {
219 $this->userPermissions[$user->userID] = CategoryPermissionHandler::getInstance()
220 ->getPermissions($this, $user);
221
222 if ($user->userID == WCF::getUser()->userID) {
223 $this->permissions = $this->userPermissions[$user->userID];
224 }
225 }
226
227 if (isset($this->userPermissions[$user->userID][$permission])) {
228 return $this->userPermissions[$user->userID][$permission];
229 }
230
231 if ($this->getParentCategory()) {
232 return $this->getParentCategory()->getPermission($permission, $user);
233 }
234
235 if ($this->getObjectType()->defaultpermission !== null) {
236 return $this->getObjectType()->defaultpermission ? true : false;
237 }
238
239 return $this->defaultPermission;
240 }
241
242 /**
243 * @inheritDoc
244 */
245 public function getTitle()
246 {
247 return WCF::getLanguage()->get($this->title);
248 }
249
250 /**
251 * Returns the description of this category.
252 *
253 * @return string
254 */
255 public function getDescription()
256 {
257 if ($this->description) {
258 return WCF::getLanguage()->get($this->description);
259 }
260
261 return '';
262 }
263
264 /**
265 * @inheritDoc
266 */
267 protected function handleData($data)
268 {
269 // handle additional data
270 if (isset($data['additionalData'])) {
271 $data['additionalData'] = @\unserialize($data['additionalData']);
272 if (!\is_array($data['additionalData'])) {
273 $data['additionalData'] = [];
274 }
275 } else {
276 $data['additionalData'] = [];
277 }
278
279 parent::handleData($data);
280 }
281
282 /**
283 * @inheritDoc
284 */
285 public function __toString()
286 {
287 return $this->getTitle();
288 }
289 }