*/ class ThreadMessageMapper extends QBMapper { public function __construct(IDBConnection $db) { parent::__construct($db, 'nuqloud_scrum_thread_messages', ThreadMessage::class); } public function findByTalkMessage(int $threadId, int $talkMessageId): ThreadMessage { $qb = $this->db->getQueryBuilder(); $qb->select('*') ->from($this->getTableName()) ->where($qb->expr()->eq('thread_id', $qb->createNamedParameter($threadId, IQueryBuilder::PARAM_INT))) ->andWhere($qb->expr()->eq('talk_message_id', $qb->createNamedParameter($talkMessageId, IQueryBuilder::PARAM_INT))); return $this->findEntity($qb); } /** @return ThreadMessage[] */ public function findByThread(int $threadId, int $limit = 200): array { $qb = $this->db->getQueryBuilder(); $qb->select('*') ->from($this->getTableName()) ->where($qb->expr()->eq('thread_id', $qb->createNamedParameter($threadId, IQueryBuilder::PARAM_INT))) ->orderBy('talk_message_id', 'ASC') ->setMaxResults(max(1, min(500, $limit))); return $this->findEntities($qb); } /** @param array $fields */ public function upsertMessage(int $threadId, int $talkMessageId, array $fields): ThreadMessage { $now = time(); try { $message = $this->findByTalkMessage($threadId, $talkMessageId); } catch (DoesNotExistException) { $message = new ThreadMessage(); $message->setThreadId($threadId); $message->setTalkMessageId($talkMessageId); $message->setCreatedAt($now); } $text = (string)($fields['messageText'] ?? $message->getMessageText() ?? ''); $message->setActorType($this->boundedString($fields['actorType'] ?? $message->getActorType(), 64, 'users')); $message->setActorId($this->boundedString($fields['actorId'] ?? $message->getActorId(), 128, '')); $message->setActorDisplayName($this->nullableString($fields['actorDisplayName'] ?? $message->getActorDisplayName())); $message->setMessageText($text); $message->setMessageHash(hash('sha256', $text)); $message->setRawPayload($this->nullableString($fields['rawPayload'] ?? $message->getRawPayload())); $message->setUpdatedAt($now); return $message->getId() === null ? $this->insert($message) : $this->update($message); } private function nullableString(mixed $value): ?string { $value = trim((string)$value); return $value === '' ? null : $value; } private function boundedString(mixed $value, int $maxLength, string $fallback): string { $value = trim((string)$value); if ($value === '') { $value = $fallback; } if (function_exists('mb_substr')) { return mb_substr($value, 0, $maxLength); } return substr($value, 0, $maxLength); } }