diff options
Diffstat (limited to 'application/bookmark')
-rw-r--r-- | application/bookmark/BookmarkFileService.php | 32 | ||||
-rw-r--r-- | application/bookmark/BookmarkServiceInterface.php | 8 | ||||
-rw-r--r-- | application/bookmark/SearchResult.php | 136 |
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 | |||
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 | } | ||