273 lines
9.9 KiB
PHP
273 lines
9.9 KiB
PHP
<?php
|
|
namespace Misuzu\Comments;
|
|
|
|
use InvalidArgumentException;
|
|
use RuntimeException;
|
|
use Index\Db\{DbConnection,DbStatementCache};
|
|
use Misuzu\Users\UserInfo;
|
|
|
|
class CommentsPostsData {
|
|
private DbStatementCache $cache;
|
|
|
|
public function __construct(DbConnection $dbConn) {
|
|
$this->cache = new DbStatementCache($dbConn);
|
|
}
|
|
|
|
public function countPosts(
|
|
CommentsCategoryInfo|string|null $categoryInfo = null,
|
|
?string $categoryName = null,
|
|
CommentsPostInfo|string|null $parentInfo = null,
|
|
UserInfo|string|null $userInfo = null,
|
|
?bool $replies = null,
|
|
?bool $deleted = null
|
|
): int {
|
|
if($categoryInfo instanceof CommentsCategoryInfo)
|
|
$categoryInfo = $categoryInfo->id;
|
|
if($parentInfo instanceof CommentsPostInfo)
|
|
$parentInfo = $parentInfo->id;
|
|
|
|
$hasCategoryInfo = $categoryInfo !== null;
|
|
$hasCategoryName = $categoryName !== null;
|
|
$hasParentInfo = $parentInfo !== null;
|
|
$hasUserInfo = $userInfo !== null;
|
|
$hasReplies = $replies !== null;
|
|
$hasDeleted = $deleted !== null;
|
|
|
|
$args = 0;
|
|
$query = 'SELECT COUNT(*) FROM msz_comments_posts';
|
|
|
|
if($hasParentInfo) {
|
|
++$args;
|
|
$query .= ' WHERE comment_reply_to = ?';
|
|
}
|
|
if($hasCategoryInfo)
|
|
$query .= sprintf(' %s category_id = ?', ++$args > 1 ? 'AND' : 'WHERE');
|
|
if($hasCategoryName)
|
|
$query .= sprintf(' %s category_id = (SELECT category_id FROM msz_comments_categories WHERE category_name = ?)', ++$args > 1 ? 'AND' : 'WHERE');
|
|
if($hasReplies)
|
|
$query .= sprintf(' %s comment_reply_to %s NULL', ++$args > 1 ? 'AND' : 'WHERE', $replies ? 'IS NOT' : 'IS');
|
|
if($hasDeleted)
|
|
$query .= sprintf(' %s comment_deleted %s NULL', ++$args > 1 ? 'AND' : 'WHERE', $deleted ? 'IS NOT' : 'IS');
|
|
if($hasUserInfo)
|
|
$query .= sprintf(' %s user_id = ?', ++$args > 1 ? 'AND' : 'WHERE');
|
|
|
|
$stmt = $this->cache->get($query);
|
|
if($hasParentInfo)
|
|
$stmt->nextParameter($parentInfo);
|
|
elseif($hasCategoryInfo)
|
|
$stmt->nextParameter($categoryInfo);
|
|
if($hasCategoryName)
|
|
$stmt->nextParameter($categoryName);
|
|
if($hasUserInfo)
|
|
$stmt->nextParameter($userInfo instanceof UserInfo ? $userInfo->id : $userInfo);
|
|
$stmt->execute();
|
|
|
|
$result = $stmt->getResult();
|
|
$count = 0;
|
|
|
|
if($result->next())
|
|
$count = $result->getInteger(0);
|
|
|
|
return $count;
|
|
}
|
|
|
|
/** @return \Iterator<int, CommentsPostInfo> */
|
|
public function getPosts(
|
|
CommentsCategoryInfo|string|null $categoryInfo = null,
|
|
?string $categoryName = null,
|
|
CommentsPostInfo|string|null $parentInfo = null,
|
|
UserInfo|string|null $userInfo = null,
|
|
?bool $replies = null,
|
|
?bool $deleted = null
|
|
): iterable {
|
|
if($categoryInfo instanceof CommentsCategoryInfo)
|
|
$categoryInfo = $categoryInfo->id;
|
|
if($parentInfo instanceof CommentsPostInfo)
|
|
$parentInfo = $parentInfo->id;
|
|
|
|
$hasCategoryInfo = $categoryInfo !== null;
|
|
$hasCategoryName = $categoryName !== null;
|
|
$hasParentInfo = $parentInfo !== null;
|
|
$hasUserInfo = $userInfo !== null;
|
|
$hasReplies = $replies !== null;
|
|
$hasDeleted = $deleted !== null;
|
|
|
|
$args = 0;
|
|
$query = <<<SQL
|
|
SELECT comment_id, category_id, user_id, comment_reply_to, comment_text,
|
|
UNIX_TIMESTAMP(comment_created),
|
|
UNIX_TIMESTAMP(comment_pinned),
|
|
UNIX_TIMESTAMP(comment_edited),
|
|
UNIX_TIMESTAMP(comment_deleted)
|
|
FROM msz_comments_posts
|
|
SQL;
|
|
|
|
if($hasParentInfo) {
|
|
++$args;
|
|
$query .= ' WHERE comment_reply_to = ?';
|
|
}
|
|
if($hasCategoryInfo)
|
|
$query .= sprintf(' %s category_id = ?', ++$args > 1 ? 'AND' : 'WHERE');
|
|
if($hasCategoryName)
|
|
$query .= sprintf(' %s category_id = (SELECT category_id FROM msz_comments_categories WHERE category_name = ?)', ++$args > 1 ? 'AND' : 'WHERE');
|
|
if($hasReplies)
|
|
$query .= sprintf(' %s comment_reply_to %s NULL', ++$args > 1 ? 'AND' : 'WHERE', $replies ? 'IS NOT' : 'IS');
|
|
if($hasDeleted)
|
|
$query .= sprintf(' %s comment_deleted %s NULL', ++$args > 1 ? 'AND' : 'WHERE', $deleted ? 'IS NOT' : 'IS');
|
|
if($hasUserInfo)
|
|
$query .= sprintf(' %s user_id = ?', ++$args > 1 ? 'AND' : 'WHERE');
|
|
|
|
// this should really not be implicit like this
|
|
if($hasParentInfo)
|
|
$query .= ' ORDER BY comment_deleted ASC, comment_pinned DESC, comment_created ASC';
|
|
elseif($hasCategoryInfo)
|
|
$query .= ' ORDER BY comment_deleted ASC, comment_pinned DESC, comment_created DESC';
|
|
else
|
|
$query .= ' ORDER BY comment_created DESC';
|
|
|
|
$stmt = $this->cache->get($query);
|
|
if($hasParentInfo)
|
|
$stmt->nextParameter($parentInfo);
|
|
elseif($hasCategoryInfo)
|
|
$stmt->nextParameter($categoryInfo);
|
|
if($hasCategoryName)
|
|
$stmt->nextParameter($categoryName);
|
|
if($hasUserInfo)
|
|
$stmt->nextParameter($userInfo instanceof UserInfo ? $userInfo->id : $userInfo);
|
|
$stmt->execute();
|
|
|
|
return $stmt->getResultIterator(CommentsPostInfo::fromResult(...));
|
|
}
|
|
|
|
public function getPost(string $postId): CommentsPostInfo {
|
|
$stmt = $this->cache->get(<<<SQL
|
|
SELECT comment_id, category_id, user_id, comment_reply_to, comment_text,
|
|
UNIX_TIMESTAMP(comment_created),
|
|
UNIX_TIMESTAMP(comment_pinned),
|
|
UNIX_TIMESTAMP(comment_edited),
|
|
UNIX_TIMESTAMP(comment_deleted)
|
|
FROM msz_comments_posts
|
|
WHERE comment_id = ?
|
|
SQL);
|
|
$stmt->nextParameter($postId);
|
|
$stmt->execute();
|
|
|
|
$result = $stmt->getResult();
|
|
if(!$result->next())
|
|
throw new RuntimeException('No comment with that ID exists.');
|
|
|
|
return CommentsPostInfo::fromResult($result);
|
|
}
|
|
|
|
public function createPost(
|
|
CommentsCategoryInfo|string|null $category,
|
|
CommentsPostInfo|string|null $parent,
|
|
UserInfo|string|null $user,
|
|
string $body,
|
|
bool $pin = false
|
|
): CommentsPostInfo {
|
|
if($category instanceof CommentsCategoryInfo)
|
|
$category = $category->id;
|
|
if($parent instanceof CommentsPostInfo) {
|
|
if($category === null)
|
|
$category = $parent->categoryId;
|
|
elseif($category !== $parent->categoryId)
|
|
throw new InvalidArgumentException('$parent belongs to a different category than where this post is attempted to be created.');
|
|
$parent = $parent->id;
|
|
}
|
|
if($category === null)
|
|
throw new InvalidArgumentException('$category is null; at least a $category or $parent must be specified.');
|
|
if($user instanceof UserInfo)
|
|
$user = $user->id;
|
|
if(empty(trim($body)))
|
|
throw new InvalidArgumentException('$body may not be empty.');
|
|
|
|
$stmt = $this->cache->get(<<<SQL
|
|
INSERT INTO msz_comments_posts (
|
|
category_id, user_id, comment_reply_to, comment_text, comment_pinned
|
|
) VALUES (?, ?, ?, ?, IF(?, NOW(), NULL))
|
|
SQL);
|
|
$stmt->nextParameter($category);
|
|
$stmt->nextParameter($user);
|
|
$stmt->nextParameter($parent);
|
|
$stmt->nextParameter($body);
|
|
$stmt->nextParameter($pin ? 1 : 0);
|
|
$stmt->execute();
|
|
|
|
return $this->getPost((string)$stmt->lastInsertId);
|
|
}
|
|
|
|
public function deletePost(CommentsPostInfo|string $infoOrId): void {
|
|
if($infoOrId instanceof CommentsPostInfo)
|
|
$infoOrId = $infoOrId->id;
|
|
|
|
$stmt = $this->cache->get(<<<SQL
|
|
UPDATE msz_comments_posts
|
|
SET comment_deleted = COALESCE(comment_deleted, NOW())
|
|
WHERE comment_id = ?
|
|
SQL);
|
|
$stmt->nextParameter($infoOrId);
|
|
$stmt->execute();
|
|
}
|
|
|
|
public function nukePost(CommentsPostInfo|string $infoOrId): void {
|
|
if($infoOrId instanceof CommentsPostInfo)
|
|
$infoOrId = $infoOrId->id;
|
|
|
|
$stmt = $this->cache->get(<<<SQL
|
|
DELETE FROM msz_comments_posts
|
|
WHERE comment_id = ?
|
|
SQL);
|
|
$stmt->nextParameter($infoOrId);
|
|
$stmt->execute();
|
|
}
|
|
|
|
public function restorePost(CommentsPostInfo|string $infoOrId): void {
|
|
if($infoOrId instanceof CommentsPostInfo)
|
|
$infoOrId = $infoOrId->id;
|
|
|
|
$stmt = $this->cache->get(<<<SQL
|
|
UPDATE msz_comments_posts
|
|
SET comment_deleted = NULL
|
|
WHERE comment_id = ?
|
|
SQL);
|
|
$stmt->nextParameter($infoOrId);
|
|
$stmt->execute();
|
|
}
|
|
|
|
public function updatePost(
|
|
CommentsPostInfo|string $infoOrId,
|
|
?string $body,
|
|
?bool $pinned,
|
|
bool $edited = false
|
|
): void {
|
|
if($infoOrId instanceof CommentsPostInfo)
|
|
$infoOrId = $infoOrId->id;
|
|
|
|
$fields = [];
|
|
$values = [];
|
|
|
|
if($body !== null) {
|
|
if(trim($body) === '')
|
|
throw new InvalidArgumentException('$body must be null or a non-empty string.');
|
|
|
|
$fields[] = 'comment_text = ?';
|
|
$values[] = $body;
|
|
}
|
|
|
|
if($pinned !== null)
|
|
$fields[] = $pinned ? 'comment_pinned = COALESCE(comment_pinned, NOW())' : 'comment_pinned = NULL';
|
|
|
|
if($edited)
|
|
$fields[] = 'comment_edited = NOW()';
|
|
|
|
if(empty($fields))
|
|
return;
|
|
|
|
$stmt = $this->cache->get(sprintf('UPDATE msz_comments_posts SET %s WHERE comment_id = ?', implode(', ', $fields)));
|
|
foreach($values as $value)
|
|
$stmt->nextParameter($value);
|
|
$stmt->nextParameter($infoOrId);
|
|
$stmt->execute();
|
|
}
|
|
}
|