aboutsummaryrefslogtreecommitdiffhomepage
path: root/application
diff options
context:
space:
mode:
Diffstat (limited to 'application')
-rw-r--r--application/api/controllers/Links.php38
-rw-r--r--application/api/controllers/Tags.php8
-rw-r--r--application/bookmark/BookmarkFileService.php32
-rw-r--r--application/bookmark/BookmarkServiceInterface.php8
-rw-r--r--application/bookmark/SearchResult.php136
-rw-r--r--application/feed/FeedBuilder.php25
-rw-r--r--application/front/controller/admin/ManageTagController.php11
-rw-r--r--application/front/controller/admin/ThumbnailsController.php2
-rw-r--r--application/front/controller/visitor/BookmarkListController.php63
-rw-r--r--application/front/controller/visitor/DailyController.php2
-rw-r--r--application/front/controller/visitor/PictureWallController.php12
-rw-r--r--application/netscape/NetscapeBookmarkUtils.php2
-rw-r--r--application/updater/Updater.php2
13 files changed, 234 insertions, 107 deletions
diff --git a/application/api/controllers/Links.php b/application/api/controllers/Links.php
index b83b2260..fe4bdc9f 100644
--- a/application/api/controllers/Links.php
+++ b/application/api/controllers/Links.php
@@ -36,13 +36,6 @@ class Links extends ApiController
36 public function getLinks($request, $response) 36 public function getLinks($request, $response)
37 { 37 {
38 $private = $request->getParam('visibility'); 38 $private = $request->getParam('visibility');
39 $bookmarks = $this->bookmarkService->search(
40 [
41 'searchtags' => $request->getParam('searchtags', ''),
42 'searchterm' => $request->getParam('searchterm', ''),
43 ],
44 $private
45 );
46 39
47 // Return bookmarks from the {offset}th link, starting from 0. 40 // Return bookmarks from the {offset}th link, starting from 0.
48 $offset = $request->getParam('offset'); 41 $offset = $request->getParam('offset');
@@ -50,9 +43,6 @@ class Links extends ApiController
50 throw new ApiBadParametersException('Invalid offset'); 43 throw new ApiBadParametersException('Invalid offset');
51 } 44 }
52 $offset = ! empty($offset) ? intval($offset) : 0; 45 $offset = ! empty($offset) ? intval($offset) : 0;
53 if ($offset > count($bookmarks)) {
54 return $response->withJson([], 200, $this->jsonStyle);
55 }
56 46
57 // limit parameter is either a number of bookmarks or 'all' for everything. 47 // limit parameter is either a number of bookmarks or 'all' for everything.
58 $limit = $request->getParam('limit'); 48 $limit = $request->getParam('limit');
@@ -61,23 +51,33 @@ class Links extends ApiController
61 } elseif (ctype_digit($limit)) { 51 } elseif (ctype_digit($limit)) {
62 $limit = intval($limit); 52 $limit = intval($limit);
63 } elseif ($limit === 'all') { 53 } elseif ($limit === 'all') {
64 $limit = count($bookmarks); 54 $limit = null;
65 } else { 55 } else {
66 throw new ApiBadParametersException('Invalid limit'); 56 throw new ApiBadParametersException('Invalid limit');
67 } 57 }
68 58
59 $searchResult = $this->bookmarkService->search(
60 [
61 'searchtags' => $request->getParam('searchtags', ''),
62 'searchterm' => $request->getParam('searchterm', ''),
63 ],
64 $private,
65 false,
66 false,
67 false,
68 [
69 'limit' => $limit,
70 'offset' => $offset,
71 'allowOutOfBounds' => true,
72 ]
73 );
74
69 // 'environment' is set by Slim and encapsulate $_SERVER. 75 // 'environment' is set by Slim and encapsulate $_SERVER.
70 $indexUrl = index_url($this->ci['environment']); 76 $indexUrl = index_url($this->ci['environment']);
71 77
72 $out = []; 78 $out = [];
73 $index = 0; 79 foreach ($searchResult->getBookmarks() as $bookmark) {
74 foreach ($bookmarks as $bookmark) { 80 $out[] = ApiUtils::formatLink($bookmark, $indexUrl);
75 if (count($out) >= $limit) {
76 break;
77 }
78 if ($index++ >= $offset) {
79 $out[] = ApiUtils::formatLink($bookmark, $indexUrl);
80 }
81 } 81 }
82 82
83 return $response->withJson($out, 200, $this->jsonStyle); 83 return $response->withJson($out, 200, $this->jsonStyle);
diff --git a/application/api/controllers/Tags.php b/application/api/controllers/Tags.php
index e60e00a7..5a23f6db 100644
--- a/application/api/controllers/Tags.php
+++ b/application/api/controllers/Tags.php
@@ -122,12 +122,12 @@ class Tags extends ApiController
122 throw new ApiBadParametersException('New tag name is required in the request body'); 122 throw new ApiBadParametersException('New tag name is required in the request body');
123 } 123 }
124 124
125 $bookmarks = $this->bookmarkService->search( 125 $searchResult = $this->bookmarkService->search(
126 ['searchtags' => $args['tagName']], 126 ['searchtags' => $args['tagName']],
127 BookmarkFilter::$ALL, 127 BookmarkFilter::$ALL,
128 true 128 true
129 ); 129 );
130 foreach ($bookmarks as $bookmark) { 130 foreach ($searchResult->getBookmarks() as $bookmark) {
131 $bookmark->renameTag($args['tagName'], $data['name']); 131 $bookmark->renameTag($args['tagName'], $data['name']);
132 $this->bookmarkService->set($bookmark, false); 132 $this->bookmarkService->set($bookmark, false);
133 $this->history->updateLink($bookmark); 133 $this->history->updateLink($bookmark);
@@ -157,12 +157,12 @@ class Tags extends ApiController
157 throw new ApiTagNotFoundException(); 157 throw new ApiTagNotFoundException();
158 } 158 }
159 159
160 $bookmarks = $this->bookmarkService->search( 160 $searchResult = $this->bookmarkService->search(
161 ['searchtags' => $args['tagName']], 161 ['searchtags' => $args['tagName']],
162 BookmarkFilter::$ALL, 162 BookmarkFilter::$ALL,
163 true 163 true
164 ); 164 );
165 foreach ($bookmarks as $bookmark) { 165 foreach ($searchResult->getBookmarks() as $bookmark) {
166 $bookmark->deleteTag($args['tagName']); 166 $bookmark->deleteTag($args['tagName']);
167 $this->bookmarkService->set($bookmark, false); 167 $this->bookmarkService->set($bookmark, false);
168 $this->history->updateLink($bookmark); 168 $this->history->updateLink($bookmark);
diff --git a/application/bookmark/BookmarkFileService.php b/application/bookmark/BookmarkFileService.php
index 6666a251..8ea37427 100644
--- a/application/bookmark/BookmarkFileService.php
+++ b/application/bookmark/BookmarkFileService.php
@@ -55,8 +55,12 @@ class BookmarkFileService implements BookmarkServiceInterface
55 /** 55 /**
56 * @inheritDoc 56 * @inheritDoc
57 */ 57 */
58 public function __construct(ConfigManager $conf, History $history, Mutex $mutex, bool $isLoggedIn) 58 public function __construct(
59 { 59 ConfigManager $conf,
60 History $history,
61 Mutex $mutex,
62 bool $isLoggedIn
63 ) {
60 $this->conf = $conf; 64 $this->conf = $conf;
61 $this->history = $history; 65 $this->history = $history;
62 $this->mutex = $mutex; 66 $this->mutex = $mutex;
@@ -129,8 +133,9 @@ class BookmarkFileService implements BookmarkServiceInterface
129 string $visibility = null, 133 string $visibility = null,
130 bool $caseSensitive = false, 134 bool $caseSensitive = false,
131 bool $untaggedOnly = false, 135 bool $untaggedOnly = false,
132 bool $ignoreSticky = false 136 bool $ignoreSticky = false,
133 ) { 137 array $pagination = []
138 ): SearchResult {
134 if ($visibility === null) { 139 if ($visibility === null) {
135 $visibility = $this->isLoggedIn ? BookmarkFilter::$ALL : BookmarkFilter::$PUBLIC; 140 $visibility = $this->isLoggedIn ? BookmarkFilter::$ALL : BookmarkFilter::$PUBLIC;
136 } 141 }
@@ -143,13 +148,20 @@ class BookmarkFileService implements BookmarkServiceInterface
143 $this->bookmarks->reorder('DESC', true); 148 $this->bookmarks->reorder('DESC', true);
144 } 149 }
145 150
146 return $this->bookmarkFilter->filter( 151 $bookmarks = $this->bookmarkFilter->filter(
147 BookmarkFilter::$FILTER_TAG | BookmarkFilter::$FILTER_TEXT, 152 BookmarkFilter::$FILTER_TAG | BookmarkFilter::$FILTER_TEXT,
148 [$searchTags, $searchTerm], 153 [$searchTags, $searchTerm],
149 $caseSensitive, 154 $caseSensitive,
150 $visibility, 155 $visibility,
151 $untaggedOnly 156 $untaggedOnly
152 ); 157 );
158
159 return SearchResult::getSearchResult(
160 $bookmarks,
161 $pagination['offset'] ?? 0,
162 $pagination['limit'] ?? null,
163 $pagination['allowOutOfBounds'] ?? false
164 );
153 } 165 }
154 166
155 /** 167 /**
@@ -282,7 +294,7 @@ class BookmarkFileService implements BookmarkServiceInterface
282 */ 294 */
283 public function count(string $visibility = null): int 295 public function count(string $visibility = null): int
284 { 296 {
285 return count($this->search([], $visibility)); 297 return $this->search([], $visibility)->getResultCount();
286 } 298 }
287 299
288 /** 300 /**
@@ -305,10 +317,10 @@ class BookmarkFileService implements BookmarkServiceInterface
305 */ 317 */
306 public function bookmarksCountPerTag(array $filteringTags = [], string $visibility = null): array 318 public function bookmarksCountPerTag(array $filteringTags = [], string $visibility = null): array
307 { 319 {
308 $bookmarks = $this->search(['searchtags' => $filteringTags], $visibility); 320 $searchResult = $this->search(['searchtags' => $filteringTags], $visibility);
309 $tags = []; 321 $tags = [];
310 $caseMapping = []; 322 $caseMapping = [];
311 foreach ($bookmarks as $bookmark) { 323 foreach ($searchResult->getBookmarks() as $bookmark) {
312 foreach ($bookmark->getTags() as $tag) { 324 foreach ($bookmark->getTags() as $tag) {
313 if ( 325 if (
314 empty($tag) 326 empty($tag)
@@ -357,7 +369,7 @@ class BookmarkFileService implements BookmarkServiceInterface
357 $previous = null; 369 $previous = null;
358 $next = null; 370 $next = null;
359 371
360 foreach ($this->search([], null, false, false, true) as $bookmark) { 372 foreach ($this->search([], null, false, false, true)->getBookmarks() as $bookmark) {
361 if ($to < $bookmark->getCreated()) { 373 if ($to < $bookmark->getCreated()) {
362 $next = $bookmark->getCreated(); 374 $next = $bookmark->getCreated();
363 } elseif ($from < $bookmark->getCreated() && $to > $bookmark->getCreated()) { 375 } elseif ($from < $bookmark->getCreated() && $to > $bookmark->getCreated()) {
@@ -378,7 +390,7 @@ class BookmarkFileService implements BookmarkServiceInterface
378 */ 390 */
379 public function getLatest(): ?Bookmark 391 public function getLatest(): ?Bookmark
380 { 392 {
381 foreach ($this->search([], null, false, false, true) as $bookmark) { 393 foreach ($this->search([], null, false, false, true)->getBookmarks() as $bookmark) {
382 return $bookmark; 394 return $bookmark;
383 } 395 }
384 396
diff --git a/application/bookmark/BookmarkServiceInterface.php b/application/bookmark/BookmarkServiceInterface.php
index 08cdbb4e..4b1f0daa 100644
--- a/application/bookmark/BookmarkServiceInterface.php
+++ b/application/bookmark/BookmarkServiceInterface.php
@@ -44,16 +44,18 @@ interface BookmarkServiceInterface
44 * @param bool $caseSensitive 44 * @param bool $caseSensitive
45 * @param bool $untaggedOnly 45 * @param bool $untaggedOnly
46 * @param bool $ignoreSticky 46 * @param bool $ignoreSticky
47 * @param array $pagination This array can contain the following keys for pagination: limit, offset.
47 * 48 *
48 * @return Bookmark[] 49 * @return SearchResult
49 */ 50 */
50 public function search( 51 public function search(
51 array $request = [], 52 array $request = [],
52 string $visibility = null, 53 string $visibility = null,
53 bool $caseSensitive = false, 54 bool $caseSensitive = false,
54 bool $untaggedOnly = false, 55 bool $untaggedOnly = false,
55 bool $ignoreSticky = false 56 bool $ignoreSticky = false,
56 ); 57 array $pagination = []
58 ): SearchResult;
57 59
58 /** 60 /**
59 * Get a single bookmark by its ID. 61 * Get a single bookmark by its ID.
diff --git a/application/bookmark/SearchResult.php b/application/bookmark/SearchResult.php
new file mode 100644
index 00000000..c0bce311
--- /dev/null
+++ b/application/bookmark/SearchResult.php
@@ -0,0 +1,136 @@
1<?php
2
3declare(strict_types=1);
4
5namespace Shaarli\Bookmark;
6
7/**
8 * Read-only class used to represent search result, including pagination.
9 */
10class SearchResult
11{
12 /** @var Bookmark[] List of result bookmarks with pagination applied */
13 protected $bookmarks;
14
15 /** @var int number of Bookmarks found, with pagination applied */
16 protected $resultCount;
17
18 /** @var int total number of result found */
19 protected $totalCount;
20
21 /** @var int pagination: limit number of result bookmarks */
22 protected $limit;
23
24 /** @var int pagination: offset to apply to complete result list */
25 protected $offset;
26
27 public function __construct(array $bookmarks, int $totalCount, int $offset, ?int $limit)
28 {
29 $this->bookmarks = $bookmarks;
30 $this->resultCount = count($bookmarks);
31 $this->totalCount = $totalCount;
32 $this->limit = $limit;
33 $this->offset = $offset;
34 }
35
36 /**
37 * Build a SearchResult from provided full result set and pagination settings.
38 *
39 * @param Bookmark[] $bookmarks Full set of result which will be filtered
40 * @param int $offset Start recording results from $offset
41 * @param int|null $limit End recording results after $limit bookmarks is reached
42 * @param bool $allowOutOfBounds Set to false to display the last page if the offset is out of bound,
43 * return empty result set otherwise (default: false)
44 *
45 * @return SearchResult
46 */
47 public static function getSearchResult(
48 $bookmarks,
49 int $offset = 0,
50 ?int $limit = null,
51 bool $allowOutOfBounds = false
52 ): self {
53 $totalCount = count($bookmarks);
54 if (!$allowOutOfBounds && $offset > $totalCount) {
55 $offset = $limit === null ? 0 : $limit * -1;
56 }
57
58 if ($bookmarks instanceof BookmarkArray) {
59 $buffer = [];
60 foreach ($bookmarks as $key => $value) {
61 $buffer[$key] = $value;
62 }
63 $bookmarks = $buffer;
64 }
65
66 return new static(
67 array_slice($bookmarks, $offset, $limit, true),
68 $totalCount,
69 $offset,
70 $limit
71 );
72 }
73
74 /** @return Bookmark[] List of result bookmarks with pagination applied */
75 public function getBookmarks(): array
76 {
77 return $this->bookmarks;
78 }
79
80 /** @return int number of Bookmarks found, with pagination applied */
81 public function getResultCount(): int
82 {
83 return $this->resultCount;
84 }
85
86 /** @return int total number of result found */
87 public function getTotalCount(): int
88 {
89 return $this->totalCount;
90 }
91
92 /** @return int pagination: limit number of result bookmarks */
93 public function getLimit(): ?int
94 {
95 return $this->limit;
96 }
97
98 /** @return int pagination: offset to apply to complete result list */
99 public function getOffset(): int
100 {
101 return $this->offset;
102 }
103
104 /** @return int Current page of result set in complete results */
105 public function getPage(): int
106 {
107 if (empty($this->limit)) {
108 return $this->offset === 0 ? 1 : 2;
109 }
110 $base = $this->offset >= 0 ? $this->offset : $this->totalCount + $this->offset;
111
112 return (int) ceil($base / $this->limit) + 1;
113 }
114
115 /** @return int Get the # of the last page */
116 public function getLastPage(): int
117 {
118 if (empty($this->limit)) {
119 return $this->offset === 0 ? 1 : 2;
120 }
121
122 return (int) ceil($this->totalCount / $this->limit);
123 }
124
125 /** @return bool Either the current page is the last one or not */
126 public function isLastPage(): bool
127 {
128 return $this->getPage() === $this->getLastPage();
129 }
130
131 /** @return bool Either the current page is the first one or not */
132 public function isFirstPage(): bool
133 {
134 return $this->offset === 0;
135 }
136}
diff --git a/application/feed/FeedBuilder.php b/application/feed/FeedBuilder.php
index ed62af26..d5d74fd1 100644
--- a/application/feed/FeedBuilder.php
+++ b/application/feed/FeedBuilder.php
@@ -102,22 +102,16 @@ class FeedBuilder
102 $userInput['searchtags'] = false; 102 $userInput['searchtags'] = false;
103 } 103 }
104 104
105 // Optionally filter the results: 105 $limit = $this->getLimit($userInput);
106 $linksToDisplay = $this->linkDB->search($userInput ?? [], null, false, false, true);
107
108 $nblinksToDisplay = $this->getNbLinks(count($linksToDisplay), $userInput);
109 106
110 // Can't use array_keys() because $link is a LinkDB instance and not a real array. 107 // Optionally filter the results:
111 $keys = []; 108 $searchResult = $this->linkDB->search($userInput ?? [], null, false, false, true, ['limit' => $limit]);
112 foreach ($linksToDisplay as $key => $value) {
113 $keys[] = $key;
114 }
115 109
116 $pageaddr = escape(index_url($this->serverInfo)); 110 $pageaddr = escape(index_url($this->serverInfo));
117 $this->formatter->addContextData('index_url', $pageaddr); 111 $this->formatter->addContextData('index_url', $pageaddr);
118 $linkDisplayed = []; 112 $links = [];
119 for ($i = 0; $i < $nblinksToDisplay && $i < count($keys); $i++) { 113 foreach ($searchResult->getBookmarks() as $key => $bookmark) {
120 $linkDisplayed[$keys[$i]] = $this->buildItem($feedType, $linksToDisplay[$keys[$i]], $pageaddr); 114 $links[$key] = $this->buildItem($feedType, $bookmark, $pageaddr);
121 } 115 }
122 116
123 $data['language'] = $this->getTypeLanguage($feedType); 117 $data['language'] = $this->getTypeLanguage($feedType);
@@ -128,7 +122,7 @@ class FeedBuilder
128 $data['self_link'] = $pageaddr . $requestUri; 122 $data['self_link'] = $pageaddr . $requestUri;
129 $data['index_url'] = $pageaddr; 123 $data['index_url'] = $pageaddr;
130 $data['usepermalinks'] = $this->usePermalinks === true; 124 $data['usepermalinks'] = $this->usePermalinks === true;
131 $data['links'] = $linkDisplayed; 125 $data['links'] = $links;
132 126
133 return $data; 127 return $data;
134 } 128 }
@@ -268,19 +262,18 @@ class FeedBuilder
268 * If 'nb' not set or invalid, default value: $DEFAULT_NB_LINKS. 262 * If 'nb' not set or invalid, default value: $DEFAULT_NB_LINKS.
269 * If 'nb' is set to 'all', display all filtered bookmarks (max parameter). 263 * If 'nb' is set to 'all', display all filtered bookmarks (max parameter).
270 * 264 *
271 * @param int $max maximum number of bookmarks to display.
272 * @param array $userInput $_GET. 265 * @param array $userInput $_GET.
273 * 266 *
274 * @return int number of bookmarks to display. 267 * @return int number of bookmarks to display.
275 */ 268 */
276 protected function getNbLinks($max, ?array $userInput) 269 protected function getLimit(?array $userInput)
277 { 270 {
278 if (empty($userInput['nb'])) { 271 if (empty($userInput['nb'])) {
279 return self::$DEFAULT_NB_LINKS; 272 return self::$DEFAULT_NB_LINKS;
280 } 273 }
281 274
282 if ($userInput['nb'] == 'all') { 275 if ($userInput['nb'] == 'all') {
283 return $max; 276 return null;
284 } 277 }
285 278
286 $intNb = intval($userInput['nb']); 279 $intNb = intval($userInput['nb']);
diff --git a/application/front/controller/admin/ManageTagController.php b/application/front/controller/admin/ManageTagController.php
index 8675a0c5..1333cce7 100644
--- a/application/front/controller/admin/ManageTagController.php
+++ b/application/front/controller/admin/ManageTagController.php
@@ -57,9 +57,12 @@ class ManageTagController extends ShaarliAdminController
57 } 57 }
58 58
59 // TODO: move this to bookmark service 59 // TODO: move this to bookmark service
60 $count = 0; 60 $searchResult = $this->container->bookmarkService->search(
61 $bookmarks = $this->container->bookmarkService->search(['searchtags' => $fromTag], BookmarkFilter::$ALL, true); 61 ['searchtags' => $fromTag],
62 foreach ($bookmarks as $bookmark) { 62 BookmarkFilter::$ALL,
63 true
64 );
65 foreach ($searchResult->getBookmarks() as $bookmark) {
63 if (false === $isDelete) { 66 if (false === $isDelete) {
64 $bookmark->renameTag($fromTag, $toTag); 67 $bookmark->renameTag($fromTag, $toTag);
65 } else { 68 } else {
@@ -68,11 +71,11 @@ class ManageTagController extends ShaarliAdminController
68 71
69 $this->container->bookmarkService->set($bookmark, false); 72 $this->container->bookmarkService->set($bookmark, false);
70 $this->container->history->updateLink($bookmark); 73 $this->container->history->updateLink($bookmark);
71 $count++;
72 } 74 }
73 75
74 $this->container->bookmarkService->save(); 76 $this->container->bookmarkService->save();
75 77
78 $count = $searchResult->getResultCount();
76 if (true === $isDelete) { 79 if (true === $isDelete) {
77 $alert = sprintf( 80 $alert = sprintf(
78 t('The tag was removed from %d bookmark.', 'The tag was removed from %d bookmarks.', $count), 81 t('The tag was removed from %d bookmark.', 'The tag was removed from %d bookmarks.', $count),
diff --git a/application/front/controller/admin/ThumbnailsController.php b/application/front/controller/admin/ThumbnailsController.php
index 94d97d4b..5dfea096 100644
--- a/application/front/controller/admin/ThumbnailsController.php
+++ b/application/front/controller/admin/ThumbnailsController.php
@@ -22,7 +22,7 @@ class ThumbnailsController extends ShaarliAdminController
22 public function index(Request $request, Response $response): Response 22 public function index(Request $request, Response $response): Response
23 { 23 {
24 $ids = []; 24 $ids = [];
25 foreach ($this->container->bookmarkService->search() as $bookmark) { 25 foreach ($this->container->bookmarkService->search()->getBookmarks() as $bookmark) {
26 // A note or not HTTP(S) 26 // A note or not HTTP(S)
27 if ($bookmark->isNote() || !startsWith(strtolower($bookmark->getUrl()), 'http')) { 27 if ($bookmark->isNote() || !startsWith(strtolower($bookmark->getUrl()), 'http')) {
28 continue; 28 continue;
diff --git a/application/front/controller/visitor/BookmarkListController.php b/application/front/controller/visitor/BookmarkListController.php
index fe8231be..321ca813 100644
--- a/application/front/controller/visitor/BookmarkListController.php
+++ b/application/front/controller/visitor/BookmarkListController.php
@@ -36,7 +36,6 @@ class BookmarkListController extends ShaarliVisitorController
36 36
37 $searchTags = normalize_spaces($request->getParam('searchtags') ?? ''); 37 $searchTags = normalize_spaces($request->getParam('searchtags') ?? '');
38 $searchTerm = escape(normalize_spaces($request->getParam('searchterm') ?? '')); 38 $searchTerm = escape(normalize_spaces($request->getParam('searchterm') ?? ''));
39 ;
40 39
41 // Filter bookmarks according search parameters. 40 // Filter bookmarks according search parameters.
42 $visibility = $this->container->sessionManager->getSessionParameter('visibility'); 41 $visibility = $this->container->sessionManager->getSessionParameter('visibility');
@@ -44,39 +43,26 @@ class BookmarkListController extends ShaarliVisitorController
44 'searchtags' => $searchTags, 43 'searchtags' => $searchTags,
45 'searchterm' => $searchTerm, 44 'searchterm' => $searchTerm,
46 ]; 45 ];
47 $linksToDisplay = $this->container->bookmarkService->search(
48 $search,
49 $visibility,
50 false,
51 !!$this->container->sessionManager->getSessionParameter('untaggedonly')
52 ) ?? [];
53
54 // ---- Handle paging.
55 $keys = [];
56 foreach ($linksToDisplay as $key => $value) {
57 $keys[] = $key;
58 }
59
60 $linksPerPage = $this->container->sessionManager->getSessionParameter('LINKS_PER_PAGE', 20) ?: 20;
61 46
62 // Select articles according to paging. 47 // Select articles according to paging.
63 $pageCount = (int) ceil(count($keys) / $linksPerPage) ?: 1; 48 $page = (int) ($request->getParam('page') ?? 1);
64 $page = (int) $request->getParam('page') ?? 1;
65 $page = $page < 1 ? 1 : $page; 49 $page = $page < 1 ? 1 : $page;
66 $page = $page > $pageCount ? $pageCount : $page; 50 $linksPerPage = $this->container->sessionManager->getSessionParameter('LINKS_PER_PAGE', 20) ?: 20;
67 51
68 // Start index. 52 $searchResult = $this->container->bookmarkService->search(
69 $i = ($page - 1) * $linksPerPage; 53 $search,
70 $end = $i + $linksPerPage; 54 $visibility,
55 false,
56 !!$this->container->sessionManager->getSessionParameter('untaggedonly'),
57 false,
58 ['offset' => $linksPerPage * ($page - 1), 'limit' => $linksPerPage]
59 ) ?? [];
71 60
72 $linkDisp = [];
73 $save = false; 61 $save = false;
74 while ($i < $end && $i < count($keys)) { 62 $links = [];
75 $save = $this->updateThumbnail($linksToDisplay[$keys[$i]], false) || $save; 63 foreach ($searchResult->getBookmarks() as $key => $bookmark) {
76 $link = $formatter->format($linksToDisplay[$keys[$i]]); 64 $save = $this->updateThumbnail($bookmark, false) || $save;
77 65 $links[$key] = $formatter->format($bookmark);
78 $linkDisp[$keys[$i]] = $link;
79 $i++;
80 } 66 }
81 67
82 if ($save) { 68 if ($save) {
@@ -86,15 +72,10 @@ class BookmarkListController extends ShaarliVisitorController
86 // Compute paging navigation 72 // Compute paging navigation
87 $searchtagsUrl = $searchTags === '' ? '' : '&searchtags=' . urlencode($searchTags); 73 $searchtagsUrl = $searchTags === '' ? '' : '&searchtags=' . urlencode($searchTags);
88 $searchtermUrl = $searchTerm === '' ? '' : '&searchterm=' . urlencode($searchTerm); 74 $searchtermUrl = $searchTerm === '' ? '' : '&searchterm=' . urlencode($searchTerm);
75 $page = $searchResult->getPage();
89 76
90 $previous_page_url = ''; 77 $previousPageUrl = !$searchResult->isLastPage() ? '?page=' . ($page + 1) . $searchtermUrl . $searchtagsUrl : '';
91 if ($i !== count($keys)) { 78 $nextPageUrl = !$searchResult->isFirstPage() ? '?page=' . ($page - 1) . $searchtermUrl . $searchtagsUrl : '';
92 $previous_page_url = '?page=' . ($page + 1) . $searchtermUrl . $searchtagsUrl;
93 }
94 $next_page_url = '';
95 if ($page > 1) {
96 $next_page_url = '?page=' . ($page - 1) . $searchtermUrl . $searchtagsUrl;
97 }
98 79
99 $tagsSeparator = $this->container->conf->get('general.tags_separator', ' '); 80 $tagsSeparator = $this->container->conf->get('general.tags_separator', ' ');
100 $searchTagsUrlEncoded = array_map('urlencode', tags_str2array($searchTags, $tagsSeparator)); 81 $searchTagsUrlEncoded = array_map('urlencode', tags_str2array($searchTags, $tagsSeparator));
@@ -104,16 +85,16 @@ class BookmarkListController extends ShaarliVisitorController
104 $data = array_merge( 85 $data = array_merge(
105 $this->initializeTemplateVars(), 86 $this->initializeTemplateVars(),
106 [ 87 [
107 'previous_page_url' => $previous_page_url, 88 'previous_page_url' => $previousPageUrl,
108 'next_page_url' => $next_page_url, 89 'next_page_url' => $nextPageUrl,
109 'page_current' => $page, 90 'page_current' => $page,
110 'page_max' => $pageCount, 91 'page_max' => $searchResult->getLastPage(),
111 'result_count' => count($linksToDisplay), 92 'result_count' => $searchResult->getTotalCount(),
112 'search_term' => escape($searchTerm), 93 'search_term' => escape($searchTerm),
113 'search_tags' => escape($searchTags), 94 'search_tags' => escape($searchTags),
114 'search_tags_url' => $searchTagsUrlEncoded, 95 'search_tags_url' => $searchTagsUrlEncoded,
115 'visibility' => $visibility, 96 'visibility' => $visibility,
116 'links' => $linkDisp, 97 'links' => $links,
117 ] 98 ]
118 ); 99 );
119 100
diff --git a/application/front/controller/visitor/DailyController.php b/application/front/controller/visitor/DailyController.php
index 29492a5f..3739ec16 100644
--- a/application/front/controller/visitor/DailyController.php
+++ b/application/front/controller/visitor/DailyController.php
@@ -100,7 +100,7 @@ class DailyController extends ShaarliVisitorController
100 $days = []; 100 $days = [];
101 $format = DailyPageHelper::getFormatByType($type); 101 $format = DailyPageHelper::getFormatByType($type);
102 $length = DailyPageHelper::getRssLengthByType($type); 102 $length = DailyPageHelper::getRssLengthByType($type);
103 foreach ($this->container->bookmarkService->search() as $bookmark) { 103 foreach ($this->container->bookmarkService->search()->getBookmarks() as $bookmark) {
104 $day = $bookmark->getCreated()->format($format); 104 $day = $bookmark->getCreated()->format($format);
105 105
106 // Stop iterating after DAILY_RSS_NB_DAYS entries 106 // Stop iterating after DAILY_RSS_NB_DAYS entries
diff --git a/application/front/controller/visitor/PictureWallController.php b/application/front/controller/visitor/PictureWallController.php
index 23553ee6..9c8f07d7 100644
--- a/application/front/controller/visitor/PictureWallController.php
+++ b/application/front/controller/visitor/PictureWallController.php
@@ -30,19 +30,19 @@ class PictureWallController extends ShaarliVisitorController
30 ); 30 );
31 31
32 // Optionally filter the results: 32 // Optionally filter the results:
33 $links = $this->container->bookmarkService->search($request->getQueryParams()); 33 $bookmarks = $this->container->bookmarkService->search($request->getQueryParams())->getBookmarks();
34 $linksToDisplay = []; 34 $links = [];
35 35
36 // Get only bookmarks which have a thumbnail. 36 // Get only bookmarks which have a thumbnail.
37 // Note: we do not retrieve thumbnails here, the request is too heavy. 37 // Note: we do not retrieve thumbnails here, the request is too heavy.
38 $formatter = $this->container->formatterFactory->getFormatter('raw'); 38 $formatter = $this->container->formatterFactory->getFormatter('raw');
39 foreach ($links as $key => $link) { 39 foreach ($bookmarks as $key => $bookmark) {
40 if (!empty($link->getThumbnail())) { 40 if (!empty($bookmark->getThumbnail())) {
41 $linksToDisplay[] = $formatter->format($link); 41 $links[] = $formatter->format($bookmark);
42 } 42 }
43 } 43 }
44 44
45 $data = ['linksToDisplay' => $linksToDisplay]; 45 $data = ['linksToDisplay' => $links];
46 $this->executePageHooks('render_picwall', $data, TemplatePage::PICTURE_WALL); 46 $this->executePageHooks('render_picwall', $data, TemplatePage::PICTURE_WALL);
47 47
48 foreach ($data as $key => $value) { 48 foreach ($data as $key => $value) {
diff --git a/application/netscape/NetscapeBookmarkUtils.php b/application/netscape/NetscapeBookmarkUtils.php
index 2d97b4c8..20715bd0 100644
--- a/application/netscape/NetscapeBookmarkUtils.php
+++ b/application/netscape/NetscapeBookmarkUtils.php
@@ -64,7 +64,7 @@ class NetscapeBookmarkUtils
64 } 64 }
65 65
66 $bookmarkLinks = []; 66 $bookmarkLinks = [];
67 foreach ($this->bookmarkService->search([], $selection) as $bookmark) { 67 foreach ($this->bookmarkService->search([], $selection)->getBookmarks() as $bookmark) {
68 $link = $formatter->format($bookmark); 68 $link = $formatter->format($bookmark);
69 $link['taglist'] = implode(',', $bookmark->getTags()); 69 $link['taglist'] = implode(',', $bookmark->getTags());
70 if ($bookmark->isNote() && $prependNoteUrl) { 70 if ($bookmark->isNote() && $prependNoteUrl) {
diff --git a/application/updater/Updater.php b/application/updater/Updater.php
index 4f557d0f..11b6c051 100644
--- a/application/updater/Updater.php
+++ b/application/updater/Updater.php
@@ -152,7 +152,7 @@ class Updater
152 { 152 {
153 $updated = false; 153 $updated = false;
154 154
155 foreach ($this->bookmarkService->search() as $bookmark) { 155 foreach ($this->bookmarkService->search()->getBookmarks() as $bookmark) {
156 if ( 156 if (
157 $bookmark->isNote() 157 $bookmark->isNote()
158 && startsWith($bookmark->getUrl(), '?') 158 && startsWith($bookmark->getUrl(), '?')