400 lines
16 KiB
PHP
400 lines
16 KiB
PHP
|
<?php
|
||
|
namespace Misuzu\Messages;
|
||
|
|
||
|
use InvalidArgumentException;
|
||
|
use RuntimeException;
|
||
|
use Index\DateTime;
|
||
|
use Index\Data\{DbStatementCache,DbTools,IDbConnection};
|
||
|
use Misuzu\Pagination;
|
||
|
use Misuzu\Users\UserInfo;
|
||
|
|
||
|
class MessagesDatabase {
|
||
|
private DbStatementCache $cache;
|
||
|
|
||
|
public function __construct(private IDbConnection $dbConn) {
|
||
|
$this->cache = new DbStatementCache($dbConn);
|
||
|
}
|
||
|
|
||
|
public function countMessages(
|
||
|
UserInfo|string|null $ownerInfo = null,
|
||
|
UserInfo|string|null $authorInfo = null,
|
||
|
UserInfo|string|null $recipientInfo = null,
|
||
|
MessageInfo|string|null $repliesFor = null,
|
||
|
MessageInfo|string|null $replyTo = null,
|
||
|
?bool $sent = null,
|
||
|
?bool $read = null,
|
||
|
?bool $deleted = null
|
||
|
): int {
|
||
|
$hasOwnerInfo = $ownerInfo !== null;
|
||
|
$hasAuthorInfo = $authorInfo !== null;
|
||
|
$hasRecipientInfo = $recipientInfo !== null;
|
||
|
$hasRepliesFor = $repliesFor !== null;
|
||
|
$hasReplyTo = $replyTo !== null;
|
||
|
$hasSent = $sent !== null;
|
||
|
$hasRead = $read !== null;
|
||
|
$hasDeleted = $deleted !== null;
|
||
|
|
||
|
$args = 0;
|
||
|
$query = 'SELECT COUNT(*) FROM msz_messages';
|
||
|
if($hasOwnerInfo) {
|
||
|
++$args;
|
||
|
$query .= ' WHERE msg_owner_id = ?';
|
||
|
}
|
||
|
if($hasAuthorInfo)
|
||
|
$query .= sprintf(' %s msg_author_id = ?', ++$args > 1 ? 'AND' : 'WHERE');
|
||
|
if($hasRecipientInfo)
|
||
|
$query .= sprintf(' %s msg_recipient_id = ?', ++$args > 1 ? 'AND' : 'WHERE');
|
||
|
if($hasRepliesFor)
|
||
|
$query .= sprintf(' %s msg_reply_to = ?', ++$args > 1 ? 'AND' : 'WHERE');
|
||
|
if($hasReplyTo) {
|
||
|
$query .= sprintf(' %s msg_id = ', ++$args > 1 ? 'AND' : 'WHERE');
|
||
|
|
||
|
if($replyTo instanceof MessageInfo)
|
||
|
$query .= '?';
|
||
|
else
|
||
|
$query .= '(SELECT reply_to FROM msz_messages WHERE msg_id = ?)';
|
||
|
}
|
||
|
if($hasSent)
|
||
|
$query .= sprintf(' %s msg_sent %s NULL', ++$args > 1 ? 'AND' : 'WHERE', $sent ? 'IS NOT' : 'IS');
|
||
|
if($hasRead)
|
||
|
$query .= sprintf(' %s msg_read %s NULL', ++$args > 1 ? 'AND' : 'WHERE', $read ? 'IS NOT' : 'IS');
|
||
|
if($hasDeleted)
|
||
|
$query .= sprintf(' %s msg_deleted %s NULL', ++$args > 1 ? 'AND' : 'WHERE', $deleted ? 'IS NOT' : 'IS');
|
||
|
$query .= ' ORDER BY msg_created DESC';
|
||
|
|
||
|
$args = 0;
|
||
|
$stmt = $this->cache->get($query);
|
||
|
|
||
|
if($hasOwnerInfo)
|
||
|
$stmt->addParameter(++$args, $ownerInfo instanceof UserInfo ? $ownerInfo->getId() : $ownerInfo);
|
||
|
if($hasAuthorInfo)
|
||
|
$stmt->addParameter(++$args, $authorInfo instanceof UserInfo ? $authorInfo->getId() : $authorInfo);
|
||
|
if($hasRecipientInfo)
|
||
|
$stmt->addParameter(++$args, $recipientInfo instanceof UserInfo ? $recipientInfo->getId() : $recipientInfo);
|
||
|
if($hasRepliesFor)
|
||
|
$stmt->addParameter(++$args, $repliesFor instanceof MessageInfo ? $repliesFor->getId() : $repliesFor);
|
||
|
if($hasReplyTo)
|
||
|
$stmt->addParameter(++$args, $replyTo instanceof MessageInfo ? $replyTo->getReplyToId() : $replyTo);
|
||
|
|
||
|
$stmt->execute();
|
||
|
$result = $stmt->getResult();
|
||
|
|
||
|
return $result->next() ? $result->getInteger(0) : 0;
|
||
|
}
|
||
|
|
||
|
public function getMessages(
|
||
|
UserInfo|string|null $ownerInfo = null,
|
||
|
UserInfo|string|null $authorInfo = null,
|
||
|
UserInfo|string|null $recipientInfo = null,
|
||
|
MessageInfo|string|null $repliesFor = null,
|
||
|
MessageInfo|string|null $replyTo = null,
|
||
|
?bool $sent = null,
|
||
|
?bool $read = null,
|
||
|
?bool $deleted = null,
|
||
|
?Pagination $pagination = null
|
||
|
): array {
|
||
|
$hasOwnerInfo = $ownerInfo !== null;
|
||
|
$hasAuthorInfo = $authorInfo !== null;
|
||
|
$hasRecipientInfo = $recipientInfo !== null;
|
||
|
$hasRepliesFor = $repliesFor !== null;
|
||
|
$hasReplyTo = $replyTo !== null;
|
||
|
$hasSent = $sent !== null;
|
||
|
$hasRead = $read !== null;
|
||
|
$hasDeleted = $deleted !== null;
|
||
|
$hasPagination = $pagination !== null;
|
||
|
|
||
|
$args = 0;
|
||
|
$query = 'SELECT msg_id, msg_owner_id, msg_author_id, msg_recipient_id, msg_reply_to, msg_title, msg_body, msg_parser, UNIX_TIMESTAMP(msg_created), UNIX_TIMESTAMP(msg_sent), UNIX_TIMESTAMP(msg_read), UNIX_TIMESTAMP(msg_deleted) FROM msz_messages';
|
||
|
if($hasOwnerInfo) {
|
||
|
++$args;
|
||
|
$query .= ' WHERE msg_owner_id = ?';
|
||
|
}
|
||
|
if($hasAuthorInfo)
|
||
|
$query .= sprintf(' %s msg_author_id = ?', ++$args > 1 ? 'AND' : 'WHERE');
|
||
|
if($hasRecipientInfo)
|
||
|
$query .= sprintf(' %s msg_recipient_id = ?', ++$args > 1 ? 'AND' : 'WHERE');
|
||
|
if($hasRepliesFor)
|
||
|
$query .= sprintf(' %s msg_reply_to = ?', ++$args > 1 ? 'AND' : 'WHERE');
|
||
|
if($hasReplyTo) {
|
||
|
$query .= sprintf(' %s msg_id = ', ++$args > 1 ? 'AND' : 'WHERE');
|
||
|
|
||
|
if($replyTo instanceof MessageInfo)
|
||
|
$query .= '?';
|
||
|
else
|
||
|
$query .= '(SELECT reply_to FROM msz_messages WHERE msg_id = ?)';
|
||
|
}
|
||
|
if($hasSent)
|
||
|
$query .= sprintf(' %s msg_sent %s NULL', ++$args > 1 ? 'AND' : 'WHERE', $sent ? 'IS NOT' : 'IS');
|
||
|
if($hasRead)
|
||
|
$query .= sprintf(' %s msg_read %s NULL', ++$args > 1 ? 'AND' : 'WHERE', $read ? 'IS NOT' : 'IS');
|
||
|
if($hasDeleted)
|
||
|
$query .= sprintf(' %s msg_deleted %s NULL', ++$args > 1 ? 'AND' : 'WHERE', $deleted ? 'IS NOT' : 'IS');
|
||
|
$query .= ' ORDER BY msg_created DESC';
|
||
|
if($hasPagination)
|
||
|
$query .= ' LIMIT ? OFFSET ?';
|
||
|
|
||
|
$args = 0;
|
||
|
$stmt = $this->cache->get($query);
|
||
|
|
||
|
if($hasOwnerInfo)
|
||
|
$stmt->addParameter(++$args, $ownerInfo instanceof UserInfo ? $ownerInfo->getId() : $ownerInfo);
|
||
|
if($hasAuthorInfo)
|
||
|
$stmt->addParameter(++$args, $authorInfo instanceof UserInfo ? $authorInfo->getId() : $authorInfo);
|
||
|
if($hasRecipientInfo)
|
||
|
$stmt->addParameter(++$args, $recipientInfo instanceof UserInfo ? $recipientInfo->getId() : $recipientInfo);
|
||
|
if($hasRepliesFor)
|
||
|
$stmt->addParameter(++$args, $repliesFor instanceof MessageInfo ? $repliesFor->getId() : $repliesFor);
|
||
|
if($hasReplyTo)
|
||
|
$stmt->addParameter(++$args, $replyTo instanceof MessageInfo ? $replyTo->getReplyToId() : $replyTo);
|
||
|
if($hasPagination) {
|
||
|
$stmt->addParameter(++$args, $pagination->getRange());
|
||
|
$stmt->addParameter(++$args, $pagination->getOffset());
|
||
|
}
|
||
|
|
||
|
$stmt->execute();
|
||
|
|
||
|
$infos = [];
|
||
|
$result = $stmt->getResult();
|
||
|
|
||
|
while($result->next())
|
||
|
$infos[] = new MessageInfo($result);
|
||
|
|
||
|
return $infos;
|
||
|
}
|
||
|
|
||
|
public function getMessageInfo(
|
||
|
UserInfo|string $ownerInfo,
|
||
|
MessageInfo|string $messageInfoOrId,
|
||
|
bool $useReplyTo = false
|
||
|
): MessageInfo {
|
||
|
$stmt = $this->cache->get(sprintf(
|
||
|
'SELECT msg_id, msg_owner_id, msg_author_id, msg_recipient_id, msg_reply_to, msg_title, msg_body, msg_parser, UNIX_TIMESTAMP(msg_created), UNIX_TIMESTAMP(msg_sent), UNIX_TIMESTAMP(msg_read), UNIX_TIMESTAMP(msg_deleted) FROM msz_messages WHERE msg_id = %s AND msg_owner_id = ?',
|
||
|
!$useReplyTo || $messageInfoOrId instanceof MessageInfo ? '?' : '(SELECT msg_reply_to FROM msz_messages WHERE msg_id = ?)'
|
||
|
));
|
||
|
|
||
|
if($messageInfoOrId instanceof MessageInfo)
|
||
|
$stmt->addParameter(1, $useReplyTo ? $messageInfoOrId->getReplyToId() : $messageInfoOrId->getId());
|
||
|
else
|
||
|
$stmt->addParameter(1, $messageInfoOrId);
|
||
|
$stmt->addParameter(2, $ownerInfo instanceof UserInfo ? $ownerInfo->getId() : $ownerInfo);
|
||
|
$stmt->execute();
|
||
|
|
||
|
$result = $stmt->getResult();
|
||
|
if(!$result->next())
|
||
|
throw new RuntimeException('Message not found.');
|
||
|
|
||
|
return new MessageInfo($result);
|
||
|
}
|
||
|
|
||
|
public function createMessage(
|
||
|
string $messageId,
|
||
|
UserInfo|string $ownerInfo,
|
||
|
UserInfo|string|null $authorInfo,
|
||
|
UserInfo|string|null $recipientInfo,
|
||
|
string $title,
|
||
|
string $body,
|
||
|
int $parser,
|
||
|
MessageInfo|string|null $replyTo = null,
|
||
|
DateTime|int|null $sentAt = null,
|
||
|
DateTime|int|null $readAt = null
|
||
|
): MessageInfo {
|
||
|
$stmt = $this->cache->get('INSERT INTO msz_messages (msg_id, msg_owner_id, msg_author_id, msg_recipient_id, msg_reply_to, msg_title, msg_body, msg_parser, msg_sent, msg_read) VALUES (?, ?, ?, ?, ?, ?, ?, ?, FROM_UNIXTIME(?), FROM_UNIXTIME(?))');
|
||
|
$stmt->addParameter(1, $messageId);
|
||
|
$stmt->addParameter(2, $ownerInfo instanceof UserInfo ? $ownerInfo->getId() : $ownerInfo);
|
||
|
$stmt->addParameter(3, $authorInfo instanceof UserInfo ? $authorInfo->getId() : $authorInfo);
|
||
|
$stmt->addParameter(4, $recipientInfo instanceof UserInfo ? $recipientInfo->getId() : $recipientInfo);
|
||
|
$stmt->addParameter(5, $replyTo instanceof MessageInfo ? $replyTo->getId() : $replyTo);
|
||
|
$stmt->addParameter(6, $title);
|
||
|
$stmt->addParameter(7, $body);
|
||
|
$stmt->addParameter(8, $parser);
|
||
|
$stmt->addParameter(9, $sentAt instanceof DateTime ? $sentAt->getUnixTimeSeconds() : $sentAt);
|
||
|
$stmt->addParameter(10, $readAt instanceof DateTime ? $readAt->getUnixTimeSeconds() : $readAt);
|
||
|
$stmt->execute();
|
||
|
|
||
|
return $this->getMessageInfo($ownerInfo, $messageId);
|
||
|
}
|
||
|
|
||
|
public function updateMessage(
|
||
|
UserInfo|string|null $ownerInfo = null,
|
||
|
MessageInfo|string|null $messageInfo = null,
|
||
|
?string $title = null,
|
||
|
?string $body = null,
|
||
|
?int $parser = null,
|
||
|
DateTime|int|null|false $sentAt = false,
|
||
|
DateTime|int|null|false $readAt = false
|
||
|
): void {
|
||
|
$setQuery = [];
|
||
|
$setValues = [];
|
||
|
$whereQuery = [];
|
||
|
$whereValues = [];
|
||
|
|
||
|
if($ownerInfo !== null) {
|
||
|
$whereQuery[] = 'msg_owner_id = ?';
|
||
|
$whereValues[] = $ownerInfo instanceof UserInfo ? $ownerInfo->getId() : $ownerInfo;
|
||
|
}
|
||
|
|
||
|
if($messageInfo !== null) {
|
||
|
$whereQuery[] = 'msg_id = ?';
|
||
|
$whereValues[] = $messageInfo instanceof MessageInfo ? $messageInfo->getId() : $messageInfo;
|
||
|
}
|
||
|
|
||
|
if($title !== null) {
|
||
|
$setQuery[] = 'msg_title = ?';
|
||
|
$setValues[] = $title;
|
||
|
}
|
||
|
|
||
|
if($body !== null) {
|
||
|
$setQuery[] = 'msg_body = ?';
|
||
|
$setValues[] = $body;
|
||
|
}
|
||
|
|
||
|
if($parser !== null) {
|
||
|
$setQuery[] = 'msg_parser = ?';
|
||
|
$setValues[] = $parser;
|
||
|
}
|
||
|
|
||
|
if($sentAt !== false) {
|
||
|
$setQuery[] = 'msg_sent = FROM_UNIXTIME(?)';
|
||
|
$setValues[] = $sentAt instanceof DateTime ? $sentAt->getUnixTimeSeconds() : $sentAt;
|
||
|
}
|
||
|
|
||
|
if($readAt !== false) {
|
||
|
$setQuery[] = 'msg_read = FROM_UNIXTIME(?)';
|
||
|
$setValues[] = $readAt instanceof DateTime ? $readAt->getUnixTimeSeconds() : $readAt;
|
||
|
}
|
||
|
|
||
|
if(empty($whereQuery))
|
||
|
throw new InvalidArgumentException('$ownerInfo or $messageInfo must be specified.');
|
||
|
if(empty($setQuery))
|
||
|
return;
|
||
|
|
||
|
$args = 0;
|
||
|
$stmt = $this->cache->get(sprintf(
|
||
|
'UPDATE msz_messages SET %s WHERE %s',
|
||
|
implode(', ', $setQuery),
|
||
|
implode(' AND ', $whereQuery)
|
||
|
));
|
||
|
|
||
|
foreach($setValues as $value)
|
||
|
$stmt->addParameter(++$args, $value);
|
||
|
foreach($whereValues as $value)
|
||
|
$stmt->addParameter(++$args, $value);
|
||
|
|
||
|
$stmt->execute();
|
||
|
}
|
||
|
|
||
|
public function deleteMessages(
|
||
|
UserInfo|string|null $ownerInfo,
|
||
|
MessageInfo|array|string|null $messageInfos
|
||
|
): void {
|
||
|
$hasOwnerInfo = $ownerInfo !== null;
|
||
|
$hasMessageInfos = $messageInfos !== null;
|
||
|
|
||
|
$query = 'UPDATE msz_messages SET msg_deleted = NOW() WHERE msg_deleted IS NULL';
|
||
|
if($hasOwnerInfo)
|
||
|
$query .= ' AND msg_owner_id = ?';
|
||
|
if($hasMessageInfos) {
|
||
|
if(!is_array($messageInfos))
|
||
|
$messageInfos = [$messageInfos];
|
||
|
|
||
|
$query .= sprintf(
|
||
|
' AND msg_id IN (%s)',
|
||
|
DbTools::prepareListString($messageInfos)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
$args = 0;
|
||
|
$stmt = $this->cache->get($query);
|
||
|
|
||
|
if($hasOwnerInfo)
|
||
|
$stmt->addParameter(++$args, $ownerInfo instanceof UserInfo ? $ownerInfo->getId() : $ownerInfo);
|
||
|
if($hasMessageInfos)
|
||
|
foreach($messageInfos as $messageInfo) {
|
||
|
if(is_string($messageInfo))
|
||
|
$stmt->addParameter(++$args, $messageInfo);
|
||
|
elseif($messageInfo instanceof MessageInfo)
|
||
|
$stmt->addParameter(++$args, $messageInfo->getId());
|
||
|
else
|
||
|
throw new InvalidArgumentException('$messageInfos must be an array of strings or MessageInfo instances.');
|
||
|
}
|
||
|
|
||
|
$stmt->execute();
|
||
|
}
|
||
|
|
||
|
public function restoreMessages(
|
||
|
UserInfo|string|null $ownerInfo,
|
||
|
MessageInfo|array|string|null $messageInfos
|
||
|
): void {
|
||
|
$hasOwnerInfo = $ownerInfo !== null;
|
||
|
$hasMessageInfos = $messageInfos !== null;
|
||
|
|
||
|
$query = 'UPDATE msz_messages SET msg_deleted = NULL WHERE msg_deleted IS NOT NULL';
|
||
|
if($hasOwnerInfo)
|
||
|
$query .= ' AND msg_owner_id = ?';
|
||
|
if($hasMessageInfos) {
|
||
|
if(!is_array($messageInfos))
|
||
|
$messageInfos = [$messageInfos];
|
||
|
|
||
|
$query .= sprintf(
|
||
|
' AND msg_id IN (%s)',
|
||
|
DbTools::prepareListString($messageInfos)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
$args = 0;
|
||
|
$stmt = $this->cache->get($query);
|
||
|
|
||
|
if($hasOwnerInfo)
|
||
|
$stmt->addParameter(++$args, $ownerInfo instanceof UserInfo ? $ownerInfo->getId() : $ownerInfo);
|
||
|
if($hasMessageInfos)
|
||
|
foreach($messageInfos as $messageInfo) {
|
||
|
if(is_string($messageInfo))
|
||
|
$stmt->addParameter(++$args, $messageInfo);
|
||
|
elseif($messageInfo instanceof MessageInfo)
|
||
|
$stmt->addParameter(++$args, $messageInfo->getId());
|
||
|
else
|
||
|
throw new InvalidArgumentException('$messageInfos must be an array of strings or MessageInfo instances.');
|
||
|
}
|
||
|
|
||
|
$stmt->execute();
|
||
|
}
|
||
|
|
||
|
public function nukeMessages(
|
||
|
UserInfo|string|null $ownerInfo,
|
||
|
MessageInfo|array|string|null $messageInfos
|
||
|
): void {
|
||
|
$hasOwnerInfo = $ownerInfo !== null;
|
||
|
$hasMessageInfos = $messageInfos !== null;
|
||
|
|
||
|
$query = 'DELETE FROM msz_messages WHERE msg_deleted IS NOT NULL';
|
||
|
if($hasOwnerInfo)
|
||
|
$query .= ' AND msg_owner_id = ?';
|
||
|
if($hasMessageInfos) {
|
||
|
if(!is_array($messageInfos))
|
||
|
$messageInfos = [$messageInfos];
|
||
|
|
||
|
$query .= sprintf(
|
||
|
' AND msg_id IN (%s)',
|
||
|
DbTools::prepareListString($messageInfos)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
$args = 0;
|
||
|
$stmt = $this->cache->get($query);
|
||
|
|
||
|
if($hasOwnerInfo)
|
||
|
$stmt->addParameter(++$args, $ownerInfo instanceof UserInfo ? $ownerInfo->getId() : $ownerInfo);
|
||
|
if($hasMessageInfos)
|
||
|
foreach($messageInfos as $messageInfo) {
|
||
|
if(is_string($messageInfo))
|
||
|
$stmt->addParameter(++$args, $messageInfo);
|
||
|
elseif($messageInfo instanceof MessageInfo)
|
||
|
$stmt->addParameter(++$args, $messageInfo->getId());
|
||
|
else
|
||
|
throw new InvalidArgumentException('$messageInfos must be an array of strings or MessageInfo instances.');
|
||
|
}
|
||
|
|
||
|
$stmt->execute();
|
||
|
}
|
||
|
}
|