Added separate context class for forum stuff and split up handling of each object type.

This commit is contained in:
flash 2023-09-08 13:22:46 +00:00
parent c68279add9
commit 163da8b213
24 changed files with 1853 additions and 1714 deletions

View file

@ -104,7 +104,10 @@ while(!$restricted && !empty($register)) {
$users->addRoles($userInfo, $defaultRoleInfo);
$config->setString('users.newest', $userInfo->getId());
$msz->getPerms()->precalculatePermissions($msz->getForum(), [$userInfo->getId()]);
$msz->getPerms()->precalculatePermissions(
$msz->getForumContext()->getCategories(),
[$userInfo->getId()]
);
url_redirect('auth-login-welcome', ['username' => $userInfo->getName()]);
return;

View file

@ -4,13 +4,16 @@ namespace Misuzu;
use stdClass;
use RuntimeException;
$forum = $msz->getForum();
$forumCtx = $msz->getForumContext();
$forumCategories = $forumCtx->getCategories();
$forumTopics = $forumCtx->getTopics();
$forumPosts = $forumCtx->getPosts();
$usersCtx = $msz->getUsersContext();
$categoryId = (int)filter_input(INPUT_GET, 'f', FILTER_SANITIZE_NUMBER_INT);
try {
$categoryInfo = $forum->getCategory(categoryId: $categoryId);
$categoryInfo = $forumCategories->getCategory(categoryId: $categoryId);
} catch(RuntimeException $ex) {
Template::throwError(404);
}
@ -29,7 +32,7 @@ if($usersCtx->hasActiveBan($currentUser))
if($categoryInfo->isLink()) {
if($categoryInfo->hasLinkTarget()) {
$forum->incrementCategoryClicks($categoryInfo);
$forumCategories->incrementCategoryClicks($categoryInfo);
redirect($categoryInfo->getLinkTarget());
return;
}
@ -37,7 +40,7 @@ if($categoryInfo->isLink()) {
Template::throwError(404);
}
$forumPagination = new Pagination($forum->countTopics(
$forumPagination = new Pagination($forumTopics->countTopics(
categoryInfo: $categoryInfo,
global: true,
deleted: $perms->check(Perm::F_POST_DELETE_ANY) ? null : false
@ -50,7 +53,7 @@ $children = [];
$topics = [];
if($categoryInfo->mayHaveChildren()) {
$children = $forum->getCategoryChildren($categoryInfo, hidden: false, asTree: true);
$children = $forumCategories->getCategoryChildren($categoryInfo, hidden: false, asTree: true);
foreach($children as $childId => $child) {
$childPerms = $authInfo->getPerms('forum', $child->info);
@ -79,7 +82,7 @@ if($categoryInfo->mayHaveChildren()) {
$catIds[] = $greatGrandChildId;
}
$grandChildUnread = $forum->checkCategoryUnread($catIds, $currentUser);
$grandChildUnread = $forumCategories->checkCategoryUnread($catIds, $currentUser);
if($grandChildUnread)
$childUnread = true;
}
@ -98,7 +101,7 @@ if($categoryInfo->mayHaveChildren()) {
}
try {
$lastPostInfo = $forum->getPost(categoryInfos: $catIds, getLast: true, deleted: false);
$lastPostInfo = $forumPosts->getPost(categoryInfos: $catIds, getLast: true, deleted: false);
} catch(RuntimeException $ex) {
$lastPostInfo = null;
}
@ -106,7 +109,7 @@ if($categoryInfo->mayHaveChildren()) {
if($lastPostInfo !== null) {
$child->lastPost = new stdClass;
$child->lastPost->info = $lastPostInfo;
$child->lastPost->topicInfo = $forum->getTopic(postInfo: $lastPostInfo);
$child->lastPost->topicInfo = $forumTopics->getTopic(postInfo: $lastPostInfo);
if($lastPostInfo->hasUserId()) {
$child->lastPost->user = $usersCtx->getUserInfo($lastPostInfo->getUserId());
@ -116,7 +119,7 @@ if($categoryInfo->mayHaveChildren()) {
}
if($child->info->mayHaveTopics() && !$childUnread)
$childUnread = $forum->checkCategoryUnread($child->info, $currentUser);
$childUnread = $forumCategories->checkCategoryUnread($child->info, $currentUser);
$child->perms = $childPerms;
$child->unread = $childUnread;
@ -124,7 +127,7 @@ if($categoryInfo->mayHaveChildren()) {
}
if($categoryInfo->mayHaveTopics()) {
$topicInfos = $forum->getTopics(
$topicInfos = $forumTopics->getTopics(
categoryInfo: $categoryInfo,
global: true,
deleted: $perms->check(Perm::F_POST_DELETE_ANY) ? null : false,
@ -134,8 +137,8 @@ if($categoryInfo->mayHaveTopics()) {
foreach($topicInfos as $topicInfo) {
$topics[] = $topic = new stdClass;
$topic->info = $topicInfo;
$topic->unread = $forum->checkTopicUnread($topicInfo, $currentUser);
$topic->participated = $forum->checkTopicParticipated($topicInfo, $currentUser);
$topic->unread = $forumTopics->checkTopicUnread($topicInfo, $currentUser);
$topic->participated = $forumTopics->checkTopicParticipated($topicInfo, $currentUser);
$topic->lastPost = new stdClass;
if($topicInfo->hasUserId()) {
@ -144,7 +147,7 @@ if($categoryInfo->mayHaveTopics()) {
}
try {
$topic->lastPost->info = $lastPostInfo = $forum->getPost(
$topic->lastPost->info = $lastPostInfo = $forumPosts->getPost(
topicInfo: $topicInfo,
getLast: true,
deleted: $topicInfo->isDeleted() ? null : false,
@ -163,8 +166,8 @@ $perms = $perms->checkMany([
]);
Template::render('forum.forum', [
'forum_breadcrumbs' => $forum->getCategoryAncestry($categoryInfo),
'global_accent_colour' => $forum->getCategoryColour($categoryInfo),
'forum_breadcrumbs' => $forumCategories->getCategoryAncestry($categoryInfo),
'global_accent_colour' => $forumCategories->getCategoryColour($categoryInfo),
'forum_info' => $categoryInfo,
'forum_children' => $children,
'forum_topics' => $topics,

View file

@ -4,7 +4,10 @@ namespace Misuzu;
use stdClass;
use RuntimeException;
$forum = $msz->getForum();
$forumCtx = $msz->getForumContext();
$forumCategories = $forumCtx->getCategories();
$forumTopics = $forumCtx->getTopics();
$forumPosts = $forumCtx->getPosts();
$usersCtx = $msz->getUsersContext();
$mode = (string)filter_input(INPUT_GET, 'm');
@ -20,13 +23,13 @@ if($mode === 'mark') {
if($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
$categoryInfos = $categoryId === null
? $forum->getCategories()
: $forum->getCategoryChildren(parentInfo: $categoryId, includeSelf: true);
? $forumCategories->getCategories()
: $forumCategories->getCategoryChildren(parentInfo: $categoryId, includeSelf: true);
foreach($categoryInfos as $categoryInfo) {
$perms = $authInfo->getPerms('forum', $categoryInfo);
if($perms->check(Perm::F_CATEGORY_LIST))
$forum->updateUserReadCategory($userInfo, $categoryInfo);
$forumCategories->updateUserReadCategory($userInfo, $categoryInfo);
}
url_redirect($categoryId ? 'forum-category' : 'forum-index', ['forum' => $categoryId]);
@ -47,7 +50,7 @@ if($mode === 'mark') {
if($mode !== '')
Template::throwError(404);
$categories = $forum->getCategories(hidden: false, asTree: true);
$categories = $forumCategories->getCategories(hidden: false, asTree: true);
foreach($categories as $categoryId => $category) {
$perms = $authInfo->getPerms('forum', $category->info);
@ -87,7 +90,7 @@ foreach($categories as $categoryId => $category) {
$catIds[] = $greatGrandChildId;
}
$grandChildUnread = $forum->checkCategoryUnread($catIds, $currentUser);
$grandChildUnread = $forumCategories->checkCategoryUnread($catIds, $currentUser);
if($grandChildUnread)
$childUnread = true;
}
@ -106,7 +109,7 @@ foreach($categories as $categoryId => $category) {
}
try {
$lastPostInfo = $forum->getPost(categoryInfos: $catIds, getLast: true, deleted: false);
$lastPostInfo = $forumPosts->getPost(categoryInfos: $catIds, getLast: true, deleted: false);
} catch(RuntimeException $ex) {
$lastPostInfo = null;
}
@ -114,7 +117,7 @@ foreach($categories as $categoryId => $category) {
if($lastPostInfo !== null) {
$child->lastPost = new stdClass;
$child->lastPost->info = $lastPostInfo;
$child->lastPost->topicInfo = $forum->getTopic(postInfo: $lastPostInfo);
$child->lastPost->topicInfo = $forumTopics->getTopic(postInfo: $lastPostInfo);
if($lastPostInfo->hasUserId()) {
$child->lastPost->user = $usersCtx->getUserInfo($lastPostInfo->getUserId());
@ -125,7 +128,7 @@ foreach($categories as $categoryId => $category) {
}
if($child->info->mayHaveTopics() && !$childUnread) {
$childUnread = $forum->checkCategoryUnread($child->info, $currentUser);
$childUnread = $forumCategories->checkCategoryUnread($child->info, $currentUser);
if($childUnread)
$unread = true;
}
@ -135,7 +138,7 @@ foreach($categories as $categoryId => $category) {
}
if($category->info->mayHaveTopics() && !$unread)
$unread = $forum->checkCategoryUnread($category->info, $currentUser);
$unread = $forumCategories->checkCategoryUnread($category->info, $currentUser);
if(!$category->info->isListing()) {
if(!array_key_exists('0', $categories)) {
@ -159,7 +162,7 @@ foreach($categories as $categoryId => $category) {
}
try {
$lastPostInfo = $forum->getPost(categoryInfos: $catIds, getLast: true, deleted: false);
$lastPostInfo = $forumPosts->getPost(categoryInfos: $catIds, getLast: true, deleted: false);
} catch(RuntimeException $ex) {
$lastPostInfo = null;
}
@ -167,7 +170,7 @@ foreach($categories as $categoryId => $category) {
if($lastPostInfo !== null) {
$category->lastPost = new stdClass;
$category->lastPost->info = $lastPostInfo;
$category->lastPost->topicInfo = $forum->getTopic(postInfo: $lastPostInfo);
$category->lastPost->topicInfo = $forumTopics->getTopic(postInfo: $lastPostInfo);
if($lastPostInfo->hasUserId()) {
$category->lastPost->user = $usersCtx->getUserInfo($lastPostInfo->getUserId());

View file

@ -6,7 +6,7 @@ use RuntimeException;
if(!$msz->getAuthInfo()->getPerms('global')->check(Perm::G_FORUM_LEADERBOARD_VIEW))
Template::throwError(403);
$forum = $msz->getForum();
$forumCtx = $msz->getForumContext();
$usersCtx = $msz->getUsersContext();
$config = $cfg->getValues([
['forum_leader.first_year:i', 2018],
@ -61,7 +61,7 @@ for($i = $currentYear, $j = $currentMonth;;) {
break;
}
$rankings = $forum->generatePostRankings($year, $month, $unrankedForums, $unrankedTopics);
$rankings = $forumCtx->getPosts()->generatePostRankings($year, $month, $unrankedForums, $unrankedTopics);
foreach($rankings as $ranking) {
$ranking->user = $ranking->colour = null;

View file

@ -3,7 +3,8 @@ namespace Misuzu;
use RuntimeException;
$forum = $msz->getForum();
$forumCtx = $msz->getForumContext();
$forumPosts = $forumCtx->getPosts();
$usersCtx = $msz->getUsersContext();
$postId = !empty($_GET['p']) && is_string($_GET['p']) ? (int)$_GET['p'] : 0;
@ -23,7 +24,7 @@ if($postMode !== '' && $usersCtx->hasActiveBan($currentUser))
Template::displayInfo('You have been banned, check your profile for more information.', 403);
try {
$postInfo = $forum->getPost(postId: $postId);
$postInfo = $forumPosts->getPost(postId: $postId);
} catch(RuntimeException $ex) {
Template::throwError(404);
}
@ -56,7 +57,7 @@ switch($postMode) {
Template::displayInfo('This post has existed for too long. Ask a moderator to remove if it absolutely necessary.', 403);
}
$originalPostInfo = $forum->getPost(topicInfo: $postInfo->getTopicId());
$originalPostInfo = $forumPosts->getPost(topicInfo: $postInfo->getTopicId());
if($originalPostInfo->getId() === $postInfo->getId())
Template::displayInfo('This is the opening post of the topic it belongs to, it may not be deleted without deleting the entire topic as well.', 403);
@ -79,7 +80,7 @@ switch($postMode) {
break;
}
$forum->deletePost($postInfo);
$forumPosts->deletePost($postInfo);
$msz->createAuditLog('FORUM_POST_DELETE', [$postInfo->getId()]);
url_redirect('forum-topic', ['topic' => $postInfo->getTopicId()]);
@ -108,7 +109,7 @@ switch($postMode) {
break;
}
$forum->nukePost($postInfo->getId());
$forumPosts->nukePost($postInfo->getId());
$msz->createAuditLog('FORUM_POST_NUKE', [$postInfo->getId()]);
url_redirect('forum-topic', ['topic' => $postInfo->getTopicId()]);
@ -137,7 +138,7 @@ switch($postMode) {
break;
}
$forum->restorePost($postInfo->getId());
$forumPosts->restorePost($postInfo->getId());
$msz->createAuditLog('FORUM_POST_RESTORE', [$postInfo->getId()]);
url_redirect('forum-topic', ['topic' => $postInfo->getTopicId()]);

View file

@ -11,7 +11,10 @@ $authInfo = $msz->getAuthInfo();
if(!$authInfo->isLoggedIn())
Template::throwError(401);
$forum = $msz->getForum();
$forumCtx = $msz->getForumContext();
$forumCategories = $forumCtx->getCategories();
$forumTopics = $forumCtx->getTopics();
$forumPosts = $forumCtx->getPosts();
$usersCtx = $msz->getUsersContext();
$currentUser = $authInfo->getUserInfo();
@ -19,8 +22,6 @@ $currentUserId = $currentUser->getId();
if($usersCtx->hasActiveBan($currentUser))
Template::throwError(403);
$userPostsCounts = [];
$forumPostingModes = [
'create', 'edit', 'quote', 'preview',
];
@ -63,7 +64,7 @@ if(empty($postId)) {
$hasPostInfo = false;
} else {
try {
$postInfo = $forum->getPost(postId: $postId);
$postInfo = $forumPosts->getPost(postId: $postId);
} catch(RuntimeException $ex) {
Template::throwError(404);
}
@ -80,7 +81,7 @@ if(empty($topicId)) {
$hasTopicInfo = false;
} else {
try {
$topicInfo = $forum->getTopic(topicId: $topicId);
$topicInfo = $forumTopics->getTopic(topicId: $topicId);
} catch(RuntimeException $ex) {
Template::throwError(404);
}
@ -89,7 +90,7 @@ if(empty($topicId)) {
Template::throwError(404);
$forumId = $topicInfo->getCategoryId();
$originalPostInfo = $forum->getPost(topicInfo: $topicInfo);
$originalPostInfo = $forumPosts->getPost(topicInfo: $topicInfo);
$hasTopicInfo = true;
}
@ -97,7 +98,7 @@ if(empty($forumId)) {
$hasCategoryInfo = false;
} else {
try {
$categoryInfo = $forum->getCategory(categoryId: $forumId);
$categoryInfo = $forumCategories->getCategory(categoryId: $forumId);
} catch(RuntimeException $ex) {
Template::throwError(404);
}
@ -152,7 +153,7 @@ if(!empty($_POST)) {
$postTimeout = $cfg->getInteger('forum.posting.timeout', 5);
if($postTimeout > 0) {
$postTimeoutThreshold = DateTime::now()->modify(sprintf('-%d seconds', $postTimeout));
$lastPostCreatedAt = $forum->getUserLastPostCreatedAt($currentUser);
$lastPostCreatedAt = $forumPosts->getUserLastPostCreatedAt($currentUser);
if($lastPostCreatedAt->isMoreThan($postTimeoutThreshold)) {
$waitSeconds = $postTimeout + ($lastPostCreatedAt->getUnixTimeSeconds() - time());
@ -205,7 +206,7 @@ if(!empty($_POST)) {
switch($mode) {
case 'create':
if(empty($topicInfo)) {
$topicInfo = $forum->createTopic(
$topicInfo = $forumTopics->createTopic(
$categoryInfo,
$currentUser,
$topicTitle,
@ -213,11 +214,11 @@ if(!empty($_POST)) {
);
$topicId = $topicInfo->getId();
$forum->incrementCategoryTopics($categoryInfo);
$forumTopics->incrementCategoryTopics($categoryInfo);
} else
$forum->bumpTopic($topicInfo);
$forumTopics->bumpTopic($topicInfo);
$postInfo = $forum->createPost(
$postInfo = $forumPosts->createPost(
$topicId,
$currentUser,
$_SERVER['REMOTE_ADDR'],
@ -228,7 +229,7 @@ if(!empty($_POST)) {
);
$postId = $postInfo->getId();
$forum->incrementCategoryPosts($categoryInfo);
$forumCategories->incrementCategoryPosts($categoryInfo);
break;
case 'edit':
@ -236,7 +237,7 @@ if(!empty($_POST)) {
&& $postInfo->shouldMarkAsEdited()
&& $postText !== $postInfo->getBody();
$forum->updatePost(
$forumPosts->updatePost(
$postId,
remoteAddr: $_SERVER['REMOTE_ADDR'],
body: $postText,
@ -246,7 +247,7 @@ if(!empty($_POST)) {
);
if($isEditingTopic && ($topicTitleChanged || $topicTypeChanged))
$forum->updateTopic(
$forumTopics->updateTopic(
$topicId,
title: $topicTitle,
type: $topicType
@ -278,11 +279,7 @@ if($mode === 'edit') { // $post is pretty much sure to be populated at this poin
if($postInfo->hasUserId()) {
$post->user = $usersCtx->getUserInfo($postInfo->getUserId());
$post->colour = $usersCtx->getUserColour($post->user);
$postUserId = $postInfo->getUserId();
if(!array_key_exists($postUserId, $userPostsCounts))
$userPostsCounts[$postUserId] = $forum->countPosts(userInfo: $post->user, deleted: false);
$post->postsCount = $userPostsCounts[$postUserId];
$post->postsCount = $forumCtx->countTotalUserPosts($post->user);
}
$post->isOriginalPost = $originalPostInfo->getId() == $postInfo->getId();
@ -293,18 +290,18 @@ if($mode === 'edit') { // $post is pretty much sure to be populated at this poin
}
try {
$lastPostInfo = $forum->getPost(userInfo: $currentUser, getLast: true, deleted: false);
$lastPostInfo = $forumPosts->getPost(userInfo: $currentUser, getLast: true, deleted: false);
$selectedParser = $lastPostInfo->getParser();
} catch(RuntimeException $ex) {
$selectedParser = Parser::BBCODE;
}
Template::render('forum.posting', [
'posting_breadcrumbs' => $forum->getCategoryAncestry($categoryInfo),
'global_accent_colour' => $forum->getCategoryColour($categoryInfo),
'posting_breadcrumbs' => $forumCategories->getCategoryAncestry($categoryInfo),
'global_accent_colour' => $forumCategories->getCategoryColour($categoryInfo),
'posting_user' => $currentUser,
'posting_user_colour' => $usersCtx->getUserColour($currentUser),
'posting_user_posts_count' => $userPostsCounts[$currentUser->getId()] ?? $forum->countPosts(userInfo: $currentUser, deleted: false),
'posting_user_posts_count' => $forumCtx->countTotalUserPosts($currentUser),
'posting_user_preferred_parser' => $selectedParser,
'posting_forum' => $categoryInfo,
'posting_notices' => $notices,

View file

@ -4,7 +4,11 @@ namespace Misuzu;
use stdClass;
use RuntimeException;
$forum = $msz->getForum();
$forumCtx = $msz->getForumContext();
$forumCategories = $forumCtx->getCategories();
$forumTopics = $forumCtx->getTopics();
$forumTopicRedirects = $forumCtx->getTopicRedirects();
$forumPosts = $forumCtx->getPosts();
$usersCtx = $msz->getUsersContext();
$postId = !empty($_GET['p']) && is_string($_GET['p']) ? (int)$_GET['p'] : 0;
@ -19,7 +23,7 @@ $currentUserId = $currentUser === null ? '0' : $currentUser->getId();
if($topicId < 1 && $postId > 0) {
try {
$postInfo = $forum->getPost(postId: $postId);
$postInfo = $forumPosts->getPost(postId: $postId);
} catch(RuntimeException $ex) {
Template::throwError(404);
}
@ -32,7 +36,7 @@ if($topicId < 1 && $postId > 0) {
Template::throwError(404);
$topicId = $postInfo->getTopicId();
$preceedingPostCount = $forum->countPosts(
$preceedingPostCount = $forumPosts->countPosts(
topicInfo: $topicId,
upToPostInfo: $postInfo,
deleted: $canDeleteAny ? null : false
@ -41,7 +45,7 @@ if($topicId < 1 && $postId > 0) {
try {
$topicIsNuked = $topicIsDeleted = $canDeleteAny = false;
$topicInfo = $forum->getTopic(topicId: $topicId);
$topicInfo = $forumTopics->getTopic(topicId: $topicId);
} catch(RuntimeException $ex) {
$topicIsNuked = true;
}
@ -60,8 +64,8 @@ if(!$topicIsNuked) {
$canDeleteAny = $perms->check(Perm::F_POST_DELETE_ANY);
}
if(($topicIsNuked || $topicIsDeleted) && $forum->hasTopicRedirect($topicId)) {
$topicRedirectInfo = $forum->getTopicRedirect($topicId);
if(($topicIsNuked || $topicIsDeleted) && $forumTopicRedirects->hasTopicRedirect($topicId)) {
$topicRedirectInfo = $forumTopicRedirects->getTopicRedirect($topicId);
Template::set('topic_redir_info', $topicRedirectInfo);
if($topicIsNuked || !$canDeleteAny) {
@ -80,7 +84,7 @@ if(!$perms->check(Perm::F_CATEGORY_VIEW))
// this should be in the config
$deletePostThreshold = 1;
$categoryInfo = $forum->getCategory(topicInfo: $topicInfo);
$categoryInfo = $forumCategories->getCategory(topicInfo: $topicInfo);
$topicIsLocked = $topicInfo->isLocked();
$topicIsArchived = $categoryInfo->isArchived();
$topicPostsTotal = $topicInfo->getTotalPostsCount();
@ -135,7 +139,7 @@ if(in_array($moderationMode, $validModerationModes, true)) {
Template::displayInfo('This topic has existed for too long. Ask a moderator to remove if it absolutely necessary.', 403);
// deleted posts are intentionally included
$topicPostCount = $forum->countPosts(topicInfo: $topicInfo);
$topicPostCount = $forumPosts->countPosts(topicInfo: $topicInfo);
if($topicPostCount > $deletePostThreshold)
Template::displayInfo('This topic already has replies, you may no longer delete it. Ask a moderator to remove if it absolutely necessary.', 403);
}
@ -159,7 +163,7 @@ if(in_array($moderationMode, $validModerationModes, true)) {
break;
}
$forum->deleteTopic($topicInfo->getId());
$forumTopics->deleteTopic($topicInfo->getId());
$msz->createAuditLog('FORUM_TOPIC_DELETE', [$topicInfo->getId()]);
url_redirect('forum-category', [
@ -189,7 +193,7 @@ if(in_array($moderationMode, $validModerationModes, true)) {
break;
}
$forum->restoreTopic($topicInfo->getId());
$forumTopics->restoreTopic($topicInfo->getId());
$msz->createAuditLog('FORUM_TOPIC_RESTORE', [$topicInfo->getId()]);
url_redirect('forum-category', [
@ -219,7 +223,7 @@ if(in_array($moderationMode, $validModerationModes, true)) {
break;
}
$forum->nukeTopic($topicInfo->getId());
$forumTopics->nukeTopic($topicInfo->getId());
$msz->createAuditLog('FORUM_TOPIC_NUKE', [$topicInfo->getId()]);
url_redirect('forum-category', [
@ -229,7 +233,7 @@ if(in_array($moderationMode, $validModerationModes, true)) {
case 'bump':
if($canBumpTopic) {
$forum->bumpTopic($topicInfo->getId());
$forumTopics->bumpTopic($topicInfo->getId());
$msz->createAuditLog('FORUM_TOPIC_BUMP', [$topicInfo->getId()]);
}
@ -240,7 +244,7 @@ if(in_array($moderationMode, $validModerationModes, true)) {
case 'lock':
if($canLockTopic && !$topicIsLocked) {
$forum->lockTopic($topicInfo->getId());
$forumTopics->lockTopic($topicInfo->getId());
$msz->createAuditLog('FORUM_TOPIC_LOCK', [$topicInfo->getId()]);
}
@ -251,7 +255,7 @@ if(in_array($moderationMode, $validModerationModes, true)) {
case 'unlock':
if($canLockTopic && $topicIsLocked) {
$forum->unlockTopic($topicInfo->getId());
$forumTopics->unlockTopic($topicInfo->getId());
$msz->createAuditLog('FORUM_TOPIC_UNLOCK', [$topicInfo->getId()]);
}
@ -275,7 +279,7 @@ if(isset($preceedingPostCount))
if(!$topicPagination->hasValidOffset())
Template::throwError(404);
$postInfos = $forum->getPosts(
$postInfos = $forumPosts->getPosts(
topicInfo: $topicInfo,
deleted: $perms->check(Perm::F_POST_DELETE_ANY) ? null : false,
pagination: $topicPagination,
@ -284,9 +288,8 @@ $postInfos = $forum->getPosts(
if(empty($postInfos))
Template::throwError(404);
$originalPostInfo = $forum->getPost(topicInfo: $topicInfo);
$originalPostInfo = $forumPosts->getPost(topicInfo: $topicInfo);
$userPostsCounts = [];
$posts = [];
foreach($postInfos as $postInfo) {
@ -296,11 +299,7 @@ foreach($postInfos as $postInfo) {
if($postInfo->hasUserId()) {
$post->user = $usersCtx->getUserInfo($postInfo->getUserId());
$post->colour = $usersCtx->getUserColour($post->user);
$postUserId = $postInfo->getUserId();
if(!array_key_exists($postUserId, $userPostsCounts))
$userPostsCounts[$postUserId] = $forum->countPosts(userInfo: $post->user, deleted: false);
$post->postsCount = $userPostsCounts[$postUserId];
$post->postsCount = $forumCtx->countTotalUserPosts($post->user);
}
$post->isOriginalPost = $originalPostInfo->getId() == $postInfo->getId();
@ -310,10 +309,10 @@ foreach($postInfos as $postInfo) {
$canReply = !$topicIsArchived && !$topicIsLocked && !$topicIsDeleted && $perms->check(Perm::F_POST_CREATE);
if(!$forum->checkUserHasReadTopic($currentUser, $topicInfo))
$forum->incrementTopicViews($topicInfo);
if(!$forumTopics->checkUserHasReadTopic($currentUser, $topicInfo))
$forumTopics->incrementTopicViews($topicInfo);
$forum->updateUserReadTopic($currentUser, $topicInfo);
$forumTopics->updateUserReadTopic($currentUser, $topicInfo);
$perms = $perms->checkMany([
'can_create_post' => Perm::F_POST_CREATE,
@ -324,8 +323,8 @@ $perms = $perms->checkMany([
]);
Template::render('forum.topic', [
'topic_breadcrumbs' => $forum->getCategoryAncestry($topicInfo),
'global_accent_colour' => $forum->getCategoryColour($topicInfo),
'topic_breadcrumbs' => $forumCategories->getCategoryAncestry($topicInfo),
'global_accent_colour' => $forumCategories->getCategoryColour($topicInfo),
'topic_info' => $topicInfo,
'category_info' => $categoryInfo,
'topic_posts' => $posts,

View file

@ -5,7 +5,8 @@ $authInfo = $msz->getAuthInfo();
if(!$authInfo->getPerms('global')->check(Perm::G_FORUM_TOPIC_REDIRS_MANAGE))
Template::throwError(403);
$forum = $msz->getForum();
$forumCtx = $msz->getForumContext();
$forumTopicRedirects = $forumCtx->getTopicRedirects();
if($_SERVER['REQUEST_METHOD'] === 'POST') {
if(!CSRF::validateRequest())
@ -15,7 +16,7 @@ if($_SERVER['REQUEST_METHOD'] === 'POST') {
$rTopicURL = trim((string)filter_input(INPUT_POST, 'topic_redir_url'));
$msz->createAuditLog('FORUM_TOPIC_REDIR_CREATE', [$rTopicId]);
$forum->createTopicRedirect($rTopicId, $authInfo->getUserInfo(), $rTopicURL);
$forumTopicRedirects->createTopicRedirect($rTopicId, $authInfo->getUserInfo(), $rTopicURL);
url_redirect('manage-forum-topic-redirs');
return;
}
@ -26,16 +27,16 @@ if(filter_input(INPUT_GET, 'm') === 'explode') {
$rTopicId = (string)filter_input(INPUT_GET, 't');
$msz->createAuditLog('FORUM_TOPIC_REDIR_REMOVE', [$rTopicId]);
$forum->deleteTopicRedirect($rTopicId);
$forumTopicRedirects->deleteTopicRedirect($rTopicId);
url_redirect('manage-forum-topic-redirs');
return;
}
$pagination = new Pagination($forum->countTopicRedirects(), 20);
$pagination = new Pagination($forumTopicRedirects->countTopicRedirects(), 20);
if(!$pagination->hasValidOffset())
Template::throwError(404);
$redirs = $forum->getTopicRedirects(pagination: $pagination);
$redirs = $forumTopicRedirects->getTopicRedirects(pagination: $pagination);
Template::render('manage.forum.redirs', [
'manage_redirs' => $redirs,

View file

@ -216,7 +216,10 @@ if(CSRF::validateRequest() && $canEdit) {
}
if($permsNeedRecalc)
$perms->precalculatePermissions($msz->getForum(), [$userInfo->getId()]);
$perms->precalculatePermissions(
$msz->getForumContext()->getCategories(),
[$userInfo->getId()]
);
url_redirect('manage-user', ['user' => $userInfo->getId()]);
return;

View file

@ -9,7 +9,7 @@ if(!$authInfo->isLoggedIn())
// TODO: restore forum-topics and forum-posts orderings
$forum = $msz->getForum();
$forumCtx = $msz->getForumContext();
$usersCtx = $msz->getUsersContext();
$users = $usersCtx->getUsers();
$roles = $usersCtx->getRoles();
@ -94,8 +94,8 @@ foreach($userInfos as $userInfo)
$userList[] = [
'info' => $userInfo,
'colour' => $usersCtx->getUserColour($userInfo),
'ftopics' => $forum->countTopics(userInfo: $userInfo, deleted: false),
'fposts' => $forum->countPosts(userInfo: $userInfo, deleted: false),
'ftopics' => $forumCtx->countTotalUserTopics($userInfo),
'fposts' => $forumCtx->countTotalUserPosts($userInfo),
];
if(empty($userList))

View file

@ -17,7 +17,10 @@ $isEditing = !empty($_GET['edit']) && is_string($_GET['edit']) ? (bool)$_GET['ed
$usersCtx = $msz->getUsersContext();
$users = $usersCtx->getUsers();
$forum = $msz->getForum();
$forumCtx = $msz->getForumContext();
$forumCategories = $forumCtx->getCategories();
$forumTopics = $forumCtx->getTopics();
$forumPosts = $forumCtx->getPosts();
$authInfo = $msz->getAuthInfo();
$viewerInfo = $authInfo->getUserInfo();
@ -289,8 +292,8 @@ if($isEditing) {
// TODO: create user counters so these can be statically kept
$profileStats = new stdClass;
$profileStats->forum_topic_count = $forum->countTopics(userInfo: $userInfo, deleted: false);
$profileStats->forum_post_count = $forum->countPosts(userInfo: $userInfo, deleted: false);
$profileStats->forum_topic_count = $forumCtx->countTotalUserTopics($userInfo);
$profileStats->forum_post_count = $forumCtx->countTotalUserPosts($userInfo);
$profileStats->comments_count = $msz->getComments()->countPosts(userInfo: $userInfo, deleted: false);
if(!$viewingAsGuest) {
@ -302,21 +305,21 @@ if(!$viewingAsGuest) {
'forum_leader.unranked.topic:a',
]);
$activeCategoryStats = $forum->getMostActiveCategoryInfo(
$activeCategoryStats = $forumCategories->getMostActiveCategoryInfo(
$userInfo,
$unranked['forum_leader.unranked.forum'],
$unranked['forum_leader.unranked.topic'],
deleted: false
);
$activeCategoryInfo = $activeCategoryStats->success ? $forum->getCategory(categoryId: $activeCategoryStats->categoryId) : null;
$activeCategoryInfo = $activeCategoryStats->success ? $forumCategories->getCategory(categoryId: $activeCategoryStats->categoryId) : null;
$activeTopicStats = $forum->getMostActiveTopicInfo(
$activeTopicStats = $forumTopics->getMostActiveTopicInfo(
$userInfo,
$unranked['forum_leader.unranked.forum'],
$unranked['forum_leader.unranked.topic'],
deleted: false
);
$activeTopicInfo = $activeTopicStats->success ? $forum->getTopic(topicId: $activeTopicStats->topicId) : null;
$activeTopicInfo = $activeTopicStats->success ? $forumTopics->getTopic(topicId: $activeTopicStats->topicId) : null;
$profileFieldValues = $profileFields->getFieldValues($userInfo);
$profileFieldInfos = $profileFieldInfos ?? $profileFields->getFields(fieldValueInfos: $isEditing ? null : $profileFieldValues);

View file

@ -41,7 +41,10 @@ Template::addFunction('search_merge_query', function($attrs) use (&$searchQueryE
if(!empty($searchQuery)) {
$usersCtx = $msz->getUsersContext();
$users = $usersCtx->getUsers();
$forum = $msz->getForum();
$forumCtx = $msz->getForumContext();
$forumCategories = $forumCtx->getCategories();
$forumTopics = $forumCtx->getTopics();
$forumPosts = $forumCtx->getPosts();
$news = $msz->getNews();
$comments = $msz->getComments();
@ -79,18 +82,18 @@ if(!empty($searchQuery)) {
$currentUserId = $currentUser === null ? 0 : (int)$currentUser->getId();
$forumCategoryIds = XArray::where(
$forum->getCategories(hidden: false),
$forumCategories->getCategories(hidden: false),
fn($categoryInfo) => $categoryInfo->mayHaveTopics() && $authInfo->getPerms('forum', $categoryInfo)->check(Perm::F_CATEGORY_VIEW)
);
$forumTopicInfos = $forum->getTopics(categoryInfo: $forumCategoryIds, deleted: false, searchQuery: $searchQueryEvaluated);
$forumTopics = [];
$forumTopicInfos = $forumTopics->getTopics(categoryInfo: $forumCategoryIds, deleted: false, searchQuery: $searchQueryEvaluated);
$ftopics = [];
foreach($forumTopicInfos as $topicInfo) {
$forumTopics[] = $topic = new stdClass;
$ftopics[] = $topic = new stdClass;
$topic->info = $topicInfo;
$topic->unread = $forum->checkTopicUnread($topicInfo, $currentUser);
$topic->participated = $forum->checkTopicParticipated($topicInfo, $currentUser);
$topic->unread = $forumTopics->checkTopicUnread($topicInfo, $currentUser);
$topic->participated = $forumTopics->checkTopicParticipated($topicInfo, $currentUser);
$topic->lastPost = new stdClass;
if($topicInfo->hasUserId()) {
@ -99,7 +102,7 @@ if(!empty($searchQuery)) {
}
try {
$topic->lastPost->info = $lastPostInfo = $forum->getPost(
$topic->lastPost->info = $lastPostInfo = $forumPosts->getPost(
topicInfo: $topicInfo,
getLast: true,
deleted: $topicInfo->isDeleted() ? null : false,
@ -112,17 +115,17 @@ if(!empty($searchQuery)) {
} catch(RuntimeException $ex) {}
}
$forumPostInfos = $forum->getPosts(categoryInfo: $forumCategoryIds, searchQuery: $searchQueryEvaluated);
$forumPosts = [];
$forumPostInfos = $forumPosts->getPosts(categoryInfo: $forumCategoryIds, searchQuery: $searchQueryEvaluated);
$fposts = [];
foreach($forumPostInfos as $postInfo) {
$forumPosts[] = $post = new stdClass;
$fposts[] = $post = new stdClass;
$post->info = $postInfo;
if($postInfo->hasUserId()) {
$post->user = $usersCtx->getUserInfo($postInfo->getUserId(), 'id');
$post->colour = $usersCtx->getUserColour($post->user);
$post->postsCount = $forum->countPosts(userInfo: $post->user, deleted: false);
$post->postsCount = $forumCtx->countTotalUserPosts($post->user);
}
// can't be bothered sorry
@ -165,15 +168,15 @@ if(!empty($searchQuery)) {
$members[] = $member = new stdClass;
$member->info = $memberInfo;
$member->colour = $usersCtx->getUserColour($memberInfo);
$member->ftopics = $forum->countTopics(userInfo: $memberInfo, deleted: false);
$member->fposts = $forum->countPosts(userInfo: $memberInfo, deleted: false);
$member->ftopics = $forumCtx->countTotalUserTopics($memberInfo);
$member->fposts = $forumCtx->countTotalUserPosts($memberInfo);
}
}
Template::render('home.search', [
'search_query' => $searchQuery,
'forum_topics' => $forumTopics ?? [],
'forum_posts' => $forumPosts ?? [],
'forum_topics' => $ftopics ?? [],
'forum_posts' => $fposts ?? [],
'members' => $members ?? [],
'news_posts' => $newsPosts ?? [],
]);

View file

@ -37,7 +37,10 @@ if(!$isRestricted && $isVerifiedRequest && !empty($_POST['role'])) {
case 'leave':
if($roleInfo->isLeavable()) {
$users->removeRoles($userInfo, $roleInfo);
$msz->getPerms()->precalculatePermissions($msz->getForum(), [$userInfo->getId()]);
$msz->getPerms()->precalculatePermissions(
$msz->getForumContext()->getCategories(),
[$userInfo->getId()]
);
} else
$errors[] = "You're not allow to leave this role, an administrator has to remove it for you.";
break;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,507 @@
<?php
namespace Misuzu\Forum;
use InvalidArgumentException;
use RuntimeException;
use stdClass;
use Index\Colour\Colour;
use Index\Data\DbStatementCache;
use Index\Data\DbTools;
use Index\Data\IDbConnection;
use Misuzu\Pagination;
use Misuzu\Users\UserInfo;
class ForumCategories {
private IDbConnection $dbConn;
private DbStatementCache $cache;
public function __construct(IDbConnection $dbConn) {
$this->dbConn = $dbConn;
$this->cache = new DbStatementCache($dbConn);
}
public static function convertCategoryListToTree(
array $catInfos,
ForumCategoryInfo|string|null $parentInfo = null,
?Colour $colour = null
): array {
$colour ??= Colour::none();
$tree = [];
$predicate = $parentInfo
? fn($catInfo) => $catInfo->isDirectChildOf($parentInfo)
: fn($catInfo) => !$catInfo->hasParent();
foreach($catInfos as $catInfo) {
if(!$predicate($catInfo))
continue;
$tree[$catInfo->getId()] = $item = new stdClass;
$item->info = $catInfo;
$item->colour = $catInfo->hasColour() ? $catInfo->getColour() : $colour;
$item->children = self::convertCategoryListToTree($catInfos, $catInfo, $item->colour);
$item->childIds = [];
foreach($item->children as $child) {
$item->childIds[] = $child->info->getId();
$item->childIds += $child->childIds;
}
}
return $tree;
}
public function countCategories(
ForumCategoryInfo|string|null|false $parentInfo = false,
string|int|null $type = null,
?bool $hidden = null
): int {
if($parentInfo instanceof ForumCategoryInfo)
$parentInfo = $parentInfo->getId();
$isRootParent = false;
$hasParentInfo = $parentInfo !== false;
$hasType = $type !== null;
$hasHidden = $hidden !== null;
$args = 0;
$query = 'SELECT COUNT(*) FROM msz_forum_categories';
if($hasParentInfo) {
++$args;
$isRootParent = $parentInfo === null;
if($isRootParent) { // make a migration that makes the field DEFAULT NULL and update all 0s to NULL
$query .= 'WHERE (forum_parent IS NULL OR forum_parent = 0)';
} else {
$query .= 'WHERE forum_parent = ?';
}
}
if($hasType) {
if(is_string($type)) {
if(!array_key_exists($type, ForumCategoryInfo::TYPE_ALIASES))
throw new InvalidArgumentException('$type is not a valid alias.');
$type = ForumCategoryInfo::TYPE_ALIASES[$type];
}
$query .= sprintf(' %s forum_type = ?', ++$args > 1 ? 'AND' : 'WHERE');
}
if($hasHidden)
$query .= sprintf(' %s forum_hidden %s 0', ++$args > 1 ? 'AND' : 'WHERE', $hidden ? '<>' : '=');
$args = 0;
$stmt = $this->cache->get($query);
if($hasParentInfo && !$isRootParent)
$stmt->addParameter(++$args, $parentInfo);
if($hasType)
$stmt->addParameter(++$args, $type);
$stmt->execute();
$result = $stmt->getResult();
return $result->next() ? $result->getInteger(0) : 0;
}
public function getCategories(
ForumCategoryInfo|string|null|false $parentInfo = false,
string|int|null $type = null,
?bool $hidden = null,
bool $asTree = false,
?Pagination $pagination = null
): array {
$isRootParent = false;
$hasParentInfo = $parentInfo !== false;
$hasType = $type !== null;
$hasHidden = $hidden !== null;
$hasPagination = $pagination !== null;
if($hasParentInfo && $asTree)
throw new InvalidArgumentException('$asTree can only be used with $parentInfo set to false.');
$args = 0;
$query = 'SELECT forum_id, forum_order, forum_parent, forum_name, forum_type, forum_description, forum_icon, forum_colour, forum_link, forum_link_clicks, UNIX_TIMESTAMP(forum_created), forum_archived, forum_hidden, forum_count_topics, forum_count_posts FROM msz_forum_categories';
if($hasParentInfo) {
++$args;
$isRootParent = $parentInfo === null;
if($isRootParent) { // make a migration that makes the field DEFAULT NULL and update all 0s to NULL
$query .= ' WHERE (forum_parent IS NULL OR forum_parent = 0)';
} else {
$query .= ' WHERE forum_parent = ?';
}
}
if($hasType) {
if(is_string($type)) {
if(!array_key_exists($type, ForumCategoryInfo::TYPE_ALIASES))
throw new InvalidArgumentException('$type is not a valid alias.');
$type = ForumCategoryInfo::TYPE_ALIASES[$type];
}
$query .= sprintf(' %s forum_type = ?', ++$args > 1 ? 'AND' : 'WHERE');
}
if($hasHidden)
$query .= sprintf(' %s forum_hidden %s 0', ++$args > 1 ? 'AND' : 'WHERE', $hidden ? '<>' : '=');
$query .= ' ORDER BY forum_parent, forum_type <> 1, forum_order';
if($hasPagination)
$query .= ' LIMIT ? OFFSET ?';
$args = 0;
$stmt = $this->cache->get($query);
if($hasParentInfo && !$isRootParent) {
if($parentInfo instanceof ForumCategoryInfo)
$stmt->addParameter(++$args, $parentInfo->getId());
else
$stmt->addParameter(++$args, $parentInfo);
}
if($hasType)
$stmt->addParameter(++$args, $type);
if($hasPagination) {
$stmt->addParameter(++$args, $pagination->getRange());
$stmt->addParameter(++$args, $pagination->getOffset());
}
$stmt->execute();
$result = $stmt->getResult();
$cats = [];
while($result->next())
$cats[] = new ForumCategoryInfo($result);
if($asTree)
$cats = self::convertCategoryListToTree($cats);
return $cats;
}
public function getCategory(
?string $categoryId = null,
ForumTopicInfo|string|null $topicInfo = null,
ForumPostInfo|string|null $postInfo = null
): ForumCategoryInfo {
$hasCategoryId = $categoryId !== null;
$hasTopicInfo = $topicInfo !== null;
$hasPostInfo = $postInfo !== null;
if(!$hasCategoryId && !$hasTopicInfo && !$hasPostInfo)
throw new InvalidArgumentException('You must specify an argument.');
if(($hasCategoryId && ($hasTopicInfo || $hasPostInfo))
|| ($hasTopicInfo && ($hasCategoryId || $hasPostInfo))
|| ($hasPostInfo && ($hasCategoryId || $hasTopicInfo)))
throw new InvalidArgumentException('Only one argument may be specified.');
$value = null;
$query = 'SELECT forum_id, forum_order, forum_parent, forum_name, forum_type, forum_description, forum_icon, forum_colour, forum_link, forum_link_clicks, UNIX_TIMESTAMP(forum_created), forum_archived, forum_hidden, forum_count_topics, forum_count_posts FROM msz_forum_categories';
if($hasCategoryId) {
$query .= ' WHERE forum_id = ?';
$value = $categoryId;
}
if($hasTopicInfo) {
if($topicInfo instanceof ForumTopicInfo) {
$query .= ' WHERE forum_id = ?';
$value = $topicInfo->getCategoryId();
} else {
$query .= ' WHERE forum_id = (SELECT forum_id FROM msz_forum_topics WHERE topic_id = ?)';
$value = $topicInfo;
}
}
if($hasPostInfo) {
if($postInfo instanceof ForumPostInfo) {
$query .= ' WHERE forum_id = ?';
$value = $postInfo->getCategoryId();
} else {
$query .= ' WHERE forum_id = (SELECT forum_id FROM msz_forum_posts WHERE post_id = ?)';
$value = $postInfo;
}
}
$stmt = $this->cache->get($query);
$stmt->addParameter(1, $value);
$stmt->execute();
$result = $stmt->getResult();
if(!$result->next())
throw new RuntimeException('Forum category info not found.');
return new ForumCategoryInfo($result);
}
public function updateCategory(
ForumCategoryInfo|string $categoryInfo
): void {
if($categoryInfo instanceof ForumCategoryInfo)
$categoryInfo = $categoryInfo->getId();
}
public function deleteCategory(ForumCategoryInfo|string $categoryInfo): void {
if($categoryInfo instanceof ForumCategoryInfo)
$categoryInfo = $categoryInfo->getId();
}
public function incrementCategoryClicks(ForumCategoryInfo|string $categoryInfo): void {
if($categoryInfo instanceof ForumCategoryInfo)
$categoryInfo = $categoryInfo->getId();
// previous implementation also WHERE'd for forum_type = link but i don't think there's any other way to get here anyhow
$stmt = $this->cache->get('UPDATE msz_forum_categories SET forum_link_clicks = forum_link_clicks + 1 WHERE forum_id = ? AND forum_link_clicks IS NOT NULL');
$stmt->addParameter(1, $categoryInfo);
$stmt->execute();
}
public function incrementCategoryTopics(ForumCategoryInfo|string $categoryInfo): void {
if($categoryInfo instanceof ForumCategoryInfo)
$categoryInfo = $categoryInfo->getId();
$stmt = $this->cache->get('UPDATE msz_forum_categories SET forum_count_topics = forum_count_topics + 1 WHERE forum_id = ?');
$stmt->addParameter(1, $categoryInfo);
$stmt->execute();
}
public function incrementCategoryPosts(ForumCategoryInfo|string $categoryInfo): void {
if($categoryInfo instanceof ForumCategoryInfo)
$categoryInfo = $categoryInfo->getId();
$stmt = $this->cache->get('UPDATE msz_forum_categories SET forum_count_posts = forum_count_posts + 1 WHERE forum_id = ?');
$stmt->addParameter(1, $categoryInfo);
$stmt->execute();
}
public function getCategoryAncestry(
ForumCategoryInfo|ForumTopicInfo|ForumPostInfo|string $categoryInfo
): array {
if($categoryInfo instanceof ForumCategoryInfo)
$categoryInfo = $categoryInfo->getId();
elseif($categoryInfo instanceof ForumTopicInfo || $categoryInfo instanceof ForumPostInfo)
$categoryInfo = $categoryInfo->getCategoryId();
$query = 'WITH RECURSIVE msz_cte_ancestry AS ('
. 'SELECT forum_id, forum_order, forum_parent, forum_name, forum_type, forum_description, forum_icon, forum_colour, forum_link, forum_link_clicks, UNIX_TIMESTAMP(forum_created), forum_archived, forum_hidden, forum_count_topics, forum_count_posts FROM msz_forum_categories WHERE forum_id = ?'
. ' UNION ALL'
. ' SELECT fc.forum_id, fc.forum_order, fc.forum_parent, fc.forum_name, fc.forum_type, fc.forum_description, fc.forum_icon, fc.forum_colour, fc.forum_link, fc.forum_link_clicks, UNIX_TIMESTAMP(fc.forum_created), fc.forum_archived, fc.forum_hidden, fc.forum_count_topics, fc.forum_count_posts FROM msz_forum_categories AS fc JOIN msz_cte_ancestry AS ca ON fc.forum_id = ca.forum_parent'
. ') SELECT * FROM msz_cte_ancestry';
$stmt = $this->cache->get($query);
$stmt->addParameter(1, $categoryInfo);
$stmt->execute();
$result = $stmt->getResult();
$cats = [];
while($result->next())
$cats[] = new ForumCategoryInfo($result);
return $cats;
}
public function getCategoryChildren(
ForumCategoryInfo|string $parentInfo,
bool $includeSelf = false,
?bool $hidden = null,
bool $asTree = false
): array {
if($parentInfo instanceof ForumCategoryInfo)
$parentInfo = $parentInfo->getId();
$hasHidden = $hidden !== null;
$query = 'WITH RECURSIVE msz_cte_children AS ('
. 'SELECT forum_id, forum_order, forum_parent, forum_name, forum_type, forum_description, forum_icon, forum_colour, forum_link, forum_link_clicks, UNIX_TIMESTAMP(forum_created), forum_archived, forum_hidden, forum_count_topics, forum_count_posts FROM msz_forum_categories WHERE forum_id = ?'
. ' UNION ALL'
. ' SELECT fc.forum_id, fc.forum_order, fc.forum_parent, fc.forum_name, fc.forum_type, fc.forum_description, fc.forum_icon, fc.forum_colour, fc.forum_link, fc.forum_link_clicks, UNIX_TIMESTAMP(fc.forum_created), fc.forum_archived, fc.forum_hidden, fc.forum_count_topics, fc.forum_count_posts FROM msz_forum_categories AS fc JOIN msz_cte_children AS cc ON fc.forum_parent = cc.forum_id'
. ') SELECT * FROM msz_cte_children';
$args = 0;
if(!$includeSelf) {
++$args;
$query .= ' WHERE forum_id <> ?';
}
if($hasHidden)
$query .= sprintf(' %s forum_hidden %s 0', ++$args > 1 ? 'AND' : 'WHERE', $hidden ? '<>' : '=');
$query .= ' ORDER BY forum_parent, forum_order';
$args = 0;
$stmt = $this->cache->get($query);
$stmt->addParameter(++$args, $parentInfo);
if(!$includeSelf)
$stmt->addParameter(++$args, $parentInfo);
$stmt->execute();
$result = $stmt->getResult();
$cats = [];
while($result->next())
$cats[] = new ForumCategoryInfo($result);
if($asTree)
$cats = self::convertCategoryListToTree($cats, $parentInfo);
return $cats;
}
public function checkCategoryUnread(
ForumCategoryInfo|string|array $categoryInfos,
UserInfo|string|null $userInfo
): bool {
if($userInfo === null)
return false;
if(!is_array($categoryInfos))
$categoryInfos = [$categoryInfos];
if($userInfo instanceof UserInfo)
$userInfo = $userInfo->getId();
$args = 0;
$stmt = $this->cache->get(sprintf(
'SELECT COUNT(*) FROM msz_forum_topics AS ft LEFT JOIN msz_forum_topics_track AS ftt ON ftt.topic_id = ft.topic_id AND ftt.user_id = ? WHERE ft.forum_id IN (%s) AND ft.topic_deleted IS NULL AND ft.topic_bumped >= NOW() - INTERVAL 1 MONTH AND (ftt.track_last_read IS NULL OR ftt.track_last_read < ft.topic_bumped)',
DbTools::prepareListString($categoryInfos)
));
$stmt->addParameter(++$args, $userInfo);
foreach($categoryInfos as $categoryInfo) {
if($categoryInfo instanceof ForumCategoryInfo)
$stmt->addParameter(++$args, $categoryInfo->getId());
elseif(is_string($categoryInfo) || is_int($categoryInfo))
$stmt->addParameter(++$args, $categoryInfo);
else
throw new InvalidArgumentException('Invalid item in $categoryInfos.');
}
$stmt->execute();
$result = $stmt->getResult();
return $result->next() && $result->getInteger(0) > 0;
}
public function updateUserReadCategory(
UserInfo|string|null $userInfo,
ForumCategoryInfo|string $categoryInfo
): void {
if($userInfo === null)