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:
ArthurHoaro 2021-01-20 14:45:59 +01:00
parent 055d97f9a9
commit 9b8c0a4560
20 changed files with 420 additions and 149 deletions

View file

@ -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);
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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.

View 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;
}
}

View file

@ -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']);

View file

@ -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),

View file

@ -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;

View file

@ -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,
]
);

View file

@ -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

View file

@ -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) {

View file

@ -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) {

View file

@ -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(), '?')

View file

@ -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())
);
}

View 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());
}
}

View file

@ -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

View file

@ -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);

View file

@ -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))

View file

@ -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 = [];

View file

@ -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'),
];
]);
}
})
;