1 <?php
2
3 4 5 6 7
8 class rex_category_service
9 {
10 11 12 13 14 15 16 17 18 19
20 public static function addCategory($category_id, array $data)
21 {
22 $message = '';
23
24 if (!is_array($data)) {
25 throw new rex_api_exception('Expecting $data to be an array!');
26 }
27
28 self::reqKey($data, 'catpriority');
29 self::reqKey($data, 'catname');
30
31
32 $parent = rex_category::get($category_id);
33 if ($parent) {
34 $path = $parent->getPath();
35 $path .= $parent->getId() . '|';
36 } else {
37 $path = '|';
38 }
39
40 if ($data['catpriority'] <= 0) {
41 $data['catpriority'] = 1;
42 }
43
44 if (!isset($data['name'])) {
45 $data['name'] = $data['catname'];
46 }
47
48 if (!isset($data['status'])) {
49 $data['status'] = 0;
50 }
51
52 $contentAvailable = rex_plugin::get('structure', 'content')->isAvailable();
53 if ($contentAvailable) {
54 $startpageTemplates = [];
55 if ($category_id != '') {
56
57 $sql = rex_sql::factory();
58
59 $sql->setQuery('select clang_id,template_id from ' . rex::getTablePrefix() . 'article where id=? and startarticle=1', [$category_id]);
60 for ($i = 0; $i < $sql->getRows(); $i++, $sql->next()) {
61 $startpageTemplates[$sql->getValue('clang_id')] = $sql->getValue('template_id');
62 }
63 }
64
65
66 $templates = rex_template::getTemplatesForCategory($category_id);
67 }
68
69 $user = self::getUser();
70
71
72 $AART = rex_sql::factory();
73 foreach (rex_clang::getAllIds() as $key) {
74 if ($contentAvailable) {
75 $template_id = rex_template::getDefaultId();
76 if (isset($startpageTemplates[$key]) && $startpageTemplates[$key] != '') {
77 $template_id = $startpageTemplates[$key];
78 }
79
80
81
82 if (!isset($templates[$template_id])) {
83 $template_id = 0;
84 if (count($templates) > 0) {
85 $template_id = key($templates);
86 }
87 }
88 }
89
90 $AART->setTable(rex::getTablePrefix() . 'article');
91 if (!isset($id)) {
92 $id = $AART->setNewId('id');
93 } else {
94 $AART->setValue('id', $id);
95 }
96
97 $AART->setValue('clang_id', $key);
98 $AART->setValue('template_id', $template_id);
99 $AART->setValue('name', $data['name']);
100 $AART->setValue('catname', $data['catname']);
101 $AART->setValue('catpriority', $data['catpriority']);
102 $AART->setValue('parent_id', $category_id);
103 $AART->setValue('priority', 1);
104 $AART->setValue('path', $path);
105 $AART->setValue('startarticle', 1);
106 $AART->setValue('status', $data['status']);
107 $AART->addGlobalUpdateFields($user);
108 $AART->addGlobalCreateFields($user);
109
110 try {
111 $AART->insert();
112
113
114 if (isset($data['catpriority'])) {
115 self::newCatPrio($category_id, $key, 0, $data['catpriority']);
116 }
117
118 $message = rex_i18n::msg('category_added_and_startarticle_created');
119
120 rex_article_cache::delete($id, $key);
121
122
123
124 $message = rex_extension::registerPoint(new rex_extension_point('CAT_ADDED', $message, [
125 'category' => clone $AART,
126 'id' => $id,
127 'parent_id' => $category_id,
128 'clang' => $key,
129 'name' => $data['catname'],
130 'priority' => $data['catpriority'],
131 'path' => $path,
132 'status' => $data['status'],
133 'article' => clone $AART,
134 'data' => $data,
135 ]));
136 } catch (rex_sql_exception $e) {
137 throw new rex_api_exception($e);
138 }
139 }
140
141 return $message;
142 }
143
144 145 146 147 148 149 150 151 152 153 154
155 public static function editCategory($category_id, $clang, array $data)
156 {
157 if (!is_array($data)) {
158 throw new rex_api_exception('Expecting $data to be an array!');
159 }
160
161
162 $thisCat = rex_sql::factory();
163 $thisCat->setQuery('SELECT * FROM ' . rex::getTablePrefix() . 'article WHERE startarticle=1 and id=? and clang_id=?', [$category_id, $clang]);
164
165
166 $EKAT = rex_sql::factory();
167 $EKAT->setTable(rex::getTablePrefix() . 'article');
168 $EKAT->setWhere(['id' => $category_id, 'startarticle' => 1, 'clang_id' => $clang]);
169
170 if (isset($data['catname'])) {
171 $EKAT->setValue('catname', $data['catname']);
172 }
173 if (isset($data['catpriority'])) {
174 $EKAT->setValue('catpriority', $data['catpriority']);
175 }
176
177 $user = self::getUser();
178
179 $EKAT->addGlobalUpdateFields($user);
180
181 try {
182 $EKAT->update();
183
184
185 if (isset($data['catname'])) {
186 $ArtSql = rex_sql::factory();
187 $ArtSql->setQuery('SELECT id FROM ' . rex::getTablePrefix() . 'article WHERE parent_id=? AND startarticle=0 AND clang_id=?', [$category_id, $clang]);
188
189 $EART = rex_sql::factory();
190 for ($i = 0; $i < $ArtSql->getRows(); ++$i) {
191 $EART->setTable(rex::getTablePrefix() . 'article');
192 $EART->setWhere(['id' => $ArtSql->getValue('id'), 'startarticle' => '0', 'clang_id' => $clang]);
193 $EART->setValue('catname', $data['catname']);
194 $EART->addGlobalUpdateFields($user);
195
196 $EART->update();
197 rex_article_cache::delete($ArtSql->getValue('id'), $clang);
198
199 $ArtSql->next();
200 }
201 }
202
203
204 if (isset($data['catpriority'])) {
205 $parent_id = $thisCat->getValue('parent_id');
206 $old_prio = $thisCat->getValue('catpriority');
207
208 if ($data['catpriority'] <= 0) {
209 $data['catpriority'] = 1;
210 }
211
212 rex_sql::factory()
213 ->setTable(rex::getTable('article'))
214 ->setWhere('id = :id AND clang_id != :clang', ['id' => $category_id, 'clang' => $clang])
215 ->setValue('catpriority', $data['catpriority'])
216 ->addGlobalUpdateFields($user)
217 ->update();
218
219 foreach (rex_clang::getAllIds() as $clangId) {
220 self::newCatPrio($parent_id, $clangId, $data['catpriority'], $old_prio);
221 }
222 }
223
224 $message = rex_i18n::msg('category_updated');
225
226 rex_article_cache::delete($category_id);
227
228
229
230 $message = rex_extension::registerPoint(new rex_extension_point('CAT_UPDATED', $message, [
231 'id' => $category_id,
232
233 'category' => clone $EKAT,
234 'category_old' => clone $thisCat,
235 'article' => clone $EKAT,
236
237 'parent_id' => $thisCat->getValue('parent_id'),
238 'clang' => $clang,
239 'name' => isset($data['catname']) ? $data['catname'] : $thisCat->getValue('catname'),
240 'priority' => isset($data['catpriority']) ? $data['catpriority'] : $thisCat->getValue('catpriority'),
241 'path' => $thisCat->getValue('path'),
242 'status' => $thisCat->getValue('status'),
243
244 'data' => $data,
245 ]));
246 } catch (rex_sql_exception $e) {
247 throw new rex_api_exception($e);
248 }
249
250 return $message;
251 }
252
253 254 255 256 257 258 259 260 261
262 public static function deleteCategory($category_id)
263 {
264 $clang = 1;
265
266 $thisCat = rex_sql::factory();
267 $thisCat->setQuery('SELECT * FROM ' . rex::getTablePrefix() . 'article WHERE id=? and clang_id=?', [$category_id, $clang]);
268
269
270 if ($thisCat->getRows() == 1) {
271 $KAT = rex_sql::factory();
272 $KAT->setQuery('select * from ' . rex::getTablePrefix() . 'article where parent_id=? and clang_id=? and startarticle=1', [$category_id, $clang]);
273
274 if ($KAT->getRows() == 0) {
275 $KAT->setQuery('select * from ' . rex::getTablePrefix() . 'article where parent_id=? and clang_id=? and startarticle=0', [$category_id, $clang]);
276
277 if ($KAT->getRows() == 0) {
278 $thisCat = rex_sql::factory();
279 $thisCat->setQuery('SELECT * FROM ' . rex::getTablePrefix() . 'article WHERE id=?', [$category_id]);
280
281 $parent_id = $thisCat->getValue('parent_id');
282 $message = rex_article_service::_deleteArticle($category_id);
283
284 foreach ($thisCat as $row) {
285 $_clang = $row->getValue('clang_id');
286
287
288 self::newCatPrio($parent_id, $_clang, 0, 1);
289
290
291 $message = rex_extension::registerPoint(new rex_extension_point('CAT_DELETED', $message, [
292 'id' => $category_id,
293 'parent_id' => $parent_id,
294 'clang' => $_clang,
295 'name' => $row->getValue('catname'),
296 'priority' => $row->getValue('catpriority'),
297 'path' => $row->getValue('path'),
298 'status' => $row->getValue('status'),
299 ]));
300 }
301
302 rex_complex_perm::removeItem('structure', $category_id);
303 } else {
304 throw new rex_api_exception(rex_i18n::msg('category_could_not_be_deleted') . ' ' . rex_i18n::msg('category_still_contains_articles'));
305 }
306 } else {
307 throw new rex_api_exception(rex_i18n::msg('category_could_not_be_deleted') . ' ' . rex_i18n::msg('category_still_contains_subcategories'));
308 }
309 } else {
310 throw new rex_api_exception(rex_i18n::msg('category_could_not_be_deleted'));
311 }
312
313 return $message;
314 }
315
316 317 318 319 320 321 322 323 324 325 326
327 public static function categoryStatus($category_id, $clang, $status = null)
328 {
329 $KAT = rex_sql::factory();
330 $KAT->setQuery('select * from ' . rex::getTablePrefix() . 'article where id=? and clang_id=? and startarticle=1', [$category_id, $clang]);
331 if ($KAT->getRows() == 1) {
332
333
334 if (!$status) {
335 $newstatus = self::nextStatus($KAT->getValue('status'));
336 } else {
337 $newstatus = $status;
338 }
339
340 $EKAT = rex_sql::factory();
341 $EKAT->setTable(rex::getTablePrefix() . 'article');
342 $EKAT->setWhere(['id' => $category_id, 'clang_id' => $clang, 'startarticle' => 1]);
343 $EKAT->setValue('status', $newstatus);
344 $EKAT->addGlobalCreateFields(self::getUser());
345
346 try {
347 $EKAT->update();
348
349 rex_article_cache::delete($category_id, $clang);
350
351
352 rex_extension::registerPoint(new rex_extension_point('CAT_STATUS', null, [
353 'id' => $category_id,
354 'clang' => $clang,
355 'status' => $newstatus,
356 ]));
357 } catch (rex_sql_exception $e) {
358 throw new rex_api_exception($e);
359 }
360 } else {
361 throw new rex_api_exception(rex_i18n::msg('no_such_category'));
362 }
363
364 return $newstatus;
365 }
366
367 368 369 370 371
372 public static function statusTypes()
373 {
374 static $catStatusTypes;
375
376 if (!$catStatusTypes) {
377 $catStatusTypes = [
378
379 [rex_i18n::msg('status_offline'), 'rex-offline', 'rex-icon-offline'],
380 [rex_i18n::msg('status_online'), 'rex-online', 'rex-icon-online'],
381 ];
382
383
384 $catStatusTypes = rex_extension::registerPoint(new rex_extension_point('CAT_STATUS_TYPES', $catStatusTypes));
385 }
386
387 return $catStatusTypes;
388 }
389
390 public static function nextStatus($currentStatus)
391 {
392 $catStatusTypes = self::statusTypes();
393 return ($currentStatus + 1) % count($catStatusTypes);
394 }
395
396 public static function prevStatus($currentStatus)
397 {
398 $catStatusTypes = self::statusTypes();
399 if (($currentStatus - 1) < 0) {
400 return count($catStatusTypes) - 1;
401 }
402
403 return ($currentStatus - 1) % count($catStatusTypes);
404 }
405
406 407 408 409 410 411
412 public static function copyCategory($from_cat, $to_cat)
413 {
414
415 }
416
417 418 419 420 421 422 423 424
425 public static function newCatPrio($parent_id, $clang, $new_prio, $old_prio)
426 {
427 if ($new_prio != $old_prio) {
428 if ($new_prio < $old_prio) {
429 $addsql = 'desc';
430 } else {
431 $addsql = 'asc';
432 }
433
434 rex_sql_util::organizePriorities(
435 rex::getTable('article'),
436 'catpriority',
437 'clang_id=' . (int) $clang . ' AND parent_id=' . (int) $parent_id . ' AND startarticle=1',
438 'catpriority,updatedate ' . $addsql
439 );
440
441 rex_article_cache::deleteLists($parent_id);
442 }
443 }
444
445 446 447 448 449 450 451 452
453 public static function moveCategory($from_cat, $to_cat)
454 {
455 $from_cat = (int) $from_cat;
456 $to_cat = (int) $to_cat;
457
458 if ($from_cat == $to_cat) {
459
460 return false;
461 }
462
463
464
465 $fcat = rex_sql::factory();
466 $fcat->setQuery('select * from ' . rex::getTablePrefix() . 'article where startarticle=1 and id=? and clang_id=?', [$from_cat, rex_clang::getStartId()]);
467
468 $tcat = rex_sql::factory();
469 $tcat->setQuery('select * from ' . rex::getTablePrefix() . 'article where startarticle=1 and id=? and clang_id=?', [$to_cat, rex_clang::getStartId()]);
470
471 if ($fcat->getRows() != 1 || ($tcat->getRows() != 1 && $to_cat != 0)) {
472
473 return false;
474 }
475 if ($to_cat > 0) {
476 $tcats = explode('|', $tcat->getValue('path'));
477 if (in_array($from_cat, $tcats)) {
478
479 return false;
480 }
481 }
482
483
484 $RC = [];
485 $RC[$fcat->getValue('parent_id')] = 1;
486 $RC[$from_cat] = 1;
487 $RC[$to_cat] = 1;
488
489 if ($to_cat > 0) {
490 $to_path = $tcat->getValue('path') . $to_cat . '|';
491 } else {
492 $to_path = '|';
493 }
494
495 $from_path = $fcat->getValue('path') . $from_cat . '|';
496
497 $gcats = rex_sql::factory();
498
499 $gcats->setQuery('select * from ' . rex::getTablePrefix() . 'article where path like ? and clang_id=?', [$from_path . '%', rex_clang::getStartId()]);
500
501 $up = rex_sql::factory();
502
503 for ($i = 0; $i < $gcats->getRows(); ++$i) {
504
505 $new_path = $to_path . $from_cat . '|' . str_replace($from_path, '', $gcats->getValue('path'));
506 $icid = $gcats->getValue('id');
507
508
509 $up->setTable(rex::getTablePrefix() . 'article');
510 $up->setWhere(['id' => $icid]);
511 $up->setValue('path', $new_path);
512 $up->update();
513
514
515 $RC[$icid] = 1;
516
517 $gcats->next();
518 }
519
520
521 $gmax = rex_sql::factory();
522 $up = rex_sql::factory();
523
524 foreach (rex_clang::getAllIds() as $clang) {
525 $gmax->setQuery('select max(catpriority) from ' . rex::getTablePrefix() . 'article where parent_id=? and clang_id=?', [$to_cat, $clang]);
526 $catpriority = (int) $gmax->getValue('max(catpriority)');
527 $up->setTable(rex::getTablePrefix() . 'article');
528 $up->setWhere(['id' => $from_cat, 'clang_id' => $clang]);
529 $up->setValue('path', $to_path);
530 $up->setValue('parent_id', $to_cat);
531 $up->setValue('catpriority', ($catpriority + 1));
532 $up->update();
533 }
534
535
536 foreach ($RC as $id => $key) {
537 rex_article_cache::delete($id);
538 }
539
540 foreach (rex_clang::getAllIds() as $clang) {
541 self::newCatPrio($fcat->getValue('parent_id'), $clang, 0, 1);
542
543 rex_extension::registerPoint(new rex_extension_point('CAT_MOVED', null, [
544 'id' => $from_cat,
545 'clang_id' => $clang,
546 'category_id' => $to_cat,
547 ]));
548 }
549
550 return true;
551 }
552
553 554 555 556 557 558 559 560
561 protected static function reqKey(array $array, $keyName)
562 {
563 if (!isset($array[$keyName])) {
564 throw new rex_api_exception('Missing required parameter "' . $keyName . '"!');
565 }
566 }
567
568 private static function getUser()
569 {
570 if (rex::getUser()) {
571 return rex::getUser()->getLogin();
572 }
573
574 if (method_exists(rex::class, 'getEnvironment')) {
575 return rex::getEnvironment();
576 }
577
578 return 'frontend';
579 }
580 }
581