Files
ops-Gazelle/app/ForumPost.php
2025-05-23 14:41:16 +02:00

225 lines
7.1 KiB
PHP

<?php
namespace Gazelle;
class ForumPost extends BaseObject {
final public const tableName = 'forums_posts';
final public const CACHE_KEY = 'fpost_%d';
public function flush(): static {
self::$cache->delete_value(sprintf(self::CACHE_KEY, $this->id));
$this->thread()->flush();
unset($this->info);
return $this;
}
public function link(): string {
return sprintf('<a href="%s">%s</a>', $this->url(), "Post #{$this->id}");
}
public function location(): string {
return "forums.php?action=viewthread&threadid={$this->threadId()}&postid={$this->id}#post{$this->id}";
}
/**
* Get information about a post
*/
public function info(): array {
if (isset($this->info)) {
return $this->info;
}
$key = sprintf(self::CACHE_KEY, $this->id);
$info = self::$cache->get_value($key);
if ($info === false) {
$info = self::$db->rowAssoc("
SELECT f.ID AS forum_id,
f.MinClassWrite AS min_class_write,
t.ID AS thread_id,
t.Islocked = '1' AS thread_locked,
ceil(t.NumPosts / ?) AS thread_page_total,
cast((SELECT ceil(sum(if(fp.ID <= p.ID, 1, 0)) / ?) FROM forums_posts fp WHERE fp.TopicID = t.ID) AS signed)
AS page,
p.AuthorID AS user_id,
(p.ID = t.StickyPostID) AS is_pinned,
p.Body AS body,
p.AddedTime AS created,
p.EditedUserID AS edit_user_id,
p.EditedTime AS edit_time
FROM forums_topics t
INNER JOIN forums f ON (t.forumid = f.id)
INNER JOIN forums_posts p ON (p.topicid = t.id)
WHERE p.ID = ?
", POSTS_PER_PAGE, POSTS_PER_PAGE, $this->id
);
self::$cache->cache_value($key, $info, 86400);
}
$this->info = $info;
return $this->info;
}
public function thread(): ForumThread {
return new ForumThread($this->threadId());
}
public function threadId(): int {
return $this->info()['thread_id'];
}
public function userId(): int {
return $this->info()['user_id'];
}
public function body(): string {
return $this->info()['body'];
}
public function created(): string {
return $this->info()['created'];
}
public function isPinned(): bool {
return (bool)$this->info()['is_pinned'];
}
public function page(): int {
return $this->info()['page'];
}
public function threadPageTotal(): int {
return $this->info()['thread_page_total'];
}
public function priorPostTotal(): int {
return (int)self::$db->scalar("
SELECT count(*)
FROM forums_posts
WHERE TopicID = (SELECT TopicID FROM forums_posts WHERE ID = ?)
AND ID <= ?
", $this->id, $this->id
);
}
public function edit(User $user, string $body): int {
self::$db->begin_transaction();
self::$db->prepared_query("
INSERT INTO comments_edits
(EditUser, PostID, Body, Page)
VALUES (?, ?, (SELECT Body from forums_posts WHERE ID = ?), 'forums')
", $user->id(), $this->id, $this->id
);
self::$db->prepared_query("
UPDATE forums_posts SET
EditedUserID = ?,
Body = ?,
EditedTime = now()
WHERE ID = ?
", $user->id(), $body, $this->id
);
$affected = self::$db->affected_rows();
self::$db->commit();
$this->flush();
$this->thread()->flushPostCatalogue($this);
$this->info['body'] = $body;
return $affected;
}
/**
* Pin/unpin a post in its thread
*/
public function pin(User $user, bool $set): int {
$this->thread()->addThreadNote($user, "Post {$this->id} " . ($set ? "pinned" : "unpinned"));
self::$db->prepared_query("
UPDATE forums_topics SET
StickyPostID = ?
WHERE ID = ?
", $set ? $this->id : 0, $this->thread()->id()
);
$affected = self::$db->affected_rows();
$this->thread()->flushCatalogue();
$this->flush();
return $affected;
}
/**
* Determine on which page a post falls in a thread
*/
public function threadCatalogue(): int {
return (int)self::$db->scalar("
WITH list AS (
SELECT ID,
TRUNCATE((row_number() OVER () - 1) / ?, 0) AS catalogue
FROM forums_posts
WHERE TopicID = ?
)
SELECT catalogue FROM list WHERE ID = ?
", THREAD_CATALOGUE, $this->thread()->id(), $this->id
);
}
/**
* Remove a post from a thread
*/
public function remove(): bool {
self::$db->begin_transaction();
$db = new DB();
$db->relaxConstraints(true);
self::$db->prepared_query("
DELETE fp, unq
FROM forums_posts fp
LEFT JOIN users_notify_quoted unq ON (unq.PostID = fp.ID and unq.Page = 'forums')
WHERE fp.ID = ?
", $this->id()
);
if (self::$db->affected_rows() === 0) {
$db->relaxConstraints(false);
self::$db->rollback();
return false;
}
$thread = $this->thread();
$threadId = $thread->id();
self::$db->prepared_query("
UPDATE forums_topics t
INNER JOIN
(
SELECT
count(p.ID) AS NumPosts,
IF(t.StickyPostID = ?, 0, t.StickyPostID) AS StickyPostID,
t.ID
FROM forums_topics t
LEFT JOIN forums_posts p ON (p.TopicID = t.ID) where t.id = ?
) UPD ON (UPD.ID = t.ID)
LEFT JOIN (
SELECT ID, AuthorID, AddedTime, TopicID
FROM forums_posts
WHERE TopicID = ?
ORDER BY ID desc
LIMIT 1
) LAST ON (LAST.TopicID = UPD.ID)
SET
t.NumPosts = UPD.NumPosts,
t.StickyPostID = UPD.StickyPostID,
t.LastPostID = LAST.ID,
t.LastPostAuthorID = LAST.AuthorID,
t.LastPostTime = LAST.AddedTime
WHERE t.ID = ?
", $this->id(), $threadId, $threadId, $threadId
);
$db->relaxConstraints(false);
self::$db->commit();
$this->thread()->forum()->adjust();
(new Manager\Subscription())->flushPage('forums', $threadId);
$thread->flushPostCatalogue($this);
$thread->flush();
return true;
}
public function modify(): bool {
$this->thread()->flushPostCatalogue($this);
return parent::modify();
}
}