Subs-Categories.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. <?php
  2. /**
  3. * This file contains the functions to add, modify, remove, collapse and expand categories.
  4. *
  5. * Simple Machines Forum (SMF)
  6. *
  7. * @package SMF
  8. * @author Simple Machines http://www.simplemachines.org
  9. * @copyright 2014 Simple Machines and individual contributors
  10. * @license http://www.simplemachines.org/about/smf/license.php BSD
  11. *
  12. * @version 2.1 Alpha 1
  13. */
  14. if (!defined('SMF'))
  15. die('No direct access...');
  16. /**
  17. * Edit the position and properties of a category.
  18. * general function to modify the settings and position of a category.
  19. * used by ManageBoards.php to change the settings of a category.
  20. *
  21. * @param int $category_id
  22. * @param array $catOptions
  23. */
  24. function modifyCategory($category_id, $catOptions)
  25. {
  26. global $sourcedir, $smcFunc;
  27. $catUpdates = array();
  28. $catParameters = array();
  29. $cat_id = $category_id;
  30. call_integration_hook('integrate_pre_modify_category', array($cat_id, &$catOptions));
  31. // Wanna change the categories position?
  32. if (isset($catOptions['move_after']))
  33. {
  34. // Store all categories in the proper order.
  35. $cats = array();
  36. $cat_order = array();
  37. // Setting 'move_after' to '0' moves the category to the top.
  38. if ($catOptions['move_after'] == 0)
  39. $cats[] = $category_id;
  40. // Grab the categories sorted by cat_order.
  41. $request = $smcFunc['db_query']('', '
  42. SELECT id_cat, cat_order
  43. FROM {db_prefix}categories
  44. ORDER BY cat_order',
  45. array(
  46. )
  47. );
  48. while ($row = $smcFunc['db_fetch_assoc']($request))
  49. {
  50. if ($row['id_cat'] != $category_id)
  51. $cats[] = $row['id_cat'];
  52. if ($row['id_cat'] == $catOptions['move_after'])
  53. $cats[] = $category_id;
  54. $cat_order[$row['id_cat']] = $row['cat_order'];
  55. }
  56. $smcFunc['db_free_result']($request);
  57. // Set the new order for the categories.
  58. foreach ($cats as $index => $cat)
  59. if ($index != $cat_order[$cat])
  60. $smcFunc['db_query']('', '
  61. UPDATE {db_prefix}categories
  62. SET cat_order = {int:new_order}
  63. WHERE id_cat = {int:current_category}',
  64. array(
  65. 'new_order' => $index,
  66. 'current_category' => $cat,
  67. )
  68. );
  69. // If the category order changed, so did the board order.
  70. require_once($sourcedir . '/Subs-Boards.php');
  71. reorderBoards();
  72. }
  73. if (isset($catOptions['cat_name']))
  74. {
  75. $catUpdates[] = 'name = {string:cat_name}';
  76. $catParameters['cat_name'] = $catOptions['cat_name'];
  77. }
  78. if (isset($catOptions['cat_desc']))
  79. {
  80. $catUpdates[] = 'description = {string:cat_desc}';
  81. $catParameters['cat_desc'] = $catOptions['cat_desc'];
  82. }
  83. // Can a user collapse this category or is it too important?
  84. if (isset($catOptions['is_collapsible']))
  85. {
  86. $catUpdates[] = 'can_collapse = {int:is_collapsible}';
  87. $catParameters['is_collapsible'] = $catOptions['is_collapsible'] ? 1 : 0;
  88. }
  89. $cat_id = $category_id;
  90. call_integration_hook('integrate_modify_category', array($cat_id, &$catUpdates, &$catParameters));
  91. // Do the updates (if any).
  92. if (!empty($catUpdates))
  93. {
  94. $smcFunc['db_query']('', '
  95. UPDATE {db_prefix}categories
  96. SET
  97. ' . implode(',
  98. ', $catUpdates) . '
  99. WHERE id_cat = {int:current_category}',
  100. array_merge($catParameters, array(
  101. 'current_category' => $category_id,
  102. ))
  103. );
  104. if (empty($catOptions['dont_log']))
  105. logAction('edit_cat', array('catname' => isset($catOptions['cat_name']) ? $catOptions['cat_name'] : $category_id), 'admin');
  106. }
  107. }
  108. /**
  109. * Create a new category.
  110. * general function to create a new category and set its position.
  111. * allows (almost) the same options as the modifyCat() function.
  112. * returns the ID of the newly created category.
  113. *
  114. * @param array $catOptions
  115. */
  116. function createCategory($catOptions)
  117. {
  118. global $smcFunc;
  119. // Check required values.
  120. if (!isset($catOptions['cat_name']) || trim($catOptions['cat_name']) == '')
  121. trigger_error('createCategory(): A category name is required', E_USER_ERROR);
  122. // Set default values.
  123. if (!isset($catOptions['cat_desc']))
  124. $catOptions['cat_desc'] = '';
  125. if (!isset($catOptions['move_after']))
  126. $catOptions['move_after'] = 0;
  127. if (!isset($catOptions['is_collapsible']))
  128. $catOptions['is_collapsible'] = true;
  129. // Don't log an edit right after.
  130. $catOptions['dont_log'] = true;
  131. $cat_columns = array(
  132. 'name' => 'string-48',
  133. 'description' => 'string',
  134. );
  135. $cat_parameters = array(
  136. $catOptions['cat_name'],
  137. $catOptions['cat_desc'],
  138. );
  139. call_integration_hook('integrate_create_category', array(&$catOptions, &$cat_columns, &$cat_parameters));
  140. // Add the category to the database.
  141. $smcFunc['db_insert']('',
  142. '{db_prefix}categories',
  143. $cat_columns,
  144. $cat_parameters,
  145. array('id_cat')
  146. );
  147. // Grab the new category ID.
  148. $category_id = $smcFunc['db_insert_id']('{db_prefix}categories', 'id_cat');
  149. // Set the given properties to the newly created category.
  150. modifyCategory($category_id, $catOptions);
  151. logAction('add_cat', array('catname' => $catOptions['cat_name']), 'admin');
  152. // Return the database ID of the category.
  153. return $category_id;
  154. }
  155. /**
  156. * Remove one or more categories.
  157. * general function to delete one or more categories.
  158. * allows to move all boards in the categories to a different category before deleting them.
  159. * if moveChildrenTo is set to null, all boards inside the given categorieswill be deleted.
  160. * deletes all information that's associated with the given categories.
  161. * updates the statistics to reflect the new situation.
  162. *
  163. * @param string $categories
  164. * @param int $moveBoardsTo = null
  165. */
  166. function deleteCategories($categories, $moveBoardsTo = null)
  167. {
  168. global $sourcedir, $smcFunc, $cat_tree;
  169. require_once($sourcedir . '/Subs-Boards.php');
  170. getBoardTree();
  171. call_integration_hook('integrate_delete_category', array($categories, &$moveBoardsTo));
  172. // With no category set to move the boards to, delete them all.
  173. if ($moveBoardsTo === null)
  174. {
  175. $request = $smcFunc['db_query']('', '
  176. SELECT id_board
  177. FROM {db_prefix}boards
  178. WHERE id_cat IN ({array_int:category_list})',
  179. array(
  180. 'category_list' => $categories,
  181. )
  182. );
  183. $boards_inside = array();
  184. while ($row = $smcFunc['db_fetch_assoc']($request))
  185. $boards_inside[] = $row['id_board'];
  186. $smcFunc['db_free_result']($request);
  187. if (!empty($boards_inside))
  188. deleteBoards($boards_inside, null);
  189. }
  190. // Make sure the safe category is really safe.
  191. elseif (in_array($moveBoardsTo, $categories))
  192. trigger_error('deleteCategories(): You cannot move the boards to a category that\'s being deleted', E_USER_ERROR);
  193. // Move the boards inside the categories to a safe category.
  194. else
  195. $smcFunc['db_query']('', '
  196. UPDATE {db_prefix}boards
  197. SET id_cat = {int:new_parent_cat}
  198. WHERE id_cat IN ({array_int:category_list})',
  199. array(
  200. 'category_list' => $categories,
  201. 'new_parent_cat' => $moveBoardsTo,
  202. )
  203. );
  204. // Noone will ever be able to collapse these categories anymore.
  205. $smcFunc['db_query']('', '
  206. DELETE FROM {db_prefix}collapsed_categories
  207. WHERE id_cat IN ({array_int:category_list})',
  208. array(
  209. 'category_list' => $categories,
  210. )
  211. );
  212. // Do the deletion of the category itself
  213. $smcFunc['db_query']('', '
  214. DELETE FROM {db_prefix}categories
  215. WHERE id_cat IN ({array_int:category_list})',
  216. array(
  217. 'category_list' => $categories,
  218. )
  219. );
  220. // Log what we've done.
  221. foreach ($categories as $category)
  222. logAction('delete_cat', array('catname' => $cat_tree[$category]['node']['name']), 'admin');
  223. // Get all boards back into the right order.
  224. reorderBoards();
  225. }
  226. /**
  227. * Collapse, expand or toggle one or more categories for one or more members.
  228. * if members is null, the category is collapsed/expanded for all members.
  229. * allows three changes to the status: 'expand', 'collapse' and 'toggle'.
  230. * if check_collapsable is set, only category allowed to be collapsed, will be collapsed.
  231. *
  232. * @param array $categories
  233. * @param string $new_status
  234. * @param array $members = null
  235. * @param bool $check_collapsable = true
  236. */
  237. function collapseCategories($categories, $new_status, $members = null, $check_collapsable = true)
  238. {
  239. global $smcFunc;
  240. // Collapse or expand the categories.
  241. if ($new_status === 'collapse' || $new_status === 'expand')
  242. {
  243. $smcFunc['db_query']('', '
  244. DELETE FROM {db_prefix}collapsed_categories
  245. WHERE id_cat IN ({array_int:category_list})' . ($members === null ? '' : '
  246. AND id_member IN ({array_int:member_list})'),
  247. array(
  248. 'category_list' => $categories,
  249. 'member_list' => $members,
  250. )
  251. );
  252. if ($new_status === 'collapse')
  253. $smcFunc['db_query']('', '
  254. INSERT INTO {db_prefix}collapsed_categories
  255. (id_cat, id_member)
  256. SELECT c.id_cat, mem.id_member
  257. FROM {db_prefix}categories AS c
  258. INNER JOIN {db_prefix}members AS mem ON (' . ($members === null ? '1=1' : '
  259. mem.id_member IN ({array_int:member_list})') . ')
  260. WHERE c.id_cat IN ({array_int:category_list})' . ($check_collapsable ? '
  261. AND c.can_collapse = {int:is_collapsible}' : ''),
  262. array(
  263. 'member_list' => $members,
  264. 'category_list' => $categories,
  265. 'is_collapsible' => 1,
  266. )
  267. );
  268. }
  269. // Toggle the categories: collapsed get expanded and expanded get collapsed.
  270. elseif ($new_status === 'toggle')
  271. {
  272. // Get the current state of the categories.
  273. $updates = array(
  274. 'insert' => array(),
  275. 'remove' => array(),
  276. );
  277. $request = $smcFunc['db_query']('', '
  278. SELECT mem.id_member, c.id_cat, IFNULL(cc.id_cat, 0) AS is_collapsed, c.can_collapse
  279. FROM {db_prefix}members AS mem
  280. INNER JOIN {db_prefix}categories AS c ON (c.id_cat IN ({array_int:category_list}))
  281. LEFT JOIN {db_prefix}collapsed_categories AS cc ON (cc.id_cat = c.id_cat AND cc.id_member = mem.id_member)
  282. ' . ($members === null ? '' : '
  283. WHERE mem.id_member IN ({array_int:member_list})'),
  284. array(
  285. 'category_list' => $categories,
  286. 'member_list' => $members,
  287. )
  288. );
  289. while ($row = $smcFunc['db_fetch_assoc']($request))
  290. {
  291. if (empty($row['is_collapsed']) && (!empty($row['can_collapse']) || !$check_collapsable))
  292. $updates['insert'][] = array($row['id_member'], $row['id_cat']);
  293. elseif (!empty($row['is_collapsed']))
  294. $updates['remove'][] = '(id_member = ' . $row['id_member'] . ' AND id_cat = ' . $row['id_cat'] . ')';
  295. }
  296. $smcFunc['db_free_result']($request);
  297. // Collapse the ones that were originally expanded...
  298. if (!empty($updates['insert']))
  299. $smcFunc['db_insert']('replace',
  300. '{db_prefix}collapsed_categories',
  301. array(
  302. 'id_cat' => 'int', 'id_member' => 'int',
  303. ),
  304. $updates['insert'],
  305. array('id_cat', 'id_member')
  306. );
  307. // And expand the ones that were originally collapsed.
  308. if (!empty($updates['remove']))
  309. $smcFunc['db_query']('', '
  310. DELETE FROM {db_prefix}collapsed_categories
  311. WHERE ' . implode(' OR ', $updates['remove']),
  312. array(
  313. )
  314. );
  315. }
  316. }
  317. ?>