Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>pull/20916/head
parent
50b1568d48
commit
4488e846a5
@ -0,0 +1,72 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
/** |
||||||
|
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||||
|
* |
||||||
|
* @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||||
|
* |
||||||
|
* @license GNU AGPL version 3 or any later version |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as |
||||||
|
* published by the Free Software Foundation, either version 3 of the |
||||||
|
* License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace OCA\Files\Search; |
||||||
|
|
||||||
|
use OCP\IL10N; |
||||||
|
use OCP\IUser; |
||||||
|
use OCP\Search\IProvider; |
||||||
|
use OCP\Search\ISearchQuery; |
||||||
|
use OCP\Search\SearchResult; |
||||||
|
|
||||||
|
class FilesSearchProvider implements IProvider { |
||||||
|
|
||||||
|
/** @var IL10N */ |
||||||
|
private $l10n; |
||||||
|
|
||||||
|
public function __construct(IL10N $l10n) { |
||||||
|
$this->l10n = $l10n; |
||||||
|
} |
||||||
|
|
||||||
|
public function getId(): string { |
||||||
|
return 'files'; |
||||||
|
} |
||||||
|
|
||||||
|
public function search(IUser $user, ISearchQuery $query): SearchResult { |
||||||
|
return SearchResult::complete( |
||||||
|
$this->l10n->t('Files'), |
||||||
|
[ |
||||||
|
new FilesSearchResultEntry( |
||||||
|
"path/to/icon.png", |
||||||
|
"cute cats.jpg", |
||||||
|
"/Cats", |
||||||
|
"/f/21156" |
||||||
|
), |
||||||
|
new FilesSearchResultEntry( |
||||||
|
"path/to/icon.png", |
||||||
|
"cat 1.jpg", |
||||||
|
"/Cats", |
||||||
|
"/f/21192" |
||||||
|
), |
||||||
|
new FilesSearchResultEntry( |
||||||
|
"path/to/icon.png", |
||||||
|
"cat 2.jpg", |
||||||
|
"/Cats", |
||||||
|
"/f/25942" |
||||||
|
), |
||||||
|
] |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,98 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
/** |
||||||
|
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||||
|
* |
||||||
|
* @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||||
|
* |
||||||
|
* @license GNU AGPL version 3 or any later version |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as |
||||||
|
* published by the Free Software Foundation, either version 3 of the |
||||||
|
* License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace OC\Core\Controller; |
||||||
|
|
||||||
|
use OC\Search\SearchComposer; |
||||||
|
use OC\Search\SearchQuery; |
||||||
|
use OCP\AppFramework\Controller; |
||||||
|
use OCP\AppFramework\Http; |
||||||
|
use OCP\AppFramework\Http\JSONResponse; |
||||||
|
use OCP\IRequest; |
||||||
|
use OCP\IUserSession; |
||||||
|
use OCP\Search\ISearchQuery; |
||||||
|
|
||||||
|
class UnifiedSearchController extends Controller { |
||||||
|
|
||||||
|
/** @var SearchComposer */ |
||||||
|
private $composer; |
||||||
|
|
||||||
|
/** @var IUserSession */ |
||||||
|
private $userSession; |
||||||
|
|
||||||
|
public function __construct(IRequest $request, |
||||||
|
IUserSession $userSession, |
||||||
|
SearchComposer $composer) { |
||||||
|
parent::__construct('core', $request); |
||||||
|
|
||||||
|
$this->composer = $composer; |
||||||
|
$this->userSession = $userSession; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @NoAdminRequired |
||||||
|
* @NoCSRFRequired |
||||||
|
*/ |
||||||
|
public function getProviders(): JSONResponse { |
||||||
|
return new JSONResponse( |
||||||
|
$this->composer->getProviders() |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @NoAdminRequired |
||||||
|
* @NoCSRFRequired |
||||||
|
* |
||||||
|
* @param string $providerId |
||||||
|
* @param string $term |
||||||
|
* @param int|null $sortOrder |
||||||
|
* @param int|null $limit |
||||||
|
* @param int|string|null $cursor |
||||||
|
* |
||||||
|
* @return JSONResponse |
||||||
|
*/ |
||||||
|
public function search(string $providerId, |
||||||
|
string $term = '', |
||||||
|
?int $sortOrder = null, |
||||||
|
?int $limit = null, |
||||||
|
$cursor = null): JSONResponse { |
||||||
|
if (empty($term)) { |
||||||
|
return new JSONResponse(null, Http::STATUS_BAD_REQUEST); |
||||||
|
} |
||||||
|
|
||||||
|
return new JSONResponse( |
||||||
|
$this->composer->search( |
||||||
|
$this->userSession->getUser(), |
||||||
|
$providerId, |
||||||
|
new SearchQuery( |
||||||
|
$term, |
||||||
|
$sortOrder ?? ISearchQuery::SORT_DATE_DESC, |
||||||
|
$limit ?? SearchQuery::LIMIT_DEFAULT, |
||||||
|
$cursor |
||||||
|
) |
||||||
|
) |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,107 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
/** |
||||||
|
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||||
|
* |
||||||
|
* @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||||
|
* |
||||||
|
* @license GNU AGPL version 3 or any later version |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as |
||||||
|
* published by the Free Software Foundation, either version 3 of the |
||||||
|
* License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace OC\Search; |
||||||
|
|
||||||
|
use OCP\AppFramework\QueryException; |
||||||
|
use OCP\ILogger; |
||||||
|
use OCP\IServerContainer; |
||||||
|
use OCP\IUser; |
||||||
|
use OCP\Search\IProvider; |
||||||
|
use OCP\Search\ISearchQuery; |
||||||
|
use OCP\Search\SearchResult; |
||||||
|
use function array_map; |
||||||
|
|
||||||
|
/** |
||||||
|
* Queries individual \OCP\Search\IProvider implementations and composes a |
||||||
|
* unified search result for the user's search term |
||||||
|
*/ |
||||||
|
class SearchComposer { |
||||||
|
|
||||||
|
/** @var string[] */ |
||||||
|
private $lazyProviders = []; |
||||||
|
|
||||||
|
/** @var IProvider[] */ |
||||||
|
private $providers = []; |
||||||
|
|
||||||
|
/** @var IServerContainer */ |
||||||
|
private $container; |
||||||
|
|
||||||
|
/** @var ILogger */ |
||||||
|
private $logger; |
||||||
|
|
||||||
|
public function __construct(IServerContainer $container, |
||||||
|
ILogger $logger) { |
||||||
|
$this->container = $container; |
||||||
|
$this->logger = $logger; |
||||||
|
} |
||||||
|
|
||||||
|
public function registerProvider(string $class): void { |
||||||
|
$this->lazyProviders[] = $class; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Load all providers dynamically that were registered through `registerProvider` |
||||||
|
* |
||||||
|
* If a provider can't be loaded we log it but the operation continues nevertheless |
||||||
|
*/ |
||||||
|
private function loadLazyProviders(): void { |
||||||
|
$classes = $this->lazyProviders; |
||||||
|
foreach ($classes as $class) { |
||||||
|
try { |
||||||
|
/** @var IProvider $provider */ |
||||||
|
$provider = $this->container->query($class); |
||||||
|
$this->providers[$provider->getId()] = $provider; |
||||||
|
} catch (QueryException $e) { |
||||||
|
// Log an continue. We can be fault tolerant here. |
||||||
|
$this->logger->logException($e, [ |
||||||
|
'message' => 'Could not load search provider dynamically: ' . $e->getMessage(), |
||||||
|
'level' => ILogger::ERROR, |
||||||
|
]); |
||||||
|
} |
||||||
|
} |
||||||
|
$this->lazyProviders = []; |
||||||
|
} |
||||||
|
|
||||||
|
public function getProviders(): array { |
||||||
|
$this->loadLazyProviders(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Return an array with the IDs, but strip the associative keys |
||||||
|
*/ |
||||||
|
return array_values( |
||||||
|
array_map(function (IProvider $provider) { |
||||||
|
return $provider->getId(); |
||||||
|
}, $this->providers)); |
||||||
|
} |
||||||
|
|
||||||
|
public function search(IUser $user, |
||||||
|
string $providerId, |
||||||
|
ISearchQuery $query): SearchResult { |
||||||
|
$this->loadLazyProviders(); |
||||||
|
|
||||||
|
return $this->providers[$providerId]->search($user, $query); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,88 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
/** |
||||||
|
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||||
|
* |
||||||
|
* @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||||
|
* |
||||||
|
* @license GNU AGPL version 3 or any later version |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as |
||||||
|
* published by the Free Software Foundation, either version 3 of the |
||||||
|
* License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace OC\Search; |
||||||
|
|
||||||
|
use OCP\Search\ISearchQuery; |
||||||
|
|
||||||
|
class SearchQuery implements ISearchQuery { |
||||||
|
public const LIMIT_DEFAULT = 20; |
||||||
|
|
||||||
|
/** @var string */ |
||||||
|
private $term; |
||||||
|
|
||||||
|
/** @var int */ |
||||||
|
private $sortOrder; |
||||||
|
|
||||||
|
/** @var int */ |
||||||
|
private $limit; |
||||||
|
|
||||||
|
/** @var int|string|null */ |
||||||
|
private $cursor; |
||||||
|
|
||||||
|
/** |
||||||
|
* @param string $term |
||||||
|
* @param int $sortOrder |
||||||
|
* @param int $limit |
||||||
|
* @param int|string|null $cursor |
||||||
|
*/ |
||||||
|
public function __construct(string $term, |
||||||
|
int $sortOrder = ISearchQuery::SORT_DATE_DESC, |
||||||
|
int $limit = self::LIMIT_DEFAULT, |
||||||
|
$cursor = null) { |
||||||
|
$this->term = $term; |
||||||
|
$this->sortOrder = $sortOrder; |
||||||
|
$this->limit = $limit; |
||||||
|
$this->cursor = $cursor; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritDoc |
||||||
|
*/ |
||||||
|
public function getTerm(): string { |
||||||
|
return $this->term; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritDoc |
||||||
|
*/ |
||||||
|
public function getSortOrder(): int { |
||||||
|
return $this->sortOrder; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritDoc |
||||||
|
*/ |
||||||
|
public function getLimit(): int { |
||||||
|
return $this->limit; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @inheritDoc |
||||||
|
*/ |
||||||
|
public function getCursor() { |
||||||
|
return $this->cursor; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,102 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
/** |
||||||
|
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||||
|
* |
||||||
|
* @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||||
|
* |
||||||
|
* @license GNU AGPL version 3 or any later version |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as |
||||||
|
* published by the Free Software Foundation, either version 3 of the |
||||||
|
* License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace OCP\Search; |
||||||
|
|
||||||
|
use JsonSerializable; |
||||||
|
|
||||||
|
/** |
||||||
|
* Represents an entry in a list of results an app returns for a unified search |
||||||
|
* query. |
||||||
|
* |
||||||
|
* The app providing the results has to extend this class for customization. In |
||||||
|
* most cases apps do not have to add any additional code. |
||||||
|
* |
||||||
|
* @example ``class MailResultEntry extends ASearchResultEntry {}` |
||||||
|
* |
||||||
|
* This approach was chosen over a final class as it allows Nextcloud to later |
||||||
|
* add new optional properties of an entry without having to break the usage of |
||||||
|
* this class in apps. |
||||||
|
* |
||||||
|
* @since 20.0.0 |
||||||
|
*/ |
||||||
|
abstract class ASearchResultEntry implements JsonSerializable { |
||||||
|
|
||||||
|
/** |
||||||
|
* @var string |
||||||
|
* @since 20.0.0 |
||||||
|
*/ |
||||||
|
protected $thumbnailUrl; |
||||||
|
|
||||||
|
/** |
||||||
|
* @var string |
||||||
|
* @since 20.0.0 |
||||||
|
*/ |
||||||
|
protected $title; |
||||||
|
|
||||||
|
/** |
||||||
|
* @var string |
||||||
|
* @since 20.0.0 |
||||||
|
*/ |
||||||
|
protected $subline; |
||||||
|
|
||||||
|
/** |
||||||
|
* @var string |
||||||
|
* @since 20.0.0 |
||||||
|
*/ |
||||||
|
protected $resourceUrl; |
||||||
|
|
||||||
|
/** |
||||||
|
* @param string $thumbnailUrl a relative or absolute URL to the thumbnail or icon of the entry |
||||||
|
* @param string $title a main title of the entry |
||||||
|
* @param string $subline the secondary line of the entry |
||||||
|
* @param string $resourceUrl the URL where the user can find the detail, like a deep link inside the app |
||||||
|
* |
||||||
|
* @since 20.0.0 |
||||||
|
*/ |
||||||
|
public function __construct(string $thumbnailUrl, |
||||||
|
string $title, |
||||||
|
string $subline, |
||||||
|
string $resourceUrl) { |
||||||
|
$this->thumbnailUrl = $thumbnailUrl; |
||||||
|
$this->title = $title; |
||||||
|
$this->subline = $subline; |
||||||
|
$this->resourceUrl = $resourceUrl; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return array |
||||||
|
* |
||||||
|
* @since 20.0.0 |
||||||
|
*/ |
||||||
|
public function jsonSerialize(): array { |
||||||
|
return [ |
||||||
|
'thumbnailUrl' => $this->thumbnailUrl, |
||||||
|
'title' => $this->title, |
||||||
|
'subline' => $this->subline, |
||||||
|
'resourceUrl' => $this->resourceUrl, |
||||||
|
]; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,83 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
/** |
||||||
|
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||||
|
* |
||||||
|
* @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||||
|
* |
||||||
|
* @license GNU AGPL version 3 or any later version |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as |
||||||
|
* published by the Free Software Foundation, either version 3 of the |
||||||
|
* License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace OCP\Search; |
||||||
|
|
||||||
|
use OCP\IUser; |
||||||
|
|
||||||
|
/** |
||||||
|
* Interface for an app search providers |
||||||
|
* |
||||||
|
* These providers will be implemented in apps, so they can participate in the |
||||||
|
* global search results of Nextcloud. If an app provides more than one type of |
||||||
|
* resource, e.g. contacts and address books in Nextcloud Contacts, it should |
||||||
|
* register one provider per group. |
||||||
|
* |
||||||
|
* @since 20.0.0 |
||||||
|
*/ |
||||||
|
interface IProvider { |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the unique ID of this search provider |
||||||
|
* |
||||||
|
* Ideally this should be the app name or an identifier identified with the |
||||||
|
* app name, especially if the app registers more than one provider. |
||||||
|
* |
||||||
|
* Example: 'mail', 'mail_recipients', 'files_sharing' |
||||||
|
* |
||||||
|
* @return string |
||||||
|
* |
||||||
|
* @since 20.0.0 |
||||||
|
*/ |
||||||
|
public function getId(): string; |
||||||
|
|
||||||
|
/** |
||||||
|
* Find matching search entries in an app |
||||||
|
* |
||||||
|
* Search results can either be a complete list of all the matches the app can |
||||||
|
* find, or ideally a paginated result set where more data can be fetched on |
||||||
|
* demand. To be able to tell where the next offset starts the search uses |
||||||
|
* "cursors" which are a property of the last result entry. E.g. search results |
||||||
|
* that show most recent entries first can look for entries older than the last |
||||||
|
* one of the first result set. This approach was chosen over a numeric limit/ |
||||||
|
* offset approach as the offset moves as new data comes in. The cursor is |
||||||
|
* resistant to these changes and will still show results without overlaps or |
||||||
|
* gaps. |
||||||
|
* |
||||||
|
* See https://dev.to/jackmarchant/offset-and-cursor-pagination-explained-b89 |
||||||
|
* for the concept of cursors. |
||||||
|
* |
||||||
|
* Implementations that return result pages have to adhere to the limit |
||||||
|
* property of a search query. |
||||||
|
* |
||||||
|
* @param IUser $user |
||||||
|
* @param ISearchQuery $query |
||||||
|
* |
||||||
|
* @return SearchResult |
||||||
|
* |
||||||
|
* @since 20.0.0 |
||||||
|
*/ |
||||||
|
public function search(IUser $user, ISearchQuery $query): SearchResult; |
||||||
|
} |
@ -0,0 +1,79 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
/** |
||||||
|
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||||
|
* |
||||||
|
* @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||||
|
* |
||||||
|
* @license GNU AGPL version 3 or any later version |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as |
||||||
|
* published by the Free Software Foundation, either version 3 of the |
||||||
|
* License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace OCP\Search; |
||||||
|
|
||||||
|
/** |
||||||
|
* The query objected passed into \OCP\Search\IProvider::search |
||||||
|
* |
||||||
|
* This mainly wraps the search term, but will ensure that Nextcloud can add new |
||||||
|
* optional properties to a search request without having break the interface of |
||||||
|
* \OCP\Search\IProvider::search. |
||||||
|
* |
||||||
|
* @see \OCP\Search\IProvider::search |
||||||
|
* |
||||||
|
* @since 20.0.0 |
||||||
|
*/ |
||||||
|
interface ISearchQuery { |
||||||
|
|
||||||
|
/** |
||||||
|
* @since 20.0.0 |
||||||
|
*/ |
||||||
|
public const SORT_DATE_DESC = 1; |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the user-entered search term to find matches for |
||||||
|
* |
||||||
|
* @return string the search term |
||||||
|
* @since 20.0.0 |
||||||
|
*/ |
||||||
|
public function getTerm(): string; |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the sort order of results as defined as SORT_* constants on this interface |
||||||
|
* |
||||||
|
* @return int |
||||||
|
* @since 20.0.0 |
||||||
|
*/ |
||||||
|
public function getSortOrder(): int; |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the number of items to return for a paginated result |
||||||
|
* |
||||||
|
* @return int |
||||||
|
* @see \OCP\Search\IProvider for details |
||||||
|
* @since 20.0.0 |
||||||
|
*/ |
||||||
|
public function getLimit(): int; |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the app-specific cursor of the tail of the previous result entries |
||||||
|
* |
||||||
|
* @return int|string|null |
||||||
|
* @see \OCP\Search\IProvider for details |
||||||
|
* @since 20.0.0 |
||||||
|
*/ |
||||||
|
public function getCursor(); |
||||||
|
} |
@ -0,0 +1,112 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
/** |
||||||
|
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||||
|
* |
||||||
|
* @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||||
|
* |
||||||
|
* @license GNU AGPL version 3 or any later version |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as |
||||||
|
* published by the Free Software Foundation, either version 3 of the |
||||||
|
* License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace OCP\Search; |
||||||
|
|
||||||
|
use JsonSerializable; |
||||||
|
|
||||||
|
/** |
||||||
|
* @since 20.0.0 |
||||||
|
*/ |
||||||
|
final class SearchResult implements JsonSerializable { |
||||||
|
|
||||||
|
/** @var string */ |
||||||
|
private $name; |
||||||
|
|
||||||
|
/** @var bool */ |
||||||
|
private $isPaginated; |
||||||
|
|
||||||
|
/** @var ASearchResultEntry[] */ |
||||||
|
private $entries; |
||||||
|
|
||||||
|
/** @var int|string|null */ |
||||||
|
private $cursor; |
||||||
|
|
||||||
|
/** |
||||||
|
* @param string $name the translated name of the result section or group, e.g. "Mail" |
||||||
|
* @param bool $isPaginated |
||||||
|
* @param ASearchResultEntry[] $entries |
||||||
|
* @param null $cursor |
||||||
|
* |
||||||
|
* @since 20.0.0 |
||||||
|
*/ |
||||||
|
private function __construct(string $name, |
||||||
|
bool $isPaginated, |
||||||
|
array $entries, |
||||||
|
$cursor = null) { |
||||||
|
$this->name = $name; |
||||||
|
$this->isPaginated = $isPaginated; |
||||||
|
$this->entries = $entries; |
||||||
|
$this->cursor = $cursor; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param ASearchResultEntry[] $entries |
||||||
|
* |
||||||
|
* @return static |
||||||
|
* |
||||||
|
* @since 20.0.0 |
||||||
|
*/ |
||||||
|
public static function complete(string $name, array $entries): self { |
||||||
|
return new self( |
||||||
|
$name, |
||||||
|
false, |
||||||
|
$entries |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param ASearchResultEntry[] $entries |
||||||
|
* @param int|string $cursor |
||||||
|
* |
||||||
|
* @return static |
||||||
|
* |
||||||
|
* @since 20.0.0 |
||||||
|
*/ |
||||||
|
public static function paginated(string $name, |
||||||
|
array $entries, |
||||||
|
$cursor): self { |
||||||
|
return new self( |
||||||
|
$name, |
||||||
|
true, |
||||||
|
$entries, |
||||||
|
$cursor |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return array |
||||||
|
* |
||||||
|
* @since 20.0.0 |
||||||
|
*/ |
||||||
|
public function jsonSerialize(): array { |
||||||
|
return [ |
||||||
|
'name' => $this->name, |
||||||
|
'isPaginated' => $this->isPaginated, |
||||||
|
'entries' => $this->entries, |
||||||
|
'cursor' => $this->cursor, |
||||||
|
]; |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue