Handle pagination through BookmarkService
Handle all search results through SearchResult object. This is a required step toward implementing a BookmarkService based on SQL database. Related to #953
This commit is contained in:
parent
055d97f9a9
commit
9b8c0a4560
20 changed files with 420 additions and 149 deletions
|
@ -36,13 +36,6 @@ class Links extends ApiController
|
|||
public function getLinks($request, $response)
|
||||
{
|
||||
$private = $request->getParam('visibility');
|
||||
$bookmarks = $this->bookmarkService->search(
|
||||
[
|
||||
'searchtags' => $request->getParam('searchtags', ''),
|
||||
'searchterm' => $request->getParam('searchterm', ''),
|
||||
],
|
||||
$private
|
||||
);
|
||||
|
||||
// Return bookmarks from the {offset}th link, starting from 0.
|
||||
$offset = $request->getParam('offset');
|
||||
|
@ -50,9 +43,6 @@ public function getLinks($request, $response)
|
|||
throw new ApiBadParametersException('Invalid offset');
|
||||
}
|
||||
$offset = ! empty($offset) ? intval($offset) : 0;
|
||||
if ($offset > count($bookmarks)) {
|
||||
return $response->withJson([], 200, $this->jsonStyle);
|
||||
}
|
||||
|
||||
// limit parameter is either a number of bookmarks or 'all' for everything.
|
||||
$limit = $request->getParam('limit');
|
||||
|
@ -61,24 +51,34 @@ public function getLinks($request, $response)
|
|||
} elseif (ctype_digit($limit)) {
|
||||
$limit = intval($limit);
|
||||
} elseif ($limit === 'all') {
|
||||
$limit = count($bookmarks);
|
||||
$limit = null;
|
||||
} else {
|
||||
throw new ApiBadParametersException('Invalid limit');
|
||||
}
|
||||
|
||||
$searchResult = $this->bookmarkService->search(
|
||||
[
|
||||
'searchtags' => $request->getParam('searchtags', ''),
|
||||
'searchterm' => $request->getParam('searchterm', ''),
|
||||
],
|
||||
$private,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
[
|
||||
'limit' => $limit,
|
||||
'offset' => $offset,
|
||||
'allowOutOfBounds' => true,
|
||||
]
|
||||
);
|
||||
|
||||
// 'environment' is set by Slim and encapsulate $_SERVER.
|
||||
$indexUrl = index_url($this->ci['environment']);
|
||||
|
||||
$out = [];
|
||||
$index = 0;
|
||||
foreach ($bookmarks as $bookmark) {
|
||||
if (count($out) >= $limit) {
|
||||
break;
|
||||
}
|
||||
if ($index++ >= $offset) {
|
||||
foreach ($searchResult->getBookmarks() as $bookmark) {
|
||||
$out[] = ApiUtils::formatLink($bookmark, $indexUrl);
|
||||
}
|
||||
}
|
||||
|
||||
return $response->withJson($out, 200, $this->jsonStyle);
|
||||
}
|
||||
|
|
|
@ -122,12 +122,12 @@ public function putTag($request, $response, $args)
|
|||
throw new ApiBadParametersException('New tag name is required in the request body');
|
||||
}
|
||||
|
||||
$bookmarks = $this->bookmarkService->search(
|
||||
$searchResult = $this->bookmarkService->search(
|
||||
['searchtags' => $args['tagName']],
|
||||
BookmarkFilter::$ALL,
|
||||
true
|
||||
);
|
||||
foreach ($bookmarks as $bookmark) {
|
||||
foreach ($searchResult->getBookmarks() as $bookmark) {
|
||||
$bookmark->renameTag($args['tagName'], $data['name']);
|
||||
$this->bookmarkService->set($bookmark, false);
|
||||
$this->history->updateLink($bookmark);
|
||||
|
@ -157,12 +157,12 @@ public function deleteTag($request, $response, $args)
|
|||
throw new ApiTagNotFoundException();
|
||||
}
|
||||
|
||||
$bookmarks = $this->bookmarkService->search(
|
||||
$searchResult = $this->bookmarkService->search(
|
||||
['searchtags' => $args['tagName']],
|
||||
BookmarkFilter::$ALL,
|
||||
true
|
||||
);
|
||||
foreach ($bookmarks as $bookmark) {
|
||||
foreach ($searchResult->getBookmarks() as $bookmark) {
|
||||
$bookmark->deleteTag($args['tagName']);
|
||||
$this->bookmarkService->set($bookmark, false);
|
||||
$this->history->updateLink($bookmark);
|
||||
|
|
|
@ -55,8 +55,12 @@ class BookmarkFileService implements BookmarkServiceInterface
|
|||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function __construct(ConfigManager $conf, History $history, Mutex $mutex, bool $isLoggedIn)
|
||||
{
|
||||
public function __construct(
|
||||
ConfigManager $conf,
|
||||
History $history,
|
||||
Mutex $mutex,
|
||||
bool $isLoggedIn
|
||||
) {
|
||||
$this->conf = $conf;
|
||||
$this->history = $history;
|
||||
$this->mutex = $mutex;
|
||||
|
@ -129,8 +133,9 @@ public function search(
|
|||
string $visibility = null,
|
||||
bool $caseSensitive = false,
|
||||
bool $untaggedOnly = false,
|
||||
bool $ignoreSticky = false
|
||||
) {
|
||||
bool $ignoreSticky = false,
|
||||
array $pagination = []
|
||||
): SearchResult {
|
||||
if ($visibility === null) {
|
||||
$visibility = $this->isLoggedIn ? BookmarkFilter::$ALL : BookmarkFilter::$PUBLIC;
|
||||
}
|
||||
|
@ -143,13 +148,20 @@ public function search(
|
|||
$this->bookmarks->reorder('DESC', true);
|
||||
}
|
||||
|
||||
return $this->bookmarkFilter->filter(
|
||||
$bookmarks = $this->bookmarkFilter->filter(
|
||||
BookmarkFilter::$FILTER_TAG | BookmarkFilter::$FILTER_TEXT,
|
||||
[$searchTags, $searchTerm],
|
||||
$caseSensitive,
|
||||
$visibility,
|
||||
$untaggedOnly
|
||||
);
|
||||
|
||||
return SearchResult::getSearchResult(
|
||||
$bookmarks,
|
||||
$pagination['offset'] ?? 0,
|
||||
$pagination['limit'] ?? null,
|
||||
$pagination['allowOutOfBounds'] ?? false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -282,7 +294,7 @@ public function exists(int $id, string $visibility = null): bool
|
|||
*/
|
||||
public function count(string $visibility = null): int
|
||||
{
|
||||
return count($this->search([], $visibility));
|
||||
return $this->search([], $visibility)->getResultCount();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -305,10 +317,10 @@ public function save(): void
|
|||
*/
|
||||
public function bookmarksCountPerTag(array $filteringTags = [], string $visibility = null): array
|
||||
{
|
||||
$bookmarks = $this->search(['searchtags' => $filteringTags], $visibility);
|
||||
$searchResult = $this->search(['searchtags' => $filteringTags], $visibility);
|
||||
$tags = [];
|
||||
$caseMapping = [];
|
||||
foreach ($bookmarks as $bookmark) {
|
||||
foreach ($searchResult->getBookmarks() as $bookmark) {
|
||||
foreach ($bookmark->getTags() as $tag) {
|
||||
if (
|
||||
empty($tag)
|
||||
|
@ -357,7 +369,7 @@ public function findByDate(
|
|||
$previous = null;
|
||||
$next = null;
|
||||
|
||||
foreach ($this->search([], null, false, false, true) as $bookmark) {
|
||||
foreach ($this->search([], null, false, false, true)->getBookmarks() as $bookmark) {
|
||||
if ($to < $bookmark->getCreated()) {
|
||||
$next = $bookmark->getCreated();
|
||||
} elseif ($from < $bookmark->getCreated() && $to > $bookmark->getCreated()) {
|
||||
|
@ -378,7 +390,7 @@ public function findByDate(
|
|||
*/
|
||||
public function getLatest(): ?Bookmark
|
||||
{
|
||||
foreach ($this->search([], null, false, false, true) as $bookmark) {
|
||||
foreach ($this->search([], null, false, false, true)->getBookmarks() as $bookmark) {
|
||||
return $bookmark;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,16 +44,18 @@ public function findByUrl(string $url): ?Bookmark;
|
|||
* @param bool $caseSensitive
|
||||
* @param bool $untaggedOnly
|
||||
* @param bool $ignoreSticky
|
||||
* @param array $pagination This array can contain the following keys for pagination: limit, offset.
|
||||
*
|
||||
* @return Bookmark[]
|
||||
* @return SearchResult
|
||||
*/
|
||||
public function search(
|
||||
array $request = [],
|
||||
string $visibility = null,
|
||||
bool $caseSensitive = false,
|
||||
bool $untaggedOnly = false,
|
||||
bool $ignoreSticky = false
|
||||
);
|
||||
bool $ignoreSticky = false,
|
||||
array $pagination = []
|
||||
): SearchResult;
|
||||
|
||||
/**
|
||||
* Get a single bookmark by its ID.
|
||||
|
|
136
application/bookmark/SearchResult.php
Normal file
136
application/bookmark/SearchResult.php
Normal file
|
@ -0,0 +1,136 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shaarli\Bookmark;
|
||||
|
||||
/**
|
||||
* Read-only class used to represent search result, including pagination.
|
||||
*/
|
||||
class SearchResult
|
||||
{
|
||||
/** @var Bookmark[] List of result bookmarks with pagination applied */
|
||||
protected $bookmarks;
|
||||
|
||||
/** @var int number of Bookmarks found, with pagination applied */
|
||||
protected $resultCount;
|
||||
|
||||
/** @var int total number of result found */
|
||||
protected $totalCount;
|
||||
|
||||
/** @var int pagination: limit number of result bookmarks */
|
||||
protected $limit;
|
||||
|
||||
/** @var int pagination: offset to apply to complete result list */
|
||||
protected $offset;
|
||||
|
||||
public function __construct(array $bookmarks, int $totalCount, int $offset, ?int $limit)
|
||||
{
|
||||
$this->bookmarks = $bookmarks;
|
||||
$this->resultCount = count($bookmarks);
|
||||
$this->totalCount = $totalCount;
|
||||
$this->limit = $limit;
|
||||
$this->offset = $offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a SearchResult from provided full result set and pagination settings.
|
||||
*
|
||||
* @param Bookmark[] $bookmarks Full set of result which will be filtered
|
||||
* @param int $offset Start recording results from $offset
|
||||
* @param int|null $limit End recording results after $limit bookmarks is reached
|
||||
* @param bool $allowOutOfBounds Set to false to display the last page if the offset is out of bound,
|
||||
* return empty result set otherwise (default: false)
|
||||
*
|
||||
* @return SearchResult
|
||||
*/
|
||||
public static function getSearchResult(
|
||||
$bookmarks,
|
||||
int $offset = 0,
|
||||
?int $limit = null,
|
||||
bool $allowOutOfBounds = false
|
||||
): self {
|
||||
$totalCount = count($bookmarks);
|
||||
if (!$allowOutOfBounds && $offset > $totalCount) {
|
||||
$offset = $limit === null ? 0 : $limit * -1;
|
||||
}
|
||||
|
||||
if ($bookmarks instanceof BookmarkArray) {
|
||||
$buffer = [];
|
||||
foreach ($bookmarks as $key => $value) {
|
||||
$buffer[$key] = $value;
|
||||
}
|
||||
$bookmarks = $buffer;
|
||||
}
|
||||
|
||||
return new static(
|
||||
array_slice($bookmarks, $offset, $limit, true),
|
||||
$totalCount,
|
||||
$offset,
|
||||
$limit
|
||||
);
|
||||
}
|
||||
|
||||
/** @return Bookmark[] List of result bookmarks with pagination applied */
|
||||
public function getBookmarks(): array
|
||||
{
|
||||
return $this->bookmarks;
|
||||
}
|
||||
|
||||
/** @return int number of Bookmarks found, with pagination applied */
|
||||
public function getResultCount(): int
|
||||
{
|
||||
return $this->resultCount;
|
||||
}
|
||||
|
||||
/** @return int total number of result found */
|
||||
public function getTotalCount(): int
|
||||
{
|
||||
return $this->totalCount;
|
||||
}
|
||||
|
||||
/** @return int pagination: limit number of result bookmarks */
|
||||
public function getLimit(): ?int
|
||||
{
|
||||
return $this->limit;
|
||||
}
|
||||
|
||||
/** @return int pagination: offset to apply to complete result list */
|
||||
public function getOffset(): int
|
||||
{
|
||||
return $this->offset;
|
||||
}
|
||||
|
||||
/** @return int Current page of result set in complete results */
|
||||
public function getPage(): int
|
||||
{
|
||||
if (empty($this->limit)) {
|
||||
return $this->offset === 0 ? 1 : 2;
|
||||
}
|
||||
$base = $this->offset >= 0 ? $this->offset : $this->totalCount + $this->offset;
|
||||
|
||||
return (int) ceil($base / $this->limit) + 1;
|
||||
}
|
||||
|
||||
/** @return int Get the # of the last page */
|
||||
public function getLastPage(): int
|
||||
{
|
||||
if (empty($this->limit)) {
|
||||
return $this->offset === 0 ? 1 : 2;
|
||||
}
|
||||
|
||||
return (int) ceil($this->totalCount / $this->limit);
|
||||
}
|
||||
|
||||
/** @return bool Either the current page is the last one or not */
|
||||
public function isLastPage(): bool
|
||||
{
|
||||
return $this->getPage() === $this->getLastPage();
|
||||
}
|
||||
|
||||
/** @return bool Either the current page is the first one or not */
|
||||
public function isFirstPage(): bool
|
||||
{
|
||||
return $this->offset === 0;
|
||||
}
|
||||
}
|
|
@ -102,22 +102,16 @@ public function buildData(string $feedType, ?array $userInput)
|
|||
$userInput['searchtags'] = false;
|
||||
}
|
||||
|
||||
$limit = $this->getLimit($userInput);
|
||||
|
||||
// Optionally filter the results:
|
||||
$linksToDisplay = $this->linkDB->search($userInput ?? [], null, false, false, true);
|
||||
|
||||
$nblinksToDisplay = $this->getNbLinks(count($linksToDisplay), $userInput);
|
||||
|
||||
// Can't use array_keys() because $link is a LinkDB instance and not a real array.
|
||||
$keys = [];
|
||||
foreach ($linksToDisplay as $key => $value) {
|
||||
$keys[] = $key;
|
||||
}
|
||||
$searchResult = $this->linkDB->search($userInput ?? [], null, false, false, true, ['limit' => $limit]);
|
||||
|
||||
$pageaddr = escape(index_url($this->serverInfo));
|
||||
$this->formatter->addContextData('index_url', $pageaddr);
|
||||
$linkDisplayed = [];
|
||||
for ($i = 0; $i < $nblinksToDisplay && $i < count($keys); $i++) {
|
||||
$linkDisplayed[$keys[$i]] = $this->buildItem($feedType, $linksToDisplay[$keys[$i]], $pageaddr);
|
||||
$links = [];
|
||||
foreach ($searchResult->getBookmarks() as $key => $bookmark) {
|
||||
$links[$key] = $this->buildItem($feedType, $bookmark, $pageaddr);
|
||||
}
|
||||
|
||||
$data['language'] = $this->getTypeLanguage($feedType);
|
||||
|
@ -128,7 +122,7 @@ public function buildData(string $feedType, ?array $userInput)
|
|||
$data['self_link'] = $pageaddr . $requestUri;
|
||||
$data['index_url'] = $pageaddr;
|
||||
$data['usepermalinks'] = $this->usePermalinks === true;
|
||||
$data['links'] = $linkDisplayed;
|
||||
$data['links'] = $links;
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
@ -268,19 +262,18 @@ protected function getIsoDate(string $feedType, DateTime $date, $format = false)
|
|||
* If 'nb' not set or invalid, default value: $DEFAULT_NB_LINKS.
|
||||
* If 'nb' is set to 'all', display all filtered bookmarks (max parameter).
|
||||
*
|
||||
* @param int $max maximum number of bookmarks to display.
|
||||
* @param array $userInput $_GET.
|
||||
*
|
||||
* @return int number of bookmarks to display.
|
||||
*/
|
||||
protected function getNbLinks($max, ?array $userInput)
|
||||
protected function getLimit(?array $userInput)
|
||||
{
|
||||
if (empty($userInput['nb'])) {
|
||||
return self::$DEFAULT_NB_LINKS;
|
||||
}
|
||||
|
||||
if ($userInput['nb'] == 'all') {
|
||||
return $max;
|
||||
return null;
|
||||
}
|
||||
|
||||
$intNb = intval($userInput['nb']);
|
||||
|
|
|
@ -57,9 +57,12 @@ public function save(Request $request, Response $response): Response
|
|||
}
|
||||
|
||||
// TODO: move this to bookmark service
|
||||
$count = 0;
|
||||
$bookmarks = $this->container->bookmarkService->search(['searchtags' => $fromTag], BookmarkFilter::$ALL, true);
|
||||
foreach ($bookmarks as $bookmark) {
|
||||
$searchResult = $this->container->bookmarkService->search(
|
||||
['searchtags' => $fromTag],
|
||||
BookmarkFilter::$ALL,
|
||||
true
|
||||
);
|
||||
foreach ($searchResult->getBookmarks() as $bookmark) {
|
||||
if (false === $isDelete) {
|
||||
$bookmark->renameTag($fromTag, $toTag);
|
||||
} else {
|
||||
|
@ -68,11 +71,11 @@ public function save(Request $request, Response $response): Response
|
|||
|
||||
$this->container->bookmarkService->set($bookmark, false);
|
||||
$this->container->history->updateLink($bookmark);
|
||||
$count++;
|
||||
}
|
||||
|
||||
$this->container->bookmarkService->save();
|
||||
|
||||
$count = $searchResult->getResultCount();
|
||||
if (true === $isDelete) {
|
||||
$alert = sprintf(
|
||||
t('The tag was removed from %d bookmark.', 'The tag was removed from %d bookmarks.', $count),
|
||||
|
|
|
@ -22,7 +22,7 @@ class ThumbnailsController extends ShaarliAdminController
|
|||
public function index(Request $request, Response $response): Response
|
||||
{
|
||||
$ids = [];
|
||||
foreach ($this->container->bookmarkService->search() as $bookmark) {
|
||||
foreach ($this->container->bookmarkService->search()->getBookmarks() as $bookmark) {
|
||||
// A note or not HTTP(S)
|
||||
if ($bookmark->isNote() || !startsWith(strtolower($bookmark->getUrl()), 'http')) {
|
||||
continue;
|
||||
|
|
|
@ -36,7 +36,6 @@ public function index(Request $request, Response $response): Response
|
|||
|
||||
$searchTags = normalize_spaces($request->getParam('searchtags') ?? '');
|
||||
$searchTerm = escape(normalize_spaces($request->getParam('searchterm') ?? ''));
|
||||
;
|
||||
|
||||
// Filter bookmarks according search parameters.
|
||||
$visibility = $this->container->sessionManager->getSessionParameter('visibility');
|
||||
|
@ -44,39 +43,26 @@ public function index(Request $request, Response $response): Response
|
|||
'searchtags' => $searchTags,
|
||||
'searchterm' => $searchTerm,
|
||||
];
|
||||
$linksToDisplay = $this->container->bookmarkService->search(
|
||||
|
||||
// Select articles according to paging.
|
||||
$page = (int) ($request->getParam('page') ?? 1);
|
||||
$page = $page < 1 ? 1 : $page;
|
||||
$linksPerPage = $this->container->sessionManager->getSessionParameter('LINKS_PER_PAGE', 20) ?: 20;
|
||||
|
||||
$searchResult = $this->container->bookmarkService->search(
|
||||
$search,
|
||||
$visibility,
|
||||
false,
|
||||
!!$this->container->sessionManager->getSessionParameter('untaggedonly')
|
||||
!!$this->container->sessionManager->getSessionParameter('untaggedonly'),
|
||||
false,
|
||||
['offset' => $linksPerPage * ($page - 1), 'limit' => $linksPerPage]
|
||||
) ?? [];
|
||||
|
||||
// ---- Handle paging.
|
||||
$keys = [];
|
||||
foreach ($linksToDisplay as $key => $value) {
|
||||
$keys[] = $key;
|
||||
}
|
||||
|
||||
$linksPerPage = $this->container->sessionManager->getSessionParameter('LINKS_PER_PAGE', 20) ?: 20;
|
||||
|
||||
// Select articles according to paging.
|
||||
$pageCount = (int) ceil(count($keys) / $linksPerPage) ?: 1;
|
||||
$page = (int) $request->getParam('page') ?? 1;
|
||||
$page = $page < 1 ? 1 : $page;
|
||||
$page = $page > $pageCount ? $pageCount : $page;
|
||||
|
||||
// Start index.
|
||||
$i = ($page - 1) * $linksPerPage;
|
||||
$end = $i + $linksPerPage;
|
||||
|
||||
$linkDisp = [];
|
||||
$save = false;
|
||||
while ($i < $end && $i < count($keys)) {
|
||||
$save = $this->updateThumbnail($linksToDisplay[$keys[$i]], false) || $save;
|
||||
$link = $formatter->format($linksToDisplay[$keys[$i]]);
|
||||
|
||||
$linkDisp[$keys[$i]] = $link;
|
||||
$i++;
|
||||
$links = [];
|
||||
foreach ($searchResult->getBookmarks() as $key => $bookmark) {
|
||||
$save = $this->updateThumbnail($bookmark, false) || $save;
|
||||
$links[$key] = $formatter->format($bookmark);
|
||||
}
|
||||
|
||||
if ($save) {
|
||||
|
@ -86,15 +72,10 @@ public function index(Request $request, Response $response): Response
|
|||
// Compute paging navigation
|
||||
$searchtagsUrl = $searchTags === '' ? '' : '&searchtags=' . urlencode($searchTags);
|
||||
$searchtermUrl = $searchTerm === '' ? '' : '&searchterm=' . urlencode($searchTerm);
|
||||
$page = $searchResult->getPage();
|
||||
|
||||
$previous_page_url = '';
|
||||
if ($i !== count($keys)) {
|
||||
$previous_page_url = '?page=' . ($page + 1) . $searchtermUrl . $searchtagsUrl;
|
||||
}
|
||||
$next_page_url = '';
|
||||
if ($page > 1) {
|
||||
$next_page_url = '?page=' . ($page - 1) . $searchtermUrl . $searchtagsUrl;
|
||||
}
|
||||
$previousPageUrl = !$searchResult->isLastPage() ? '?page=' . ($page + 1) . $searchtermUrl . $searchtagsUrl : '';
|
||||
$nextPageUrl = !$searchResult->isFirstPage() ? '?page=' . ($page - 1) . $searchtermUrl . $searchtagsUrl : '';
|
||||
|
||||
$tagsSeparator = $this->container->conf->get('general.tags_separator', ' ');
|
||||
$searchTagsUrlEncoded = array_map('urlencode', tags_str2array($searchTags, $tagsSeparator));
|
||||
|
@ -104,16 +85,16 @@ public function index(Request $request, Response $response): Response
|
|||
$data = array_merge(
|
||||
$this->initializeTemplateVars(),
|
||||
[
|
||||
'previous_page_url' => $previous_page_url,
|
||||
'next_page_url' => $next_page_url,
|
||||
'previous_page_url' => $previousPageUrl,
|
||||
'next_page_url' => $nextPageUrl,
|
||||
'page_current' => $page,
|
||||
'page_max' => $pageCount,
|
||||
'result_count' => count($linksToDisplay),
|
||||
'page_max' => $searchResult->getLastPage(),
|
||||
'result_count' => $searchResult->getTotalCount(),
|
||||
'search_term' => escape($searchTerm),
|
||||
'search_tags' => escape($searchTags),
|
||||
'search_tags_url' => $searchTagsUrlEncoded,
|
||||
'visibility' => $visibility,
|
||||
'links' => $linkDisp,
|
||||
'links' => $links,
|
||||
]
|
||||
);
|
||||
|
||||
|
|
|
@ -100,7 +100,7 @@ public function rss(Request $request, Response $response): Response
|
|||
$days = [];
|
||||
$format = DailyPageHelper::getFormatByType($type);
|
||||
$length = DailyPageHelper::getRssLengthByType($type);
|
||||
foreach ($this->container->bookmarkService->search() as $bookmark) {
|
||||
foreach ($this->container->bookmarkService->search()->getBookmarks() as $bookmark) {
|
||||
$day = $bookmark->getCreated()->format($format);
|
||||
|
||||
// Stop iterating after DAILY_RSS_NB_DAYS entries
|
||||
|
|
|
@ -30,19 +30,19 @@ public function index(Request $request, Response $response): Response
|
|||
);
|
||||
|
||||
// Optionally filter the results:
|
||||
$links = $this->container->bookmarkService->search($request->getQueryParams());
|
||||
$linksToDisplay = [];
|
||||
$bookmarks = $this->container->bookmarkService->search($request->getQueryParams())->getBookmarks();
|
||||
$links = [];
|
||||
|
||||
// Get only bookmarks which have a thumbnail.
|
||||
// Note: we do not retrieve thumbnails here, the request is too heavy.
|
||||
$formatter = $this->container->formatterFactory->getFormatter('raw');
|
||||
foreach ($links as $key => $link) {
|
||||
if (!empty($link->getThumbnail())) {
|
||||
$linksToDisplay[] = $formatter->format($link);
|
||||
foreach ($bookmarks as $key => $bookmark) {
|
||||
if (!empty($bookmark->getThumbnail())) {
|
||||
$links[] = $formatter->format($bookmark);
|
||||
}
|
||||
}
|
||||
|
||||
$data = ['linksToDisplay' => $linksToDisplay];
|
||||
$data = ['linksToDisplay' => $links];
|
||||
$this->executePageHooks('render_picwall', $data, TemplatePage::PICTURE_WALL);
|
||||
|
||||
foreach ($data as $key => $value) {
|
||||
|
|
|
@ -64,7 +64,7 @@ public function filterAndFormat(
|
|||
}
|
||||
|
||||
$bookmarkLinks = [];
|
||||
foreach ($this->bookmarkService->search([], $selection) as $bookmark) {
|
||||
foreach ($this->bookmarkService->search([], $selection)->getBookmarks() as $bookmark) {
|
||||
$link = $formatter->format($bookmark);
|
||||
$link['taglist'] = implode(',', $bookmark->getTags());
|
||||
if ($bookmark->isNote() && $prependNoteUrl) {
|
||||
|
|
|
@ -152,7 +152,7 @@ public function updateMethodMigrateExistingNotesUrl(): bool
|
|||
{
|
||||
$updated = false;
|
||||
|
||||
foreach ($this->bookmarkService->search() as $bookmark) {
|
||||
foreach ($this->bookmarkService->search()->getBookmarks() as $bookmark) {
|
||||
if (
|
||||
$bookmark->isNote()
|
||||
&& startsWith($bookmark->getUrl(), '?')
|
||||
|
|
|
@ -807,7 +807,7 @@ public function testFilterString()
|
|||
$request = ['searchtags' => $tags];
|
||||
$this->assertEquals(
|
||||
2,
|
||||
count($this->privateLinkDB->search($request, null, true))
|
||||
count($this->privateLinkDB->search($request, null, true)->getBookmarks())
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -820,7 +820,7 @@ public function testFilterArray()
|
|||
$request = ['searchtags' => $tags];
|
||||
$this->assertEquals(
|
||||
2,
|
||||
count($this->privateLinkDB->search($request, null, true))
|
||||
count($this->privateLinkDB->search($request, null, true)->getBookmarks())
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -834,12 +834,12 @@ public function testHiddenTags()
|
|||
$request = ['searchtags' => $tags];
|
||||
$this->assertEquals(
|
||||
1,
|
||||
count($this->privateLinkDB->search($request, 'all', true))
|
||||
count($this->privateLinkDB->search($request, 'all', true)->getBookmarks())
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
0,
|
||||
count($this->publicLinkDB->search($request, 'public', true))
|
||||
count($this->publicLinkDB->search($request, 'public', true)->getBookmarks())
|
||||
);
|
||||
}
|
||||
|
||||
|
|
125
tests/bookmark/SearchResultTest.php
Normal file
125
tests/bookmark/SearchResultTest.php
Normal file
|
@ -0,0 +1,125 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shaarli\Bookmark;
|
||||
|
||||
use Shaarli\TestCase;
|
||||
|
||||
/**
|
||||
* Test SearchResult class.
|
||||
*/
|
||||
class SearchResultTest extends TestCase
|
||||
{
|
||||
/** Create a SearchResult without any pagination parameter. */
|
||||
public function testResultNoParameters(): void
|
||||
{
|
||||
$searchResult = SearchResult::getSearchResult($data = ['a', 'b', 'c', 'd', 'e', 'f']);
|
||||
|
||||
static::assertSame($data, $searchResult->getBookmarks());
|
||||
static::assertSame(6, $searchResult->getResultCount());
|
||||
static::assertSame(6, $searchResult->getTotalCount());
|
||||
static::assertSame(null, $searchResult->getLimit());
|
||||
static::assertSame(0, $searchResult->getOffset());
|
||||
static::assertSame(1, $searchResult->getPage());
|
||||
static::assertSame(1, $searchResult->getLastPage());
|
||||
static::assertTrue($searchResult->isFirstPage());
|
||||
static::assertTrue($searchResult->isLastPage());
|
||||
}
|
||||
|
||||
/** Create a SearchResult with only an offset parameter */
|
||||
public function testResultWithOffset(): void
|
||||
{
|
||||
$searchResult = SearchResult::getSearchResult(['a', 'b', 'c', 'd', 'e', 'f'], 2);
|
||||
|
||||
static::assertSame([2 => 'c', 3 => 'd', 4 => 'e', 5 => 'f'], $searchResult->getBookmarks());
|
||||
static::assertSame(4, $searchResult->getResultCount());
|
||||
static::assertSame(6, $searchResult->getTotalCount());
|
||||
static::assertSame(null, $searchResult->getLimit());
|
||||
static::assertSame(2, $searchResult->getOffset());
|
||||
static::assertSame(2, $searchResult->getPage());
|
||||
static::assertSame(2, $searchResult->getLastPage());
|
||||
static::assertFalse($searchResult->isFirstPage());
|
||||
static::assertTrue($searchResult->isLastPage());
|
||||
}
|
||||
|
||||
/** Create a SearchResult with only a limit parameter */
|
||||
public function testResultWithLimit(): void
|
||||
{
|
||||
$searchResult = SearchResult::getSearchResult(['a', 'b', 'c', 'd', 'e', 'f'], 0, 2);
|
||||
|
||||
static::assertSame([0 => 'a', 1 => 'b'], $searchResult->getBookmarks());
|
||||
static::assertSame(2, $searchResult->getResultCount());
|
||||
static::assertSame(6, $searchResult->getTotalCount());
|
||||
static::assertSame(2, $searchResult->getLimit());
|
||||
static::assertSame(0, $searchResult->getOffset());
|
||||
static::assertSame(1, $searchResult->getPage());
|
||||
static::assertSame(3, $searchResult->getLastPage());
|
||||
static::assertTrue($searchResult->isFirstPage());
|
||||
static::assertFalse($searchResult->isLastPage());
|
||||
}
|
||||
|
||||
/** Create a SearchResult with offset and limit parameters */
|
||||
public function testResultWithLimitAndOffset(): void
|
||||
{
|
||||
$searchResult = SearchResult::getSearchResult(['a', 'b', 'c', 'd', 'e', 'f'], 2, 2);
|
||||
|
||||
static::assertSame([2 => 'c', 3 => 'd'], $searchResult->getBookmarks());
|
||||
static::assertSame(2, $searchResult->getResultCount());
|
||||
static::assertSame(6, $searchResult->getTotalCount());
|
||||
static::assertSame(2, $searchResult->getLimit());
|
||||
static::assertSame(2, $searchResult->getOffset());
|
||||
static::assertSame(2, $searchResult->getPage());
|
||||
static::assertSame(3, $searchResult->getLastPage());
|
||||
static::assertFalse($searchResult->isFirstPage());
|
||||
static::assertFalse($searchResult->isLastPage());
|
||||
}
|
||||
|
||||
/** Create a SearchResult with offset and limit parameters displaying the last page */
|
||||
public function testResultWithLimitAndOffsetLastPage(): void
|
||||
{
|
||||
$searchResult = SearchResult::getSearchResult(['a', 'b', 'c', 'd', 'e', 'f'], 4, 2);
|
||||
|
||||
static::assertSame([4 => 'e', 5 => 'f'], $searchResult->getBookmarks());
|
||||
static::assertSame(2, $searchResult->getResultCount());
|
||||
static::assertSame(6, $searchResult->getTotalCount());
|
||||
static::assertSame(2, $searchResult->getLimit());
|
||||
static::assertSame(4, $searchResult->getOffset());
|
||||
static::assertSame(3, $searchResult->getPage());
|
||||
static::assertSame(3, $searchResult->getLastPage());
|
||||
static::assertFalse($searchResult->isFirstPage());
|
||||
static::assertTrue($searchResult->isLastPage());
|
||||
}
|
||||
|
||||
/** Create a SearchResult with offset and limit parameters out of bound (display the last page) */
|
||||
public function testResultWithLimitAndOffsetOutOfBounds(): void
|
||||
{
|
||||
$searchResult = SearchResult::getSearchResult(['a', 'b', 'c', 'd', 'e', 'f'], 12, 2);
|
||||
|
||||
static::assertSame([4 => 'e', 5 => 'f'], $searchResult->getBookmarks());
|
||||
static::assertSame(2, $searchResult->getResultCount());
|
||||
static::assertSame(6, $searchResult->getTotalCount());
|
||||
static::assertSame(2, $searchResult->getLimit());
|
||||
static::assertSame(-2, $searchResult->getOffset());
|
||||
static::assertSame(3, $searchResult->getPage());
|
||||
static::assertSame(3, $searchResult->getLastPage());
|
||||
static::assertFalse($searchResult->isFirstPage());
|
||||
static::assertTrue($searchResult->isLastPage());
|
||||
}
|
||||
|
||||
/** Create a SearchResult with offset and limit parameters out of bound (no result) */
|
||||
public function testResultWithLimitAndOffsetOutOfBoundsNoResult(): void
|
||||
{
|
||||
$searchResult = SearchResult::getSearchResult(['a', 'b', 'c', 'd', 'e', 'f'], 12, 2, true);
|
||||
|
||||
static::assertSame([], $searchResult->getBookmarks());
|
||||
static::assertSame(0, $searchResult->getResultCount());
|
||||
static::assertSame(6, $searchResult->getTotalCount());
|
||||
static::assertSame(2, $searchResult->getLimit());
|
||||
static::assertSame(12, $searchResult->getOffset());
|
||||
static::assertSame(7, $searchResult->getPage());
|
||||
static::assertSame(3, $searchResult->getLastPage());
|
||||
static::assertFalse($searchResult->isFirstPage());
|
||||
static::assertFalse($searchResult->isLastPage());
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
use Shaarli\Bookmark\Bookmark;
|
||||
use Shaarli\Bookmark\BookmarkFilter;
|
||||
use Shaarli\Bookmark\SearchResult;
|
||||
use Shaarli\Config\ConfigManager;
|
||||
use Shaarli\Front\Exception\WrongTokenException;
|
||||
use Shaarli\Security\SessionManager;
|
||||
|
@ -100,11 +101,11 @@ public function testSaveRenameTagValid(): void
|
|||
->expects(static::once())
|
||||
->method('search')
|
||||
->with(['searchtags' => 'old-tag'], BookmarkFilter::$ALL, true)
|
||||
->willReturnCallback(function () use ($bookmark1, $bookmark2): array {
|
||||
->willReturnCallback(function () use ($bookmark1, $bookmark2): SearchResult {
|
||||
$bookmark1->expects(static::once())->method('renameTag')->with('old-tag', 'new-tag');
|
||||
$bookmark2->expects(static::once())->method('renameTag')->with('old-tag', 'new-tag');
|
||||
|
||||
return [$bookmark1, $bookmark2];
|
||||
return SearchResult::getSearchResult([$bookmark1, $bookmark2]);
|
||||
})
|
||||
;
|
||||
$this->container->bookmarkService
|
||||
|
@ -153,11 +154,11 @@ public function testSaveDeleteTagValid(): void
|
|||
->expects(static::once())
|
||||
->method('search')
|
||||
->with(['searchtags' => 'old-tag'], BookmarkFilter::$ALL, true)
|
||||
->willReturnCallback(function () use ($bookmark1, $bookmark2): array {
|
||||
->willReturnCallback(function () use ($bookmark1, $bookmark2): SearchResult {
|
||||
$bookmark1->expects(static::once())->method('deleteTag')->with('old-tag');
|
||||
$bookmark2->expects(static::once())->method('deleteTag')->with('old-tag');
|
||||
|
||||
return [$bookmark1, $bookmark2];
|
||||
return SearchResult::getSearchResult([$bookmark1, $bookmark2]);
|
||||
})
|
||||
;
|
||||
$this->container->bookmarkService
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
use Shaarli\Bookmark\Bookmark;
|
||||
use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
|
||||
use Shaarli\Bookmark\SearchResult;
|
||||
use Shaarli\TestCase;
|
||||
use Shaarli\Thumbnailer;
|
||||
use Slim\Http\Request;
|
||||
|
@ -40,12 +41,12 @@ public function testIndex(): void
|
|||
$this->container->bookmarkService
|
||||
->expects(static::once())
|
||||
->method('search')
|
||||
->willReturn([
|
||||
->willReturn(SearchResult::getSearchResult([
|
||||
(new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'),
|
||||
(new Bookmark())->setId(2)->setUrl('?abcdef')->setTitle('Note 1'),
|
||||
(new Bookmark())->setId(3)->setUrl('http://url2.tld')->setTitle('Title 2'),
|
||||
(new Bookmark())->setId(4)->setUrl('ftp://domain.tld', ['ftp'])->setTitle('FTP'),
|
||||
])
|
||||
]))
|
||||
;
|
||||
|
||||
$result = $this->controller->index($request, $response);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
use Shaarli\Bookmark\Bookmark;
|
||||
use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
|
||||
use Shaarli\Bookmark\SearchResult;
|
||||
use Shaarli\Config\ConfigManager;
|
||||
use Shaarli\Security\LoginManager;
|
||||
use Shaarli\TestCase;
|
||||
|
@ -45,13 +46,15 @@ public function testIndexDefaultFirstPage(): void
|
|||
['searchtags' => '', 'searchterm' => ''],
|
||||
null,
|
||||
false,
|
||||
false
|
||||
false,
|
||||
false,
|
||||
['offset' => 0, 'limit' => 2]
|
||||
)
|
||||
->willReturn([
|
||||
->willReturn(SearchResult::getSearchResult([
|
||||
(new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'),
|
||||
(new Bookmark())->setId(2)->setUrl('http://url2.tld')->setTitle('Title 2'),
|
||||
(new Bookmark())->setId(3)->setUrl('http://url3.tld')->setTitle('Title 3'),
|
||||
]
|
||||
], 0, 2)
|
||||
);
|
||||
|
||||
$this->container->sessionManager
|
||||
|
@ -119,13 +122,15 @@ public function testIndexDefaultSecondPage(): void
|
|||
['searchtags' => '', 'searchterm' => ''],
|
||||
null,
|
||||
false,
|
||||
false
|
||||
false,
|
||||
false,
|
||||
['offset' => 2, 'limit' => 2]
|
||||
)
|
||||
->willReturn([
|
||||
->willReturn(SearchResult::getSearchResult([
|
||||
(new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'),
|
||||
(new Bookmark())->setId(2)->setUrl('http://url2.tld')->setTitle('Title 2'),
|
||||
(new Bookmark())->setId(3)->setUrl('http://url3.tld')->setTitle('Title 3'),
|
||||
])
|
||||
], 2, 2))
|
||||
;
|
||||
|
||||
$this->container->sessionManager
|
||||
|
@ -207,13 +212,15 @@ public function testIndexDefaultWithFilters(): void
|
|||
['searchtags' => 'abc@def', 'searchterm' => 'ghi jkl'],
|
||||
'private',
|
||||
false,
|
||||
true
|
||||
true,
|
||||
false,
|
||||
['offset' => 0, 'limit' => 2]
|
||||
)
|
||||
->willReturn([
|
||||
->willReturn(SearchResult::getSearchResult([
|
||||
(new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'),
|
||||
(new Bookmark())->setId(2)->setUrl('http://url2.tld')->setTitle('Title 2'),
|
||||
(new Bookmark())->setId(3)->setUrl('http://url3.tld')->setTitle('Title 3'),
|
||||
])
|
||||
], 0, 2))
|
||||
;
|
||||
|
||||
$result = $this->controller->index($request, $response);
|
||||
|
@ -358,13 +365,13 @@ public function testThumbnailUpdateFromLinkList(): void
|
|||
$this->container->bookmarkService
|
||||
->expects(static::once())
|
||||
->method('search')
|
||||
->willReturn([
|
||||
->willReturn(SearchResult::getSearchResult([
|
||||
(new Bookmark())->setId(1)->setUrl('https://url1.tld')->setTitle('Title 1')->setThumbnail(false),
|
||||
$b1 = (new Bookmark())->setId(2)->setUrl('https://url2.tld')->setTitle('Title 2'),
|
||||
(new Bookmark())->setId(3)->setUrl('https://url3.tld')->setTitle('Title 3')->setThumbnail(false),
|
||||
$b2 = (new Bookmark())->setId(2)->setUrl('https://url4.tld')->setTitle('Title 4'),
|
||||
(new Bookmark())->setId(2)->setUrl('ftp://url5.tld', ['ftp'])->setTitle('Title 5'),
|
||||
])
|
||||
]))
|
||||
;
|
||||
$this->container->bookmarkService
|
||||
->expects(static::exactly(2))
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
namespace Shaarli\Front\Controller\Visitor;
|
||||
|
||||
use Shaarli\Bookmark\Bookmark;
|
||||
use Shaarli\Bookmark\SearchResult;
|
||||
use Shaarli\Feed\CachedPage;
|
||||
use Shaarli\TestCase;
|
||||
use Slim\Http\Request;
|
||||
|
@ -347,13 +348,15 @@ public function testValidRssControllerInvokeDefault(): void
|
|||
$request = $this->createMock(Request::class);
|
||||
$response = new Response();
|
||||
|
||||
$this->container->bookmarkService->expects(static::once())->method('search')->willReturn([
|
||||
$this->container->bookmarkService->expects(static::once())->method('search')->willReturn(
|
||||
SearchResult::getSearchResult([
|
||||
(new Bookmark())->setId(1)->setCreated($dates[0])->setUrl('http://domain.tld/1'),
|
||||
(new Bookmark())->setId(2)->setCreated($dates[1])->setUrl('http://domain.tld/2'),
|
||||
(new Bookmark())->setId(3)->setCreated($dates[1])->setUrl('http://domain.tld/3'),
|
||||
(new Bookmark())->setId(4)->setCreated($dates[2])->setUrl('http://domain.tld/4'),
|
||||
(new Bookmark())->setId(5)->setCreated($dates[3])->setUrl('http://domain.tld/5'),
|
||||
]);
|
||||
])
|
||||
);
|
||||
|
||||
$this->container->pageCacheManager
|
||||
->expects(static::once())
|
||||
|
@ -454,7 +457,9 @@ public function testValidRssControllerInvokeNoBookmark(): void
|
|||
$request = $this->createMock(Request::class);
|
||||
$response = new Response();
|
||||
|
||||
$this->container->bookmarkService->expects(static::once())->method('search')->willReturn([]);
|
||||
$this->container->bookmarkService
|
||||
->expects(static::once())->method('search')
|
||||
->willReturn(SearchResult::getSearchResult([]));
|
||||
|
||||
// Save RainTPL assigned variables
|
||||
$assignedVariables = [];
|
||||
|
@ -613,11 +618,13 @@ public function testSimpleRssWeekly(): void
|
|||
});
|
||||
$response = new Response();
|
||||
|
||||
$this->container->bookmarkService->expects(static::once())->method('search')->willReturn([
|
||||
$this->container->bookmarkService->expects(static::once())->method('search')->willReturn(
|
||||
SearchResult::getSearchResult([
|
||||
(new Bookmark())->setId(1)->setCreated($dates[0])->setUrl('http://domain.tld/1'),
|
||||
(new Bookmark())->setId(2)->setCreated($dates[1])->setUrl('http://domain.tld/2'),
|
||||
(new Bookmark())->setId(3)->setCreated($dates[1])->setUrl('http://domain.tld/3'),
|
||||
]);
|
||||
])
|
||||
);
|
||||
|
||||
// Save RainTPL assigned variables
|
||||
$assignedVariables = [];
|
||||
|
@ -674,11 +681,13 @@ public function testSimpleRssMonthly(): void
|
|||
});
|
||||
$response = new Response();
|
||||
|
||||
$this->container->bookmarkService->expects(static::once())->method('search')->willReturn([
|
||||
$this->container->bookmarkService->expects(static::once())->method('search')->willReturn(
|
||||
SearchResult::getSearchResult([
|
||||
(new Bookmark())->setId(1)->setCreated($dates[0])->setUrl('http://domain.tld/1'),
|
||||
(new Bookmark())->setId(2)->setCreated($dates[1])->setUrl('http://domain.tld/2'),
|
||||
(new Bookmark())->setId(3)->setCreated($dates[1])->setUrl('http://domain.tld/3'),
|
||||
]);
|
||||
])
|
||||
);
|
||||
|
||||
// Save RainTPL assigned variables
|
||||
$assignedVariables = [];
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
namespace Shaarli\Front\Controller\Visitor;
|
||||
|
||||
use Shaarli\Bookmark\Bookmark;
|
||||
use Shaarli\Bookmark\SearchResult;
|
||||
use Shaarli\Config\ConfigManager;
|
||||
use Shaarli\Front\Exception\ThumbnailsDisabledException;
|
||||
use Shaarli\TestCase;
|
||||
|
@ -50,17 +51,17 @@ public function testValidControllerInvokeDefault(): void
|
|||
$this->container->bookmarkService
|
||||
->expects(static::once())
|
||||
->method('search')
|
||||
->willReturnCallback(function (array $parameters, ?string $visibility): array {
|
||||
->willReturnCallback(function (array $parameters, ?string $visibility): SearchResult {
|
||||
// Visibility is set through the container, not the call
|
||||
static::assertNull($visibility);
|
||||
|
||||
// No query parameters
|
||||
if (count($parameters) === 0) {
|
||||
return [
|
||||
return SearchResult::getSearchResult([
|
||||
(new Bookmark())->setId(1)->setUrl('http://url.tld')->setThumbnail('thumb1'),
|
||||
(new Bookmark())->setId(2)->setUrl('http://url2.tld'),
|
||||
(new Bookmark())->setId(3)->setUrl('http://url3.tld')->setThumbnail('thumb2'),
|
||||
];
|
||||
]);
|
||||
}
|
||||
})
|
||||
;
|
||||
|
|
Loading…
Reference in a new issue