misuzu/src/Comments/CommentsCategoriesData.php

227 lines
7.1 KiB
PHP

<?php
namespace Misuzu\Comments;
use InvalidArgumentException;
use RuntimeException;
use Index\Db\{DbConnection,DbStatement,DbStatementCache};
use Misuzu\Pagination;
use Misuzu\Users\UserInfo;
class CommentsCategoriesData {
private DbStatementCache $cache;
public function __construct(DbConnection $dbConn) {
$this->cache = new DbStatementCache($dbConn);
}
public function countCategories(
UserInfo|string|null $owner = null
): int {
if($owner instanceof UserInfo)
$owner = $owner->id;
$hasOwner = $owner !== null;
$query = 'SELECT COUNT(*) FROM msz_comments_categories';
if($hasOwner)
$query .= ' WHERE user_id = ?';
$stmt = $this->cache->get($query);
$stmt->nextParameter($owner);
$stmt->execute();
$count = 0;
$result = $stmt->getResult();
if($result->next())
$count = $result->getInteger(0);
return $count;
}
/** @return \Iterator<int, CommentsCategoryInfo> */
public function getCategories(
UserInfo|string|null $owner = null,
?Pagination $pagination = null
): iterable {
if($owner instanceof UserInfo)
$owner = $owner->id;
$hasOwner = $owner !== null;
$hasPagination = $pagination !== null;
$query = <<<SQL
SELECT category_id, category_name, user_id,
UNIX_TIMESTAMP(category_created),
UNIX_TIMESTAMP(category_locked)
FROM msz_comments_categories
SQL;
if($hasOwner)
$query .= ' WHERE user_id = ?';
$query .= ' ORDER BY category_id ASC'; // should order by date but no index on
if($hasPagination)
$query .= ' LIMIT ? RANGE ?';
$stmt = $this->cache->get($query);
if($hasOwner)
$stmt->nextParameter($owner);
if($hasPagination)
$pagination->addToStatement($stmt);
$stmt->execute();
return $stmt->getResultIterator(CommentsCategoryInfo::fromResult(...));
}
public function getCategory(
?string $categoryId = null,
?string $name = null,
CommentsPostInfo|string|null $postInfo = null
): CommentsCategoryInfo {
$hasCategoryId = $categoryId !== null;
$hasName = $name !== null;
$hasPostInfo = $postInfo !== null;
if(!$hasCategoryId && !$hasName && !$hasPostInfo)
throw new InvalidArgumentException('At least one of the arguments must be set.');
// there has got to be a better way to do this
if(($hasCategoryId && ($hasName || $hasPostInfo)) || ($hasName && ($hasCategoryId || $hasPostInfo)) || ($hasPostInfo && ($hasCategoryId || $hasName)))
throw new InvalidArgumentException('Only one of the arguments may be specified.');
$query = <<<SQL
SELECT category_id, category_name, user_id,
UNIX_TIMESTAMP(category_created),
UNIX_TIMESTAMP(category_locked)
FROM msz_comments_categories
SQL;
$value = null;
if($hasCategoryId) {
$query .= ' WHERE category_id = ?';
$value = $categoryId;
}
if($hasName) {
$query .= ' WHERE category_name = ?';
$value = $name;
}
if($hasPostInfo) {
if($postInfo instanceof CommentsPostInfo) {
$query .= ' WHERE category_id = ?';
$value = $postInfo->categoryId;
} else {
$query .= ' WHERE category_id = (SELECT category_id FROM msz_comments_posts WHERE comment_id = ?)';
$value = $postInfo;
}
}
$stmt = $this->cache->get($query);
$stmt->nextParameter($value);
$stmt->execute();
$result = $stmt->getResult();
if(!$result->next())
throw new RuntimeException('Comments category not found.');
return CommentsCategoryInfo::fromResult($result);
}
private function createCategoryInternal(
string $name,
UserInfo|string|null $owner = null,
): DbStatement {
if($owner instanceof UserInfo)
$owner = $owner->id;
$name = trim($name);
if(empty($name))
throw new InvalidArgumentException('$name may not be empty.');
$stmt = $this->cache->get(<<<SQL
INSERT INTO msz_comments_categories (
category_name, user_id
) VALUES (?, ?)
SQL);
$stmt->nextParameter($name);
$stmt->nextParameter($owner);
$stmt->execute();
return $stmt;
}
public function createCategory(
string $name,
UserInfo|string|null $owner = null
): CommentsCategoryInfo {
return $this->getCategory(
categoryId: (string)$this->createCategoryInternal($name, $owner)->lastInsertId,
);
}
public function ensureCategoryExists(
string $name,
UserInfo|string|null $owner = null
): void {
$stmt = $this->cache->get(<<<SQL
SELECT COUNT(*)
FROM msz_comments_categories
WHERE category_name = ?
SQL);
$stmt->nextParameter($name);
$stmt->execute();
$result = $stmt->getResult();
if(!$result->next())
throw new RuntimeException('failed to query for the existence of comments category');
if(!$result->getBoolean(0))
$this->createCategoryInternal($name, $owner);
}
public function deleteCategory(CommentsCategoryInfo|string $category): void {
if($category instanceof CommentsCategoryInfo)
$category = $category->id;
$stmt = $this->cache->get(<<<SQL
DELETE FROM msz_comments_categories
WHERE category_id = ?
SQL);
$stmt->nextParameter($category);
$stmt->execute();
}
public function updateCategory(
CommentsCategoryInfo|string $infoOrId,
?string $name = null,
?bool $locked = null,
UserInfo|string|false|null $ownerInfo = null
): void {
$fields = [];
$values = [];
if($name !== null) {
if(trim($name) === '')
throw new InvalidArgumentException('$name must be null or a non-empty string.');
$fields[] = 'category_name = ?';
$values[] = $name;
}
if($locked !== null)
$fields[] = $locked ? 'category_locked = COALESCE(category_locked, NOW())' : 'category_locked = NULL';
if($ownerInfo !== null) {
if($ownerInfo === false) {
$fields[] = 'user_id = NULL';
} else {
$fields[] = 'user_id = ?';
$values[] = $ownerInfo instanceof UserInfo ? $ownerInfo->id : $ownerInfo;
}
}
$stmt = $this->cache->get(sprintf('UPDATE msz_comments_categories SET %s WHERE category_id = ?', implode(', ', $fields)));
foreach($values as $value)
$stmt->nextParameter($value);
$stmt->nextParameter($infoOrId instanceof CommentsCategoryInfo ? $infoOrId->id : $infoOrId);
$stmt->execute();
}
}