*/ class LocalMessageMapper extends QBMapper { /** @var LocalAttachmentMapper */ private $attachmentMapper; /** @var RecipientMapper */ private $recipientMapper; public function __construct(IDBConnection $db, LocalAttachmentMapper $attachmentMapper, RecipientMapper $recipientMapper) { parent::__construct($db, 'mail_local_messages'); $this->recipientMapper = $recipientMapper; $this->attachmentMapper = $attachmentMapper; } /** * @param string $userId * @return LocalMessage[] * @throws DBException */ public function getAllForUser(string $userId, int $type = LocalMessage::TYPE_OUTGOING): array { $qb = $this->db->getQueryBuilder(); $qb->select('m.*') ->from('mail_accounts', 'a') ->join('a', $this->getTableName(), 'm', $qb->expr()->eq('m.account_id', 'a.id')) ->where( $qb->expr()->eq('a.user_id', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR), IQueryBuilder::PARAM_STR), $qb->expr()->eq('m.type', $qb->createNamedParameter($type, IQueryBuilder::PARAM_INT), IQueryBuilder::PARAM_INT), $qb->expr()->neq('m.status', $qb->createNamedParameter(LocalMessage::STATUS_PROCESSED, IQueryBuilder::PARAM_INT), IQueryBuilder::PARAM_INT) ); $rows = $qb->executeQuery(); $results = []; $ids = []; while (($row = $rows->fetch()) !== false) { $results[] = $this->mapRowToEntity($row); $ids[] = $row['id']; } $rows->closeCursor(); if ($ids === []) { return []; } $attachments = $this->attachmentMapper->findByLocalMessageIds($ids); $recipients = $this->recipientMapper->findByLocalMessageIds($ids); $recipientMap = []; foreach ($recipients as $r) { $recipientMap[$r->getLocalMessageId()][] = $r; } $attachmentMap = []; foreach ($attachments as $a) { $attachmentMap[$a->getLocalMessageId()][] = $a; } return array_map(static function ($localMessage) use ($attachmentMap, $recipientMap) { $localMessage->setAttachments($attachmentMap[$localMessage->getId()] ?? []); $localMessage->setRecipients($recipientMap[$localMessage->getId()] ?? []); return $localMessage; }, $results); } /** * @param LocalMessage::TYPE_* $type * @throws DoesNotExistException */ public function findById(int $id, string $userId, int $type): LocalMessage { $qb = $this->db->getQueryBuilder(); $qb->select('m.*') ->from('mail_accounts', 'a') ->join('a', $this->getTableName(), 'm', $qb->expr()->eq('m.account_id', 'a.id')) ->where( $qb->expr()->eq('a.user_id', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR), IQueryBuilder::PARAM_STR), $qb->expr()->eq('m.id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT), IQueryBuilder::PARAM_INT), $qb->expr()->eq('type', $qb->createNamedParameter($type, IQueryBuilder::PARAM_INT), IQueryBuilder::PARAM_INT), ); $entity = $this->findEntity($qb); $entity->setAttachments($this->attachmentMapper->findByLocalMessageId($userId, $id)); $entity->setRecipients($this->recipientMapper->findByLocalMessageId($id)); return $entity; } /** * Find all messages that should be sent * * @param int $time upper bound send time stamp * * @return LocalMessage[] */ public function findDue(int $time, int $type = LocalMessage::TYPE_OUTGOING): array { $qb = $this->db->getQueryBuilder(); $select = $qb->select('*') ->from($this->getTableName()) ->where( $qb->expr()->isNotNull('send_at'), $qb->expr()->eq('type', $qb->createNamedParameter($type, IQueryBuilder::PARAM_INT), IQueryBuilder::PARAM_INT), $qb->expr()->lte('send_at', $qb->createNamedParameter($time, IQueryBuilder::PARAM_INT), IQueryBuilder::PARAM_INT), ) ->orderBy('send_at', 'asc'); $messages = $this->findEntities($select); if (empty($messages)) { return []; } $ids = array_map(static fn (LocalMessage $message) => $message->getId(), $messages); $attachments = $this->attachmentMapper->findByLocalMessageIds($ids); $recipients = $this->recipientMapper->findByLocalMessageIds($ids); $recipientMap = []; foreach ($recipients as $r) { $recipientMap[$r->getLocalMessageId()][] = $r; } $attachmentMap = []; foreach ($attachments as $a) { $attachmentMap[$a->getLocalMessageId()][] = $a; } return array_map(static function ($localMessage) use ($attachmentMap, $recipientMap) { $localMessage->setAttachments($attachmentMap[$localMessage->getId()] ?? []); $localMessage->setRecipients($recipientMap[$localMessage->getId()] ?? []); return $localMessage; }, $messages); } /** * Find all messages that should be sent * * @param int $time upper bound send time stamp * * @return LocalMessage[] */ public function findDueDrafts(int $time): array { $qb = $this->db->getQueryBuilder(); $select = $qb->select('*') ->from($this->getTableName()) ->where( $qb->expr()->isNull('send_at'), $qb->expr()->eq('type', $qb->createNamedParameter(LocalMessage::TYPE_DRAFT, IQueryBuilder::PARAM_INT), IQueryBuilder::PARAM_INT), $qb->expr()->lte('updated_at', $qb->createNamedParameter($time - 300, IQueryBuilder::PARAM_INT), IQueryBuilder::PARAM_INT), $qb->expr()->orX( $qb->expr()->isNull('failed'), $qb->expr()->eq('failed', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL), IQueryBuilder::PARAM_BOOL), ) ) ->orderBy('updated_at', 'asc') ->orderBy('account_id', 'asc'); $messages = $this->findEntities($select); if (empty($messages)) { return []; } $ids = array_map(static fn (LocalMessage $message) => $message->getId(), $messages); $attachments = $this->attachmentMapper->findByLocalMessageIds($ids); $recipients = $this->recipientMapper->findByLocalMessageIds($ids); $recipientMap = []; foreach ($recipients as $r) { $recipientMap[$r->getLocalMessageId()][] = $r; } $attachmentMap = []; foreach ($attachments as $a) { $attachmentMap[$a->getLocalMessageId()][] = $a; } return array_map(static function ($localMessage) use ($attachmentMap, $recipientMap) { $localMessage->setAttachments($attachmentMap[$localMessage->getId()] ?? []); $localMessage->setRecipients($recipientMap[$localMessage->getId()] ?? []); return $localMessage; }, $messages); } /** * @param Recipient[] $to * @param Recipient[] $cc * @param Recipient[] $bcc */ public function saveWithRecipients(LocalMessage $message, array $to, array $cc, array $bcc): LocalMessage { $this->db->beginTransaction(); try { $message = $this->insert($message); $this->recipientMapper->saveRecipients($message->getId(), $to); $this->recipientMapper->saveRecipients($message->getId(), $cc); $this->recipientMapper->saveRecipients($message->getId(), $bcc); $this->db->commit(); } catch (Throwable $e) { $this->db->rollBack(); throw $e; } $message->setRecipients(array_merge( $to, $cc, $bcc, )); return $message; } /** * @param Recipient[] $to * @param Recipient[] $cc * @param Recipient[] $bcc */ public function updateWithRecipients(LocalMessage $message, array $to, array $cc, array $bcc): LocalMessage { $this->db->beginTransaction(); try { $message = $this->update($message); $this->recipientMapper->updateRecipients($message->getId(), $message->getRecipients(), $to, $cc, $bcc); $recipients = $this->recipientMapper->findByLocalMessageId($message->getId()); $message->setRecipients($recipients); $this->db->commit(); return $message; } catch (Throwable $e) { $this->db->rollBack(); throw $e; } } public function deleteWithRecipients(LocalMessage $message): void { $this->db->beginTransaction(); try { $this->recipientMapper->deleteForLocalMessage($message->getId()); $this->delete($message); $this->db->commit(); } catch (Throwable $e) { $this->db->rollBack(); throw $e; } } }