diff options
Diffstat (limited to 'lib/private/FullTextSearch')
-rw-r--r-- | lib/private/FullTextSearch/FullTextSearchManager.php | 188 | ||||
-rw-r--r-- | lib/private/FullTextSearch/Model/DocumentAccess.php | 267 | ||||
-rw-r--r-- | lib/private/FullTextSearch/Model/IndexDocument.php | 774 | ||||
-rw-r--r-- | lib/private/FullTextSearch/Model/SearchOption.php | 209 | ||||
-rw-r--r-- | lib/private/FullTextSearch/Model/SearchRequestSimpleQuery.php | 132 | ||||
-rw-r--r-- | lib/private/FullTextSearch/Model/SearchTemplate.php | 191 |
6 files changed, 1761 insertions, 0 deletions
diff --git a/lib/private/FullTextSearch/FullTextSearchManager.php b/lib/private/FullTextSearch/FullTextSearchManager.php new file mode 100644 index 00000000000..989da8d6bae --- /dev/null +++ b/lib/private/FullTextSearch/FullTextSearchManager.php @@ -0,0 +1,188 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OC\FullTextSearch; + +use OCP\FullTextSearch\Exceptions\FullTextSearchAppNotAvailableException; +use OCP\FullTextSearch\IFullTextSearchManager; +use OCP\FullTextSearch\Model\IIndex; +use OCP\FullTextSearch\Model\ISearchResult; +use OCP\FullTextSearch\Service\IIndexService; +use OCP\FullTextSearch\Service\IProviderService; +use OCP\FullTextSearch\Service\ISearchService; + +/** + * Class FullTextSearchManager + * + * @package OC\FullTextSearch + */ +class FullTextSearchManager implements IFullTextSearchManager { + private ?IProviderService $providerService = null; + + private ?IIndexService $indexService = null; + + private ?ISearchService $searchService = null; + + /** + * @since 15.0.0 + */ + public function registerProviderService(IProviderService $providerService): void { + $this->providerService = $providerService; + } + + /** + * @since 15.0.0 + */ + public function registerIndexService(IIndexService $indexService): void { + $this->indexService = $indexService; + } + + /** + * @since 15.0.0 + */ + public function registerSearchService(ISearchService $searchService): void { + $this->searchService = $searchService; + } + + /** + * @since 16.0.0 + */ + public function isAvailable(): bool { + if ($this->indexService === null + || $this->providerService === null + || $this->searchService === null) { + return false; + } + + return true; + } + + + /** + * @throws FullTextSearchAppNotAvailableException + */ + private function getProviderService(): IProviderService { + if ($this->providerService === null) { + throw new FullTextSearchAppNotAvailableException('No IProviderService registered'); + } + + return $this->providerService; + } + + + /** + * @throws FullTextSearchAppNotAvailableException + */ + private function getIndexService(): IIndexService { + if ($this->indexService === null) { + throw new FullTextSearchAppNotAvailableException('No IIndexService registered'); + } + + return $this->indexService; + } + + + /** + * @throws FullTextSearchAppNotAvailableException + */ + private function getSearchService(): ISearchService { + if ($this->searchService === null) { + throw new FullTextSearchAppNotAvailableException('No ISearchService registered'); + } + + return $this->searchService; + } + + + /** + * @throws FullTextSearchAppNotAvailableException + */ + public function addJavascriptAPI(): void { + $this->getProviderService()->addJavascriptAPI(); + } + + + /** + * @throws FullTextSearchAppNotAvailableException + */ + public function isProviderIndexed(string $providerId): bool { + return $this->getProviderService()->isProviderIndexed($providerId); + } + + + /** + * @throws FullTextSearchAppNotAvailableException + */ + public function getIndex(string $providerId, string $documentId): IIndex { + return $this->getIndexService()->getIndex($providerId, $documentId); + } + + /** + * @see IIndex for available value for $status. + * + * @throws FullTextSearchAppNotAvailableException + */ + public function createIndex( + string $providerId, + string $documentId, + string $userId, + int $status = 0, + ): IIndex { + return $this->getIndexService()->createIndex($providerId, $documentId, $userId, $status); + } + + + /** + * @see IIndex for available value for $status. + * + * @throws FullTextSearchAppNotAvailableException + */ + public function updateIndexStatus( + string $providerId, + string $documentId, + int $status, + bool $reset = false, + ): void { + $this->getIndexService()->updateIndexStatus($providerId, $documentId, $status, $reset); + } + + /** + * @see IIndex for available value for $status. + * + * @throws FullTextSearchAppNotAvailableException + */ + public function updateIndexesStatus( + string $providerId, + array $documentIds, + int $status, + bool $reset = false, + ): void { + $this->getIndexService()->updateIndexesStatus($providerId, $documentIds, $status, $reset); + } + + + /** + * @param IIndex[] $indexes + * + * @throws FullTextSearchAppNotAvailableException + */ + public function updateIndexes(array $indexes): void { + $this->getIndexService()->updateIndexes($indexes); + } + + + /** + * @return ISearchResult[] + * @throws FullTextSearchAppNotAvailableException + */ + public function search(array $request, string $userId = ''): array { + $searchRequest = $this->getSearchService()->generateSearchRequest($request); + + return $this->getSearchService()->search($userId, $searchRequest); + } +} diff --git a/lib/private/FullTextSearch/Model/DocumentAccess.php b/lib/private/FullTextSearch/Model/DocumentAccess.php new file mode 100644 index 00000000000..9efffeaee88 --- /dev/null +++ b/lib/private/FullTextSearch/Model/DocumentAccess.php @@ -0,0 +1,267 @@ +<?php + +declare(strict_types=1); +/** + * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OC\FullTextSearch\Model; + +use JsonSerializable; +use OCP\FullTextSearch\Model\IDocumentAccess; + +/** + * Class IDocumentAccess + * + * This object is used as a data transfer object when + * + * - indexing a document, + * - generating a search request. + * + * During the index, it is used to define which users, groups, circles, ... + * have access to the IndexDocument + * + * During the search, it is internally use to define to which group, circles, ... + * a user that perform the search belongs to. + * + * @see IIndexDocument::setAccess + * + * @since 16.0.0 + * + * @package OC\FullTextSearch\Model + */ +final class DocumentAccess implements IDocumentAccess, JsonSerializable { + private string $ownerId; + + private string $viewerId = ''; + + private array $users = []; + + private array $groups = []; + + private array $circles = []; + + private array $links = []; + + + /** + * Owner of the document can be set at the init of the object. + * + * @since 16.0.0 + * + * IDocumentAccess constructor. + */ + public function __construct(string $ownerId = '') { + $this->setOwnerId($ownerId); + } + + + /** + * Set the Owner of the document. + * + * @since 16.0.0 + */ + public function setOwnerId(string $ownerId): IDocumentAccess { + $this->ownerId = $ownerId; + + return $this; + } + + /** + * Get the Owner of the document. + * + * @since 16.0.0 + */ + public function getOwnerId(): string { + return $this->ownerId; + } + + + /** + * Set the viewer of the document. + * + * @since 16.0.0 + */ + public function setViewerId(string $viewerId): IDocumentAccess { + $this->viewerId = $viewerId; + + return $this; + } + + /** + * Get the viewer of the document. + * + * @since 16.0.0 + */ + public function getViewerId(): string { + return $this->viewerId; + } + + + /** + * Set the list of users that have read access to the document. + * + * @since 16.0.0 + */ + public function setUsers(array $users): IDocumentAccess { + $this->users = $users; + + return $this; + } + + /** + * Add an entry to the list of users that have read access to the document. + * + * @since 16.0.0 + */ + public function addUser(string $user): IDocumentAccess { + $this->users[] = $user; + + return $this; + } + + /** + * Add multiple entries to the list of users that have read access to the + * document. + * + * @since 16.0.0 + */ + public function addUsers($users): IDocumentAccess { + $this->users = array_merge($this->users, $users); + + return $this; + } + + /** + * Get the complete list of users that have read access to the document. + * + * @since 16.0.0 + */ + public function getUsers(): array { + return $this->users; + } + + + /** + * Set the list of groups that have read access to the document. + * + * @since 16.0.0 + */ + public function setGroups(array $groups): IDocumentAccess { + $this->groups = $groups; + + return $this; + } + + /** + * Add an entry to the list of groups that have read access to the document. + * + * @since 16.0.0 + */ + public function addGroup(string $group): IDocumentAccess { + $this->groups[] = $group; + + return $this; + } + + /** + * Add multiple entries to the list of groups that have read access to the + * document. + * + * @since 16.0.0 + */ + public function addGroups(array $groups): IDocumentAccess { + $this->groups = array_merge($this->groups, $groups); + + return $this; + } + + /** + * Get the complete list of groups that have read access to the document. + * + * @since 16.0.0 + */ + public function getGroups(): array { + return $this->groups; + } + + + /** + * Set the list of circles that have read access to the document. + * + * @since 16.0.0 + */ + public function setCircles(array $circles): IDocumentAccess { + $this->circles = $circles; + + return $this; + } + + /** + * Add an entry to the list of circles that have read access to the document. + * + * @since 16.0.0 + */ + public function addCircle(string $circle): IDocumentAccess { + $this->circles[] = $circle; + + return $this; + } + + /** + * Add multiple entries to the list of groups that have read access to the + * document. + * + * @since 16.0.0 + */ + public function addCircles(array $circles): IDocumentAccess { + $this->circles = array_merge($this->circles, $circles); + + return $this; + } + + /** + * Get the complete list of circles that have read access to the document. + * + * @since 16.0.0 + */ + public function getCircles(): array { + return $this->circles; + } + + + /** + * Set the list of links that have read access to the document. + * + * @since 16.0.0 + */ + public function setLinks(array $links): IDocumentAccess { + $this->links = $links; + + return $this; + } + + /** + * Get the list of links that have read access to the document. + * + * @since 16.0.0 + */ + public function getLinks(): array { + return $this->links; + } + + + /** + * @since 16.0.0 + */ + public function jsonSerialize(): array { + return [ + 'ownerId' => $this->getOwnerId(), + 'viewerId' => $this->getViewerId(), + 'users' => $this->getUsers(), + 'groups' => $this->getGroups(), + 'circles' => $this->getCircles(), + 'links' => $this->getLinks() + ]; + } +} diff --git a/lib/private/FullTextSearch/Model/IndexDocument.php b/lib/private/FullTextSearch/Model/IndexDocument.php new file mode 100644 index 00000000000..a51447393ed --- /dev/null +++ b/lib/private/FullTextSearch/Model/IndexDocument.php @@ -0,0 +1,774 @@ +<?php + +declare(strict_types=1); +/** + * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OC\FullTextSearch\Model; + +use JsonSerializable; +use OCP\FullTextSearch\Exceptions\FullTextSearchIndexNotAvailableException; +use OCP\FullTextSearch\Model\IDocumentAccess; +use OCP\FullTextSearch\Model\IIndex; +use OCP\FullTextSearch\Model\IIndexDocument; + +/** + * Class IndexDocument + * + * This is one of the main class of the FullTextSearch, used as a data transfer + * object. An IndexDocument is created to manage documents around FullTextSearch, + * during an index and during a search. + * The uniqueness of an IndexDocument is made by the Id of the Content Provider + * and the Id of the original document within the Content Provider. + * + * We will call original document the source from which the IndexDocument is + * generated. As an example, an original document can be a file, a mail, ... + * + * @since 15.0.0 + * + * @package OC\FullTextSearch\Model + */ +class IndexDocument implements IIndexDocument, JsonSerializable { + protected string $id = ''; + + protected DocumentAccess $access; + + protected ?IIndex $index = null; + + protected int $modifiedTime = 0; + + protected string $source = ''; + + protected array $tags = []; + + protected array $metaTags = []; + + protected array $subTags = []; + + protected string $title = ''; + + protected string $content = ''; + + protected string $hash = ''; + + protected array $parts = []; + + protected string $link = ''; + + protected array $more = []; + + protected array $excerpts = []; + + protected string $score = ''; + + protected array $info = []; + + protected int $contentEncoded = 0; + + + /** + * IIndexDocument constructor. + * + * On creation, we assure the uniqueness of the object using the providerId + * and the Id of the original document. + * + * @since 15.0.0 + */ + public function __construct( + protected string $providerId, + string $documentId, + ) { + $this->id = $documentId; + } + + + /** + * Returns the Id of the original document. + * + * @since 15.0.0 + */ + final public function getId(): string { + return $this->id; + } + + + /** + * Returns the Id of the provider. + * + * @since 15.0.0 + */ + final public function getProviderId(): string { + return $this->providerId; + } + + + /** + * Set the Index related to the IIndexDocument. + * + * @see IIndex + * + * @since 15.0.0 + */ + final public function setIndex(IIndex $index): IIndexDocument { + $this->index = $index; + + return $this; + } + + /** + * Get the Index. + * + * @throws FullTextSearchIndexNotAvailableException + * @since 15.0.0 + */ + final public function getIndex(): IIndex { + if ($this->index === null) { + throw new FullTextSearchIndexNotAvailableException('No IIndex generated'); + } + + return $this->index; + } + + /** + * return if Index is defined. + * + * @since 16.0.0 + */ + final public function hasIndex(): bool { + return $this->index !== null; + } + + /** + * Set the modified time of the original document. + * + * @since 15.0.0 + */ + final public function setModifiedTime(int $modifiedTime): IIndexDocument { + $this->modifiedTime = $modifiedTime; + + return $this; + } + + /** + * Get the modified time of the original document. + * + * @since 15.0.0 + */ + final public function getModifiedTime(): int { + return $this->modifiedTime; + } + + /** + * Check if the original document of the IIndexDocument is older than $time. + * + * @since 15.0.0 + */ + final public function isOlderThan(int $time): bool { + return ($this->modifiedTime < $time); + } + + + /** + * Set the read rights of the original document using a IDocumentAccess. + * + * @see IDocumentAccess + * + * @since 15.0.0 + */ + final public function setAccess(IDocumentAccess $access): IIndexDocument { + $this->access = $access; + + return $this; + } + + /** + * Get the IDocumentAccess related to the original document. + * + * @since 15.0.0 + */ + final public function getAccess(): IDocumentAccess { + return $this->access; + } + + + /** + * Add a tag to the list. + * + * @since 15.0.0 + */ + final public function addTag(string $tag): IIndexDocument { + $this->tags[] = $tag; + + return $this; + } + + /** + * Set the list of tags assigned to the original document. + * + * @since 15.0.0 + */ + final public function setTags(array $tags): IIndexDocument { + $this->tags = $tags; + + return $this; + } + + /** + * Get the list of tags assigned to the original document. + * + * @since 15.0.0 + */ + final public function getTags(): array { + return $this->tags; + } + + + /** + * Add a meta tag to the list. + * + * @since 15.0.0 + */ + final public function addMetaTag(string $tag): IIndexDocument { + $this->metaTags[] = $tag; + + return $this; + } + + /** + * Set the list of meta tags assigned to the original document. + * + * @since 15.0.0 + */ + final public function setMetaTags(array $tags): IIndexDocument { + $this->metaTags = $tags; + + return $this; + } + + /** + * Get the list of meta tags assigned to the original document. + * + * @since 15.0.0 + */ + final public function getMetaTags(): array { + return $this->metaTags; + } + + + /** + * Add a sub tag to the list. + * + * @since 15.0.0 + */ + final public function addSubTag(string $sub, string $tag): IIndexDocument { + if (!array_key_exists($sub, $this->subTags)) { + $this->subTags[$sub] = []; + } + + $this->subTags[$sub][] = $tag; + + return $this; + } + + + /** + * Set the list of sub tags assigned to the original document. + * + * @since 15.0.0 + */ + final public function setSubTags(array $tags): IIndexDocument { + $this->subTags = $tags; + + return $this; + } + + /** + * Get the list of sub tags assigned to the original document. + * If $formatted is true, the result will be formatted in a one + * dimensional array. + * + * @since 15.0.0 + */ + final public function getSubTags(bool $formatted = false): array { + if ($formatted === false) { + return $this->subTags; + } + + $subTags = []; + $ak = array_keys($this->subTags); + foreach ($ak as $source) { + $tags = $this->subTags[$source]; + foreach ($tags as $tag) { + $subTags[] = $source . '_' . $tag; + } + } + + return $subTags; + } + + + /** + * Set the source of the original document. + * + * @since 15.0.0 + */ + final public function setSource(string $source): IIndexDocument { + $this->source = $source; + + return $this; + } + + /** + * Get the source of the original document. + * + * @since 15.0.0 + */ + final public function getSource(): string { + return $this->source; + } + + + /** + * Set the title of the original document. + * + * @since 15.0.0 + */ + final public function setTitle(string $title): IIndexDocument { + $this->title = $title; + + return $this; + } + + /** + * Get the title of the original document. + * + * @since 15.0.0 + */ + final public function getTitle(): string { + return $this->title; + } + + + /** + * Set the content of the document. + * $encoded can be NOT_ENCODED or ENCODED_BASE64 if the content is raw or + * encoded in base64. + * + * @since 15.0.0 + */ + final public function setContent(string $content, int $encoded = 0): IIndexDocument { + $this->content = $content; + $this->contentEncoded = $encoded; + + return $this; + } + + /** + * Get the content of the original document. + * + * @since 15.0.0 + */ + final public function getContent(): string { + return $this->content; + } + + /** + * Returns the type of the encoding on the content. + * + * @since 15.0.0 + */ + final public function isContentEncoded(): int { + return $this->contentEncoded; + } + + /** + * Return the size of the content. + * + * @since 15.0.0 + */ + final public function getContentSize(): int { + return strlen($this->getContent()); + } + + + /** + * Generate a hash, based on the content of the original document. + * + * @since 15.0.0 + */ + final public function initHash(): IIndexDocument { + if ($this->getContent() === '' || is_null($this->getContent())) { + return $this; + } + + $this->hash = hash('md5', $this->getContent()); + + return $this; + } + + /** + * Set the hash of the original document. + * + * @since 15.0.0 + */ + final public function setHash(string $hash): IIndexDocument { + $this->hash = $hash; + + return $this; + } + + /** + * Get the hash of the original document. + * + * @since 15.0.0 + */ + final public function getHash(): string { + return $this->hash; + } + + + /** + * Add a part, identified by a string, and its content. + * + * It is strongly advised to use alphanumerical chars with no space in the + * $part string. + * + * @since 15.0.0 + */ + final public function addPart(string $part, string $content): IIndexDocument { + $this->parts[$part] = $content; + + return $this; + } + + /** + * Set all parts and their content. + * + * @since 15.0.0 + */ + final public function setParts(array $parts): IIndexDocument { + $this->parts = $parts; + + return $this; + } + + /** + * Get all parts of the IIndexDocument. + * + * @since 15.0.0 + */ + final public function getParts(): array { + return $this->parts; + } + + + /** + * Add a link, usable by the frontend. + * + * @since 15.0.0 + */ + final public function setLink(string $link): IIndexDocument { + $this->link = $link; + + return $this; + } + + /** + * Get the link. + * + * @since 15.0.0 + */ + final public function getLink(): string { + return $this->link; + } + + + /** + * Set more information that couldn't be set using other method. + * + * @since 15.0.0 + */ + final public function setMore(array $more): IIndexDocument { + $this->more = $more; + + return $this; + } + + /** + * Get more information. + * + * @since 15.0.0 + */ + final public function getMore(): array { + return $this->more; + } + + + /** + * Add some excerpt of the content of the original document, usually based + * on the search request. + * + * @since 16.0.0 + */ + final public function addExcerpt(string $source, string $excerpt): IIndexDocument { + $this->excerpts[] + = [ + 'source' => $source, + 'excerpt' => $this->cleanExcerpt($excerpt) + ]; + + return $this; + } + + + /** + * Set all excerpts of the content of the original document. + * + * @since 16.0.0 + */ + final public function setExcerpts(array $excerpts): IIndexDocument { + $new = []; + foreach ($excerpts as $entry) { + $new[] = [ + 'source' => $entry['source'], + 'excerpt' => $this->cleanExcerpt($entry['excerpt']) + ]; + } + + $this->excerpts = $new; + + return $this; + } + + /** + * Get all excerpts of the content of the original document. + * + * @since 15.0.0 + */ + final public function getExcerpts(): array { + return $this->excerpts; + } + + /** + * Clean excerpt. + * + * @since 16.0.0 + */ + private function cleanExcerpt(string $excerpt): string { + $excerpt = str_replace('\\n', ' ', $excerpt); + $excerpt = str_replace('\\r', ' ', $excerpt); + $excerpt = str_replace('\\t', ' ', $excerpt); + $excerpt = str_replace("\n", ' ', $excerpt); + $excerpt = str_replace("\r", ' ', $excerpt); + $excerpt = str_replace("\t", ' ', $excerpt); + + return $excerpt; + } + + + /** + * Set the score to the result assigned to this document during a search + * request. + * + * @since 15.0.0 + */ + final public function setScore(string $score): IIndexDocument { + $this->score = $score; + + return $this; + } + + /** + * Get the score. + * + * @since 15.0.0 + */ + final public function getScore(): string { + return $this->score; + } + + + /** + * Set some information about the original document that will be available + * to the front-end when displaying search result. (as string) + * Because this information will not be indexed, this method can also be + * used to manage some data while filling the IIndexDocument before its + * indexing. + * + * @since 15.0.0 + */ + final public function setInfo(string $info, string $value): IIndexDocument { + $this->info[$info] = $value; + + return $this; + } + + /** + * Get an information about a document. (string) + * + * @since 15.0.0 + */ + final public function getInfo(string $info, string $default = ''): string { + if (!key_exists($info, $this->info)) { + return $default; + } + + return $this->info[$info]; + } + + /** + * Set some information about the original document that will be available + * to the front-end when displaying search result. (as array) + * Because this information will not be indexed, this method can also be + * used to manage some data while filling the IIndexDocument before its + * indexing. + * + * @since 15.0.0 + */ + final public function setInfoArray(string $info, array $value): IIndexDocument { + $this->info[$info] = $value; + + return $this; + } + + /** + * Get an information about a document. (array) + * + * @since 15.0.0 + */ + final public function getInfoArray(string $info, array $default = []): array { + if (!key_exists($info, $this->info)) { + return $default; + } + + return $this->info[$info]; + } + + /** + * Set some information about the original document that will be available + * to the front-end when displaying search result. (as int) + * Because this information will not be indexed, this method can also be + * used to manage some data while filling the IIndexDocument before its + * indexing. + * + * @since 15.0.0 + */ + final public function setInfoInt(string $info, int $value): IIndexDocument { + $this->info[$info] = $value; + + return $this; + } + + /** + * Get an information about a document. (int) + * + * @since 15.0.0 + */ + final public function getInfoInt(string $info, int $default = 0): int { + if (!key_exists($info, $this->info)) { + return $default; + } + + return $this->info[$info]; + } + + /** + * Set some information about the original document that will be available + * to the front-end when displaying search result. (as bool) + * Because this information will not be indexed, this method can also be + * used to manage some data while filling the IIndexDocument before its + * indexing. + * + * @since 15.0.0 + */ + final public function setInfoBool(string $info, bool $value): IIndexDocument { + $this->info[$info] = $value; + + return $this; + } + + /** + * Get an information about a document. (bool) + * + * @since 15.0.0 + */ + final public function getInfoBool(string $info, bool $default = false): bool { + if (!key_exists($info, $this->info)) { + return $default; + } + + return $this->info[$info]; + } + + /** + * Get all info. + * + * @since 15.0.0 + */ + final public function getInfoAll(): array { + $info = []; + foreach ($this->info as $k => $v) { + if (str_starts_with($k, '_')) { + continue; + } + + $info[$k] = $v; + } + + return $info; + } + + + /** + * @since 15.0.0 + * + * On some version of PHP, it is better to force destruct the object. + * And during the index, the number of generated IIndexDocument can be + * _huge_. + */ + public function __destruct() { + unset($this->id); + unset($this->providerId); + unset($this->access); + unset($this->modifiedTime); + unset($this->title); + unset($this->content); + unset($this->hash); + unset($this->link); + unset($this->source); + unset($this->tags); + unset($this->metaTags); + unset($this->subTags); + unset($this->more); + unset($this->excerpts); + unset($this->score); + unset($this->info); + unset($this->contentEncoded); + } + + /** + * @since 15.0.0 + */ + public function jsonSerialize(): array { + return [ + 'id' => $this->getId(), + 'providerId' => $this->getProviderId(), + 'access' => $this->access, + 'modifiedTime' => $this->getModifiedTime(), + 'title' => $this->getTitle(), + 'link' => $this->getLink(), + 'index' => $this->index, + 'source' => $this->getSource(), + 'info' => $this->getInfoAll(), + 'hash' => $this->getHash(), + 'contentSize' => $this->getContentSize(), + 'tags' => $this->getTags(), + 'metatags' => $this->getMetaTags(), + 'subtags' => $this->getSubTags(), + 'more' => $this->getMore(), + 'excerpts' => $this->getExcerpts(), + 'score' => $this->getScore() + ]; + } +} diff --git a/lib/private/FullTextSearch/Model/SearchOption.php b/lib/private/FullTextSearch/Model/SearchOption.php new file mode 100644 index 00000000000..c7769a62138 --- /dev/null +++ b/lib/private/FullTextSearch/Model/SearchOption.php @@ -0,0 +1,209 @@ +<?php + +declare(strict_types=1); +/** + * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OC\FullTextSearch\Model; + +use JsonSerializable; +use OCP\FullTextSearch\Model\ISearchOption; + +/** + * @since 15.0.0 + * + * Class ISearchOption + * + * @package OC\FullTextSearch\Model + */ +final class SearchOption implements ISearchOption, JsonSerializable { + /** + * * + * + * The array can be empty in case no search options are available. + * The format of the array must be like this: + * + * [ + * 'panel' => [ + * 'options' => [ + * OPTION1, + * OPTION2, + * OPTION3 + * ] + * ], + * 'navigation' => [ + * 'icon' => 'css-class-of-the-icon', + * 'options' => [ + * OPTION1, + * OPTION2, + * OPTION3 + * ] + * ] + * ] + * + * - PANEL contains entries that will be displayed in the app itself, when + * a search is initiated. + * - NAVIGATION contains entries that will be available when using the + * FullTextSearch navigation page + * - OPTION is an element that define each option available to the user. + * + * The format for the options must be like this: + * + * [ + * 'name' => 'name_of_the_option', + * 'title' => 'Name displayed in the panel', + * 'type' => '', + * 'size' => '' (optional), + * 'placeholder' => '' (optional) + * ] + * + * - NAME is the variable name that is sent to the IFullTextSearchProvider + * when a ISearchRequest is requested. (keys in the array returned by the + * ISearchRequest->getOptions()) + * - TYPE can be 'input' or 'checkbox' + * - SIZE is only used in case TYPE='input', default is 'large' but can be + * 'small' + * - PLACEHOLDER is only used in case TYPE='input', default is empty. + */ + + /** + * ISearchOption constructor. + * + * Some value can be set during the creation of the object. + * + * @since 15.0.0 + */ + public function __construct( + private string $name = '', + private string $title = '', + private string $type = '', + private string $size = '', + private string $placeholder = '', + ) { + } + + + /** + * Set the name/key of the option. + * The string should only contain alphanumerical chars and underscore. + * The key can be retrieved when using ISearchRequest::getOption + * + * @see ISearchRequest::getOption + * + * @since 15.0.0 + */ + public function setName(string $name): ISearchOption { + $this->name = $name; + + return $this; + } + + /** + * Get the name/key of the option. + * + * @since 15.0.0 + */ + public function getName(): string { + return $this->name; + } + + + /** + * Set the title/display name of the option. + * + * @since 15.0.0 + */ + public function setTitle(string $title): ISearchOption { + $this->title = $title; + + return $this; + } + + /** + * Get the title of the option. + * + * @since 15.0.0 + */ + public function getTitle(): string { + return $this->title; + } + + + /** + * Set the type of the option. + * $type can be ISearchOption::CHECKBOX or ISearchOption::INPUT + * + * @since 15.0.0 + */ + public function setType(string $type): ISearchOption { + $this->type = $type; + + return $this; + } + + /** + * Get the type of the option. + * + * @since 15.0.0 + */ + public function getType(): string { + return $this->type; + } + + + /** + * In case of Type is INPUT, set the size of the input field. + * Value can be ISearchOption::INPUT_SMALL or not defined. + * + * @since 15.0.0 + */ + public function setSize(string $size): ISearchOption { + $this->size = $size; + + return $this; + } + + /** + * Get the size of the INPUT. + * + * @since 15.0.0 + */ + public function getSize(): string { + return $this->size; + } + + /** + * In case of Type is , set the placeholder to be displayed in the input + * field. + * + * @since 15.0.0 + */ + public function setPlaceholder(string $placeholder): ISearchOption { + $this->placeholder = $placeholder; + + return $this; + } + + /** + * Get the placeholder. + * + * @since 15.0.0 + */ + public function getPlaceholder(): string { + return $this->placeholder; + } + + /** + * @since 15.0.0 + */ + public function jsonSerialize(): array { + return [ + 'name' => $this->getName(), + 'title' => $this->getTitle(), + 'type' => $this->getType(), + 'size' => $this->getSize(), + 'placeholder' => $this->getPlaceholder() + ]; + } +} diff --git a/lib/private/FullTextSearch/Model/SearchRequestSimpleQuery.php b/lib/private/FullTextSearch/Model/SearchRequestSimpleQuery.php new file mode 100644 index 00000000000..5b075daf7e6 --- /dev/null +++ b/lib/private/FullTextSearch/Model/SearchRequestSimpleQuery.php @@ -0,0 +1,132 @@ +<?php + +declare(strict_types=1); +/** + * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OC\FullTextSearch\Model; + +use JsonSerializable; +use OCP\FullTextSearch\Model\ISearchRequestSimpleQuery; + +/** + * @since 17.0.0 + * + * Class SearchRequestSimpleQuery + * + * @package OC\FullTextSearch\Model + */ +final class SearchRequestSimpleQuery implements ISearchRequestSimpleQuery, JsonSerializable { + private array $values = []; + + + /** + * SearchRequestQuery constructor. + * + * @since 17.0.0 + */ + public function __construct( + private string $field, + private int $type, + ) { + } + + + /** + * Get the compare type of the query + * + * @since 17.0.0 + */ + public function getType(): int { + return $this->type; + } + + + /** + * Get the field to apply query + * + * @since 17.0.0 + */ + public function getField(): string { + return $this->field; + } + + /** + * Set the field to apply query + * + * @since 17.0.0 + */ + public function setField(string $field): ISearchRequestSimpleQuery { + $this->field = $field; + + return $this; + } + + + /** + * Get the value to compare (string) + * + * @since 17.0.0 + */ + public function getValues(): array { + return $this->values; + } + + + /** + * Add value to compare (string) + * + * @since 17.0.0 + */ + public function addValue(string $value): ISearchRequestSimpleQuery { + $this->values[] = $value; + + return $this; + } + + /** + * Add value to compare (int) + * + * @since 17.0.0 + */ + public function addValueInt(int $value): ISearchRequestSimpleQuery { + $this->values[] = $value; + + return $this; + } + + /** + * Add value to compare (array) + * + * @since 17.0.0 + */ + public function addValueArray(array $value): ISearchRequestSimpleQuery { + $this->values[] = $value; + + return $this; + } + + /** + * Add value to compare (bool) + * + * @since 17.0.0 + */ + public function addValueBool(bool $value): ISearchRequestSimpleQuery { + $this->values[] = $value; + + return $this; + } + + + /** + * @since 17.0.0 + */ + public function jsonSerialize(): array { + return [ + 'type' => $this->getType(), + 'field' => $this->getField(), + 'values' => $this->getValues() + ]; + } +} diff --git a/lib/private/FullTextSearch/Model/SearchTemplate.php b/lib/private/FullTextSearch/Model/SearchTemplate.php new file mode 100644 index 00000000000..6f9a04a911e --- /dev/null +++ b/lib/private/FullTextSearch/Model/SearchTemplate.php @@ -0,0 +1,191 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OC\FullTextSearch\Model; + +use JsonSerializable; +use OCP\FullTextSearch\IFullTextSearchProvider; +use OCP\FullTextSearch\Model\ISearchOption; +use OCP\FullTextSearch\Model\ISearchTemplate; + +/** + * Class ISearchTemplate + * + * This is a data transfer object that should be created by Content Provider + * when the getSearchTemplate() method is called. + * + * The object will contain templates to be displayed, and the list of the different + * options to be available to the user when they start a new search. + * + * The display of the Options is generated by the FullTextSearch app and Options + * can be displayed in 2 places: + * + * - the navigation page of the app that generate the indexed content. + * (files, bookmarks, deck, mails, ...) + * - the navigation page of the FullTextSearch app. + * + * Both pages will have different Options, and only the first one can integrate + * a specific template. + * + * @see IFullTextSearchProvider::getSearchTemplate + * + * @since 15.0.0 + * + * @package OC\FullTextSearch\Model + */ +final class SearchTemplate implements ISearchTemplate, JsonSerializable { + private string $template = ''; + + /** @var SearchOption[] */ + private array $panelOptions = []; + + /** @var SearchOption[] */ + private array $navigationOptions = []; + + /** + * ISearchTemplate constructor. + * + * the class of the icon and the css file to be loaded can be set during the + * creation of the object. + * + * @since 15.0.0 + */ + public function __construct( + private string $icon = '', + private string $css = '', + ) { + } + + + /** + * Set the class of the icon to be displayed in the left panel of the + * FullTextSearch navigation page, in front of the related Content Provider. + * + * @since 15.0.0 + */ + public function setIcon(string $class): ISearchTemplate { + $this->icon = $class; + + return $this; + } + + /** + * Get the class of the icon. + */ + public function getIcon(): string { + return $this->icon; + } + + + /** + * Set the path of a CSS file that will be loaded when needed. + * + * @since 15.0.0 + */ + public function setCss(string $css): ISearchTemplate { + $this->css = $css; + + return $this; + } + + /** + * Get the path of the CSS file. + * + * @since 15.0.0 + */ + public function getCss(): string { + return $this->css; + } + + + /** + * Set the path of the file of a template that the HTML will be displayed + * below the Options. + * This should only be used if your Content Provider needs to set options in + * a way not generated by FullTextSearch + * + * @since 15.0.0 + */ + public function setTemplate(string $template): ISearchTemplate { + $this->template = $template; + + return $this; + } + + /** + * Get the path of the template file. + * + * @since 15.0.0 + */ + public function getTemplate(): string { + return $this->template; + } + + + /** + * Add an option in the Panel that is displayed when the user start a search + * within the app that generate the content. + * + * @see ISearchOption + * + * @since 15.0.0 + */ + public function addPanelOption(ISearchOption $option): ISearchTemplate { + $this->panelOptions[] = $option; + + return $this; + } + + /** + * Get all options to be displayed in the Panel. + * + * @since 15.0.0 + * + * @return SearchOption[] + */ + public function getPanelOptions(): array { + return $this->panelOptions; + } + + + /** + * Add an option in the left panel of the FullTextSearch navigation page. + * + * @see ISearchOption + * + * @since 15.0.0 + */ + public function addNavigationOption(ISearchOption $option): ISearchTemplate { + $this->navigationOptions[] = $option; + + return $this; + } + + /** + * Get all options to be displayed in the FullTextSearch navigation page. + * + * @since 15.0.0 + */ + public function getNavigationOptions(): array { + return $this->navigationOptions; + } + + + /** + * @since 15.0.0 + */ + public function jsonSerialize(): array { + return [ + 'icon' => $this->getIcon(), + 'css' => $this->getCss(), + 'template' => $this->getTemplate(), + 'panel' => $this->getPanelOptions(), + 'navigation' => $this->getNavigationOptions() + ]; + } +} |