diff options
author | ArthurHoaro <arthur@hoa.ro> | 2021-01-20 14:45:59 +0100 |
---|---|---|
committer | ArthurHoaro <arthur@hoa.ro> | 2021-01-20 15:01:29 +0100 |
commit | 9b8c0a4560fa1d87cab1529099b1b4677e92e265 (patch) | |
tree | 330a9b1a42ff7b7f24a76612b57fae63417ef483 /application | |
parent | 055d97f9a9e67d8ee8ae81bbf59a4b846a145d9f (diff) | |
download | Shaarli-9b8c0a4560fa1d87cab1529099b1b4677e92e265.tar.gz Shaarli-9b8c0a4560fa1d87cab1529099b1b4677e92e265.tar.zst Shaarli-9b8c0a4560fa1d87cab1529099b1b4677e92e265.zip |
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
Diffstat (limited to 'application')
-rw-r--r-- | application/api/controllers/Links.php | 38 | ||||
-rw-r--r-- | application/api/controllers/Tags.php | 8 | ||||
-rw-r--r-- | application/bookmark/BookmarkFileService.php | 32 | ||||
-rw-r--r-- | application/bookmark/BookmarkServiceInterface.php | 8 | ||||
-rw-r--r-- | application/bookmark/SearchResult.php | 136 | ||||
-rw-r--r-- | application/feed/FeedBuilder.php | 25 | ||||
-rw-r--r-- | application/front/controller/admin/ManageTagController.php | 11 | ||||
-rw-r--r-- | application/front/controller/admin/ThumbnailsController.php | 2 | ||||
-rw-r--r-- | application/front/controller/visitor/BookmarkListController.php | 63 | ||||
-rw-r--r-- | application/front/controller/visitor/DailyController.php | 2 | ||||
-rw-r--r-- | application/front/controller/visitor/PictureWallController.php | 12 | ||||
-rw-r--r-- | application/netscape/NetscapeBookmarkUtils.php | 2 | ||||
-rw-r--r-- | application/updater/Updater.php | 2 |
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 | |||
3 | declare(strict_types=1); | ||
4 | |||
5 | namespace Shaarli\Bookmark; | ||
6 | |||
7 | /** | ||
8 | * Read-only class used to represent search result, including pagination. | ||
9 | */ | ||
10 | class 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(), '?') |