aboutsummaryrefslogtreecommitdiffhomepage
path: root/application/bookmark
diff options
context:
space:
mode:
authorArthurHoaro <arthur@hoa.ro>2021-02-04 10:57:44 +0100
committerGitHub <noreply@github.com>2021-02-04 10:57:44 +0100
commit8997ae6c8e24286f7d47981eaf905e80d2481c10 (patch)
tree9906b122998ca4420af68b1bb110033b99f7d8bf /application/bookmark
parent11edc143b42a7be09c0c9dc02730c83e8cbb73c2 (diff)
parent9b8c0a4560fa1d87cab1529099b1b4677e92e265 (diff)
downloadShaarli-8997ae6c8e24286f7d47981eaf905e80d2481c10.tar.gz
Shaarli-8997ae6c8e24286f7d47981eaf905e80d2481c10.tar.zst
Shaarli-8997ae6c8e24286f7d47981eaf905e80d2481c10.zip
Merge pull request #1697 from ArthurHoaro/feature/pagination
Handle pagination through BookmarkService
Diffstat (limited to 'application/bookmark')
-rw-r--r--application/bookmark/BookmarkFileService.php32
-rw-r--r--application/bookmark/BookmarkServiceInterface.php8
-rw-r--r--application/bookmark/SearchResult.php136
3 files changed, 163 insertions, 13 deletions
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}