diff --git a/lib/Db/DbFileMapper.php b/lib/Db/DbFileMapper.php index 4aea9a76..dec809a7 100644 --- a/lib/Db/DbFileMapper.php +++ b/lib/Db/DbFileMapper.php @@ -47,6 +47,37 @@ public function getFileIdsWithoutTags(array $excludedTagIds, int $limit): array return $fileIds; } + /** + * Get file ids that have at least one of the given tags + * @param array $includedTagIds + * @param int $limit + * @return array of file ids + * @throws Exception if the database platform is not supported + */ + public function getFileIdsWithTags(array $includedTagIds, int $limit): array + { + $qb = $this->db->getQueryBuilder(); + $qb->automaticTablePrefix(true); + + $qb->select('f.fileid') + ->from($this->getTableName(), 'f') + ->leftJoin('f', 'systemtag_object_mapping', 'o', $qb->expr()->eq('f.fileid', $qb->createFunction($this->getPlatformSpecificCast()))) + ->leftJoin('f', 'mimetypes', 'm', $qb->expr()->eq('f.mimetype', 'm.id')) + ->where($qb->expr()->in('o.systemtagid', $qb->createNamedParameter($includedTagIds, IQueryBuilder::PARAM_INT_ARRAY))) + ->andWhere($qb->expr()->notLike('m.mimetype', $qb->createNamedParameter('%unix-directory%'))) + ->andWhere($qb->expr()->lte('f.size', $qb->createNamedParameter(VerdictService::MAX_FILE_SIZE))) + ->andWhere($qb->expr()->like('f.path', $qb->createNamedParameter('files/%'))) + ->orderBy('f.fileid', 'DESC') + ->setMaxResults($limit); + + $fileIds = []; + $result = $qb->executeQuery(); + while ($row = $result->fetch()) { + $fileIds[] = $row['fileid']; + } + return $fileIds; + } + /** * Create a platform-specific cast function * @return string the database platform-specific cast function diff --git a/lib/Service/TagService.php b/lib/Service/TagService.php index 2b9a0022..07c47807 100644 --- a/lib/Service/TagService.php +++ b/lib/Service/TagService.php @@ -110,17 +110,17 @@ public function hasUnscannedTag(int $fileId): bool /** * @param string $tagName * @param int $limit Count of object ids you want to get - * @param string $offset The last object id you already received * @return array + * @throws Exception if the database platform is not supported */ - public function getFileIdsWithTag(string $tagName, int $limit, string $offset): array + public function getFileIdsWithTag(string $tagName, int $limit): array { try { $tag = $this->getTag($tagName, false); } catch (TagNotFoundException) { return []; } - return $this->tagMapper->getObjectIdsForTags([$tag->getId()], 'files', $limit, $offset); + return $this->dbFileMapper->getFileIdsWithTags([$tag->getId()], $limit); } /** @@ -138,24 +138,24 @@ public function getFileIdsWithoutTags(array $excludedTagIds, int $limit): array * Get file ids that have any of the given tags * @param array $tagIds The tags to get the file ids for * @param int $limit The count of file ids you want to get - * @param ISystemTag|null $priorTagId Tag id to prioritize over the others + * @param ISystemTag|null $priorityTagId Tag id to prioritize over the others * @return array * @throws TagNotFoundException if a tag does not exist + * @throws Exception If the database platform is not supported */ - public function getRandomTaggedFileIds(array $tagIds, int $limit, ?ISystemTag $priorTagId = null): array + public function getRandomTaggedFileIds(array $tagIds, int $limit, ?ISystemTag $priorityTagId = null): array { - if ($priorTagId === null) { - $objectIds = $this->tagMapper->getObjectIdsForTags($tagIds, 'files'); - shuffle($objectIds); - return array_slice($objectIds, 0, $limit); + $objectIdsPriority = []; + if ($priorityTagId !== null) { + $objectIdsPriority = $this->dbFileMapper->getFileIdsWithTags([$priorityTagId->getId()], $limit); + shuffle($objectIdsPriority); } - $objectIdsPrior = $this->tagMapper->getObjectIdsForTags([$priorTagId->getId()], 'files', $limit, 0); - if (count($objectIdsPrior) >= $limit) { - return $objectIdsPrior; + if (count($objectIdsPriority) < $limit) { + $objectIds = $this->dbFileMapper->getFileIdsWithTags($tagIds, $limit - count($objectIdsPriority)); + shuffle($objectIds); + return array_merge($objectIdsPriority, $objectIds); } - $objectIds = $this->tagMapper->getObjectIdsForTags($tagIds, 'files'); - shuffle($objectIds); - return array_merge($objectIdsPrior, array_slice($objectIds, 0, $limit - count($objectIdsPrior))); + return $objectIdsPriority; } /**