diff options
author | ArthurHoaro <arthur@hoa.ro> | 2020-10-02 17:50:59 +0200 |
---|---|---|
committer | ArthurHoaro <arthur@hoa.ro> | 2020-10-13 13:50:11 +0200 |
commit | efb7d21b52eb033530e80e5e49d175e6e3b031f4 (patch) | |
tree | 4f34052788a08be1a30cb88c3339ae14e0b7c4da /application | |
parent | 29c31b7ec6ca48ba37b7eb6da650931fd0cb7164 (diff) | |
download | Shaarli-efb7d21b52eb033530e80e5e49d175e6e3b031f4.tar.gz Shaarli-efb7d21b52eb033530e80e5e49d175e6e3b031f4.tar.zst Shaarli-efb7d21b52eb033530e80e5e49d175e6e3b031f4.zip |
Add strict types for bookmarks management
Parameters typing and using strict types overall increase the codebase
quality by enforcing the a given parameter will have the expected type.
It also removes the need to unnecessary unit tests checking methods
behavior with invalid input.
Diffstat (limited to 'application')
-rw-r--r-- | application/api/ApiUtils.php | 6 | ||||
-rw-r--r-- | application/api/controllers/Links.php | 19 | ||||
-rw-r--r-- | application/bookmark/Bookmark.php | 121 | ||||
-rw-r--r-- | application/bookmark/BookmarkArray.php | 14 | ||||
-rw-r--r-- | application/bookmark/BookmarkFileService.php | 66 | ||||
-rw-r--r-- | application/bookmark/BookmarkFilter.php | 47 | ||||
-rw-r--r-- | application/bookmark/BookmarkIO.php | 6 | ||||
-rw-r--r-- | application/bookmark/BookmarkInitializer.php | 6 | ||||
-rw-r--r-- | application/bookmark/BookmarkServiceInterface.php | 72 | ||||
-rw-r--r-- | application/feed/FeedBuilder.php | 2 | ||||
-rw-r--r-- | application/front/controller/admin/ThumbnailsController.php | 2 | ||||
-rw-r--r-- | application/security/LoginManager.php | 2 |
12 files changed, 187 insertions, 176 deletions
diff --git a/application/api/ApiUtils.php b/application/api/ApiUtils.php index 4a6326f0..eb1ca9bc 100644 --- a/application/api/ApiUtils.php +++ b/application/api/ApiUtils.php | |||
@@ -89,12 +89,12 @@ class ApiUtils | |||
89 | * If no URL is provided, it will generate a local note URL. | 89 | * If no URL is provided, it will generate a local note URL. |
90 | * If no title is provided, it will use the URL as title. | 90 | * If no title is provided, it will use the URL as title. |
91 | * | 91 | * |
92 | * @param array $input Request Link. | 92 | * @param array|null $input Request Link. |
93 | * @param bool $defaultPrivate Request Link. | 93 | * @param bool $defaultPrivate Setting defined if a bookmark is private by default. |
94 | * | 94 | * |
95 | * @return Bookmark instance. | 95 | * @return Bookmark instance. |
96 | */ | 96 | */ |
97 | public static function buildBookmarkFromRequest($input, $defaultPrivate): Bookmark | 97 | public static function buildBookmarkFromRequest(?array $input, bool $defaultPrivate): Bookmark |
98 | { | 98 | { |
99 | $bookmark = new Bookmark(); | 99 | $bookmark = new Bookmark(); |
100 | $url = ! empty($input['url']) ? cleanup_url($input['url']) : ''; | 100 | $url = ! empty($input['url']) ? cleanup_url($input['url']) : ''; |
diff --git a/application/api/controllers/Links.php b/application/api/controllers/Links.php index 778097fd..73a1b84e 100644 --- a/application/api/controllers/Links.php +++ b/application/api/controllers/Links.php | |||
@@ -96,11 +96,12 @@ class Links extends ApiController | |||
96 | */ | 96 | */ |
97 | public function getLink($request, $response, $args) | 97 | public function getLink($request, $response, $args) |
98 | { | 98 | { |
99 | if (!$this->bookmarkService->exists($args['id'])) { | 99 | $id = is_integer_mixed($args['id']) ? (int) $args['id'] : null; |
100 | if ($id === null || ! $this->bookmarkService->exists($id)) { | ||
100 | throw new ApiLinkNotFoundException(); | 101 | throw new ApiLinkNotFoundException(); |
101 | } | 102 | } |
102 | $index = index_url($this->ci['environment']); | 103 | $index = index_url($this->ci['environment']); |
103 | $out = ApiUtils::formatLink($this->bookmarkService->get($args['id']), $index); | 104 | $out = ApiUtils::formatLink($this->bookmarkService->get($id), $index); |
104 | 105 | ||
105 | return $response->withJson($out, 200, $this->jsonStyle); | 106 | return $response->withJson($out, 200, $this->jsonStyle); |
106 | } | 107 | } |
@@ -115,7 +116,7 @@ class Links extends ApiController | |||
115 | */ | 116 | */ |
116 | public function postLink($request, $response) | 117 | public function postLink($request, $response) |
117 | { | 118 | { |
118 | $data = $request->getParsedBody(); | 119 | $data = (array) ($request->getParsedBody() ?? []); |
119 | $bookmark = ApiUtils::buildBookmarkFromRequest($data, $this->conf->get('privacy.default_private_links')); | 120 | $bookmark = ApiUtils::buildBookmarkFromRequest($data, $this->conf->get('privacy.default_private_links')); |
120 | // duplicate by URL, return 409 Conflict | 121 | // duplicate by URL, return 409 Conflict |
121 | if (! empty($bookmark->getUrl()) | 122 | if (! empty($bookmark->getUrl()) |
@@ -148,7 +149,8 @@ class Links extends ApiController | |||
148 | */ | 149 | */ |
149 | public function putLink($request, $response, $args) | 150 | public function putLink($request, $response, $args) |
150 | { | 151 | { |
151 | if (! $this->bookmarkService->exists($args['id'])) { | 152 | $id = is_integer_mixed($args['id']) ? (int) $args['id'] : null; |
153 | if ($id === null || !$this->bookmarkService->exists($id)) { | ||
152 | throw new ApiLinkNotFoundException(); | 154 | throw new ApiLinkNotFoundException(); |
153 | } | 155 | } |
154 | 156 | ||
@@ -159,7 +161,7 @@ class Links extends ApiController | |||
159 | // duplicate URL on a different link, return 409 Conflict | 161 | // duplicate URL on a different link, return 409 Conflict |
160 | if (! empty($requestBookmark->getUrl()) | 162 | if (! empty($requestBookmark->getUrl()) |
161 | && ! empty($dup = $this->bookmarkService->findByUrl($requestBookmark->getUrl())) | 163 | && ! empty($dup = $this->bookmarkService->findByUrl($requestBookmark->getUrl())) |
162 | && $dup->getId() != $args['id'] | 164 | && $dup->getId() != $id |
163 | ) { | 165 | ) { |
164 | return $response->withJson( | 166 | return $response->withJson( |
165 | ApiUtils::formatLink($dup, $index), | 167 | ApiUtils::formatLink($dup, $index), |
@@ -168,7 +170,7 @@ class Links extends ApiController | |||
168 | ); | 170 | ); |
169 | } | 171 | } |
170 | 172 | ||
171 | $responseBookmark = $this->bookmarkService->get($args['id']); | 173 | $responseBookmark = $this->bookmarkService->get($id); |
172 | $responseBookmark = ApiUtils::updateLink($responseBookmark, $requestBookmark); | 174 | $responseBookmark = ApiUtils::updateLink($responseBookmark, $requestBookmark); |
173 | $this->bookmarkService->set($responseBookmark); | 175 | $this->bookmarkService->set($responseBookmark); |
174 | 176 | ||
@@ -189,10 +191,11 @@ class Links extends ApiController | |||
189 | */ | 191 | */ |
190 | public function deleteLink($request, $response, $args) | 192 | public function deleteLink($request, $response, $args) |
191 | { | 193 | { |
192 | if (! $this->bookmarkService->exists($args['id'])) { | 194 | $id = is_integer_mixed($args['id']) ? (int) $args['id'] : null; |
195 | if ($id === null || !$this->bookmarkService->exists($id)) { | ||
193 | throw new ApiLinkNotFoundException(); | 196 | throw new ApiLinkNotFoundException(); |
194 | } | 197 | } |
195 | $bookmark = $this->bookmarkService->get($args['id']); | 198 | $bookmark = $this->bookmarkService->get($id); |
196 | $this->bookmarkService->remove($bookmark); | 199 | $this->bookmarkService->remove($bookmark); |
197 | 200 | ||
198 | return $response->withStatus(204); | 201 | return $response->withStatus(204); |
diff --git a/application/bookmark/Bookmark.php b/application/bookmark/Bookmark.php index 1beb8be2..fa45d2fc 100644 --- a/application/bookmark/Bookmark.php +++ b/application/bookmark/Bookmark.php | |||
@@ -1,5 +1,7 @@ | |||
1 | <?php | 1 | <?php |
2 | 2 | ||
3 | declare(strict_types=1); | ||
4 | |||
3 | namespace Shaarli\Bookmark; | 5 | namespace Shaarli\Bookmark; |
4 | 6 | ||
5 | use DateTime; | 7 | use DateTime; |
@@ -59,25 +61,25 @@ class Bookmark | |||
59 | * | 61 | * |
60 | * @return $this | 62 | * @return $this |
61 | */ | 63 | */ |
62 | public function fromArray($data) | 64 | public function fromArray(array $data): Bookmark |
63 | { | 65 | { |
64 | $this->id = $data['id']; | 66 | $this->id = $data['id'] ?? null; |
65 | $this->shortUrl = $data['shorturl']; | 67 | $this->shortUrl = $data['shorturl'] ?? null; |
66 | $this->url = $data['url']; | 68 | $this->url = $data['url'] ?? null; |
67 | $this->title = $data['title']; | 69 | $this->title = $data['title'] ?? null; |
68 | $this->description = $data['description']; | 70 | $this->description = $data['description'] ?? null; |
69 | $this->thumbnail = isset($data['thumbnail']) ? $data['thumbnail'] : null; | 71 | $this->thumbnail = $data['thumbnail'] ?? null; |
70 | $this->sticky = isset($data['sticky']) ? $data['sticky'] : false; | 72 | $this->sticky = $data['sticky'] ?? false; |
71 | $this->created = $data['created']; | 73 | $this->created = $data['created'] ?? null; |
72 | if (is_array($data['tags'])) { | 74 | if (is_array($data['tags'])) { |
73 | $this->tags = $data['tags']; | 75 | $this->tags = $data['tags']; |
74 | } else { | 76 | } else { |
75 | $this->tags = preg_split('/\s+/', $data['tags'], -1, PREG_SPLIT_NO_EMPTY); | 77 | $this->tags = preg_split('/\s+/', $data['tags'] ?? '', -1, PREG_SPLIT_NO_EMPTY); |
76 | } | 78 | } |
77 | if (! empty($data['updated'])) { | 79 | if (! empty($data['updated'])) { |
78 | $this->updated = $data['updated']; | 80 | $this->updated = $data['updated']; |
79 | } | 81 | } |
80 | $this->private = $data['private'] ? true : false; | 82 | $this->private = ($data['private'] ?? false) ? true : false; |
81 | 83 | ||
82 | return $this; | 84 | return $this; |
83 | } | 85 | } |
@@ -95,13 +97,12 @@ class Bookmark | |||
95 | * | 97 | * |
96 | * @throws InvalidBookmarkException | 98 | * @throws InvalidBookmarkException |
97 | */ | 99 | */ |
98 | public function validate() | 100 | public function validate(): void |
99 | { | 101 | { |
100 | if ($this->id === null | 102 | if ($this->id === null |
101 | || ! is_int($this->id) | 103 | || ! is_int($this->id) |
102 | || empty($this->shortUrl) | 104 | || empty($this->shortUrl) |
103 | || empty($this->created) | 105 | || empty($this->created) |
104 | || ! $this->created instanceof DateTimeInterface | ||
105 | ) { | 106 | ) { |
106 | throw new InvalidBookmarkException($this); | 107 | throw new InvalidBookmarkException($this); |
107 | } | 108 | } |
@@ -119,11 +120,11 @@ class Bookmark | |||
119 | * - created: with the current datetime | 120 | * - created: with the current datetime |
120 | * - shortUrl: with a generated small hash from the date and the given ID | 121 | * - shortUrl: with a generated small hash from the date and the given ID |
121 | * | 122 | * |
122 | * @param int $id | 123 | * @param int|null $id |
123 | * | 124 | * |
124 | * @return Bookmark | 125 | * @return Bookmark |
125 | */ | 126 | */ |
126 | public function setId($id) | 127 | public function setId(?int $id): Bookmark |
127 | { | 128 | { |
128 | $this->id = $id; | 129 | $this->id = $id; |
129 | if (empty($this->created)) { | 130 | if (empty($this->created)) { |
@@ -139,9 +140,9 @@ class Bookmark | |||
139 | /** | 140 | /** |
140 | * Get the Id. | 141 | * Get the Id. |
141 | * | 142 | * |
142 | * @return int | 143 | * @return int|null |
143 | */ | 144 | */ |
144 | public function getId() | 145 | public function getId(): ?int |
145 | { | 146 | { |
146 | return $this->id; | 147 | return $this->id; |
147 | } | 148 | } |
@@ -149,9 +150,9 @@ class Bookmark | |||
149 | /** | 150 | /** |
150 | * Get the ShortUrl. | 151 | * Get the ShortUrl. |
151 | * | 152 | * |
152 | * @return string | 153 | * @return string|null |
153 | */ | 154 | */ |
154 | public function getShortUrl() | 155 | public function getShortUrl(): ?string |
155 | { | 156 | { |
156 | return $this->shortUrl; | 157 | return $this->shortUrl; |
157 | } | 158 | } |
@@ -159,9 +160,9 @@ class Bookmark | |||
159 | /** | 160 | /** |
160 | * Get the Url. | 161 | * Get the Url. |
161 | * | 162 | * |
162 | * @return string | 163 | * @return string|null |
163 | */ | 164 | */ |
164 | public function getUrl() | 165 | public function getUrl(): ?string |
165 | { | 166 | { |
166 | return $this->url; | 167 | return $this->url; |
167 | } | 168 | } |
@@ -171,7 +172,7 @@ class Bookmark | |||
171 | * | 172 | * |
172 | * @return string | 173 | * @return string |
173 | */ | 174 | */ |
174 | public function getTitle() | 175 | public function getTitle(): ?string |
175 | { | 176 | { |
176 | return $this->title; | 177 | return $this->title; |
177 | } | 178 | } |
@@ -181,7 +182,7 @@ class Bookmark | |||
181 | * | 182 | * |
182 | * @return string | 183 | * @return string |
183 | */ | 184 | */ |
184 | public function getDescription() | 185 | public function getDescription(): string |
185 | { | 186 | { |
186 | return ! empty($this->description) ? $this->description : ''; | 187 | return ! empty($this->description) ? $this->description : ''; |
187 | } | 188 | } |
@@ -191,7 +192,7 @@ class Bookmark | |||
191 | * | 192 | * |
192 | * @return DateTimeInterface | 193 | * @return DateTimeInterface |
193 | */ | 194 | */ |
194 | public function getCreated() | 195 | public function getCreated(): ?DateTimeInterface |
195 | { | 196 | { |
196 | return $this->created; | 197 | return $this->created; |
197 | } | 198 | } |
@@ -201,7 +202,7 @@ class Bookmark | |||
201 | * | 202 | * |
202 | * @return DateTimeInterface | 203 | * @return DateTimeInterface |
203 | */ | 204 | */ |
204 | public function getUpdated() | 205 | public function getUpdated(): ?DateTimeInterface |
205 | { | 206 | { |
206 | return $this->updated; | 207 | return $this->updated; |
207 | } | 208 | } |
@@ -209,11 +210,11 @@ class Bookmark | |||
209 | /** | 210 | /** |
210 | * Set the ShortUrl. | 211 | * Set the ShortUrl. |
211 | * | 212 | * |
212 | * @param string $shortUrl | 213 | * @param string|null $shortUrl |
213 | * | 214 | * |
214 | * @return Bookmark | 215 | * @return Bookmark |
215 | */ | 216 | */ |
216 | public function setShortUrl($shortUrl) | 217 | public function setShortUrl(?string $shortUrl): Bookmark |
217 | { | 218 | { |
218 | $this->shortUrl = $shortUrl; | 219 | $this->shortUrl = $shortUrl; |
219 | 220 | ||
@@ -223,14 +224,14 @@ class Bookmark | |||
223 | /** | 224 | /** |
224 | * Set the Url. | 225 | * Set the Url. |
225 | * | 226 | * |
226 | * @param string $url | 227 | * @param string|null $url |
227 | * @param array $allowedProtocols | 228 | * @param string[] $allowedProtocols |
228 | * | 229 | * |
229 | * @return Bookmark | 230 | * @return Bookmark |
230 | */ | 231 | */ |
231 | public function setUrl($url, $allowedProtocols = []) | 232 | public function setUrl(?string $url, array $allowedProtocols = []): Bookmark |
232 | { | 233 | { |
233 | $url = trim($url); | 234 | $url = $url !== null ? trim($url) : ''; |
234 | if (! empty($url)) { | 235 | if (! empty($url)) { |
235 | $url = whitelist_protocols($url, $allowedProtocols); | 236 | $url = whitelist_protocols($url, $allowedProtocols); |
236 | } | 237 | } |
@@ -242,13 +243,13 @@ class Bookmark | |||
242 | /** | 243 | /** |
243 | * Set the Title. | 244 | * Set the Title. |
244 | * | 245 | * |
245 | * @param string $title | 246 | * @param string|null $title |
246 | * | 247 | * |
247 | * @return Bookmark | 248 | * @return Bookmark |
248 | */ | 249 | */ |
249 | public function setTitle($title) | 250 | public function setTitle(?string $title): Bookmark |
250 | { | 251 | { |
251 | $this->title = trim($title); | 252 | $this->title = $title !== null ? trim($title) : ''; |
252 | 253 | ||
253 | return $this; | 254 | return $this; |
254 | } | 255 | } |
@@ -256,11 +257,11 @@ class Bookmark | |||
256 | /** | 257 | /** |
257 | * Set the Description. | 258 | * Set the Description. |
258 | * | 259 | * |
259 | * @param string $description | 260 | * @param string|null $description |
260 | * | 261 | * |
261 | * @return Bookmark | 262 | * @return Bookmark |
262 | */ | 263 | */ |
263 | public function setDescription($description) | 264 | public function setDescription(?string $description): Bookmark |
264 | { | 265 | { |
265 | $this->description = $description; | 266 | $this->description = $description; |
266 | 267 | ||
@@ -271,11 +272,11 @@ class Bookmark | |||
271 | * Set the Created. | 272 | * Set the Created. |
272 | * Note: you shouldn't set this manually except for special cases (like bookmark import) | 273 | * Note: you shouldn't set this manually except for special cases (like bookmark import) |
273 | * | 274 | * |
274 | * @param DateTimeInterface $created | 275 | * @param DateTimeInterface|null $created |
275 | * | 276 | * |
276 | * @return Bookmark | 277 | * @return Bookmark |
277 | */ | 278 | */ |
278 | public function setCreated($created) | 279 | public function setCreated(?DateTimeInterface $created): Bookmark |
279 | { | 280 | { |
280 | $this->created = $created; | 281 | $this->created = $created; |
281 | 282 | ||
@@ -285,11 +286,11 @@ class Bookmark | |||
285 | /** | 286 | /** |
286 | * Set the Updated. | 287 | * Set the Updated. |
287 | * | 288 | * |
288 | * @param DateTimeInterface $updated | 289 | * @param DateTimeInterface|null $updated |
289 | * | 290 | * |
290 | * @return Bookmark | 291 | * @return Bookmark |
291 | */ | 292 | */ |
292 | public function setUpdated($updated) | 293 | public function setUpdated(?DateTimeInterface $updated): Bookmark |
293 | { | 294 | { |
294 | $this->updated = $updated; | 295 | $this->updated = $updated; |
295 | 296 | ||
@@ -301,7 +302,7 @@ class Bookmark | |||
301 | * | 302 | * |
302 | * @return bool | 303 | * @return bool |
303 | */ | 304 | */ |
304 | public function isPrivate() | 305 | public function isPrivate(): bool |
305 | { | 306 | { |
306 | return $this->private ? true : false; | 307 | return $this->private ? true : false; |
307 | } | 308 | } |
@@ -309,11 +310,11 @@ class Bookmark | |||
309 | /** | 310 | /** |
310 | * Set the Private. | 311 | * Set the Private. |
311 | * | 312 | * |
312 | * @param bool $private | 313 | * @param bool|null $private |
313 | * | 314 | * |
314 | * @return Bookmark | 315 | * @return Bookmark |
315 | */ | 316 | */ |
316 | public function setPrivate($private) | 317 | public function setPrivate(?bool $private): Bookmark |
317 | { | 318 | { |
318 | $this->private = $private ? true : false; | 319 | $this->private = $private ? true : false; |
319 | 320 | ||
@@ -323,9 +324,9 @@ class Bookmark | |||
323 | /** | 324 | /** |
324 | * Get the Tags. | 325 | * Get the Tags. |
325 | * | 326 | * |
326 | * @return array | 327 | * @return string[] |
327 | */ | 328 | */ |
328 | public function getTags() | 329 | public function getTags(): array |
329 | { | 330 | { |
330 | return is_array($this->tags) ? $this->tags : []; | 331 | return is_array($this->tags) ? $this->tags : []; |
331 | } | 332 | } |
@@ -333,13 +334,13 @@ class Bookmark | |||
333 | /** | 334 | /** |
334 | * Set the Tags. | 335 | * Set the Tags. |
335 | * | 336 | * |
336 | * @param array $tags | 337 | * @param string[]|null $tags |
337 | * | 338 | * |
338 | * @return Bookmark | 339 | * @return Bookmark |
339 | */ | 340 | */ |
340 | public function setTags($tags) | 341 | public function setTags(?array $tags): Bookmark |
341 | { | 342 | { |
342 | $this->setTagsString(implode(' ', $tags)); | 343 | $this->setTagsString(implode(' ', $tags ?? [])); |
343 | 344 | ||
344 | return $this; | 345 | return $this; |
345 | } | 346 | } |
@@ -357,11 +358,11 @@ class Bookmark | |||
357 | /** | 358 | /** |
358 | * Set the Thumbnail. | 359 | * Set the Thumbnail. |
359 | * | 360 | * |
360 | * @param string|bool $thumbnail Thumbnail's URL - false if no thumbnail could be found | 361 | * @param string|bool|null $thumbnail Thumbnail's URL - false if no thumbnail could be found |
361 | * | 362 | * |
362 | * @return Bookmark | 363 | * @return Bookmark |
363 | */ | 364 | */ |
364 | public function setThumbnail($thumbnail) | 365 | public function setThumbnail($thumbnail): Bookmark |
365 | { | 366 | { |
366 | $this->thumbnail = $thumbnail; | 367 | $this->thumbnail = $thumbnail; |
367 | 368 | ||
@@ -373,7 +374,7 @@ class Bookmark | |||
373 | * | 374 | * |
374 | * @return bool | 375 | * @return bool |
375 | */ | 376 | */ |
376 | public function isSticky() | 377 | public function isSticky(): bool |
377 | { | 378 | { |
378 | return $this->sticky ? true : false; | 379 | return $this->sticky ? true : false; |
379 | } | 380 | } |
@@ -381,11 +382,11 @@ class Bookmark | |||
381 | /** | 382 | /** |
382 | * Set the Sticky. | 383 | * Set the Sticky. |
383 | * | 384 | * |
384 | * @param bool $sticky | 385 | * @param bool|null $sticky |
385 | * | 386 | * |
386 | * @return Bookmark | 387 | * @return Bookmark |
387 | */ | 388 | */ |
388 | public function setSticky($sticky) | 389 | public function setSticky(?bool $sticky): Bookmark |
389 | { | 390 | { |
390 | $this->sticky = $sticky ? true : false; | 391 | $this->sticky = $sticky ? true : false; |
391 | 392 | ||
@@ -395,7 +396,7 @@ class Bookmark | |||
395 | /** | 396 | /** |
396 | * @return string Bookmark's tags as a string, separated by a space | 397 | * @return string Bookmark's tags as a string, separated by a space |
397 | */ | 398 | */ |
398 | public function getTagsString() | 399 | public function getTagsString(): string |
399 | { | 400 | { |
400 | return implode(' ', $this->getTags()); | 401 | return implode(' ', $this->getTags()); |
401 | } | 402 | } |
@@ -403,7 +404,7 @@ class Bookmark | |||
403 | /** | 404 | /** |
404 | * @return bool | 405 | * @return bool |
405 | */ | 406 | */ |
406 | public function isNote() | 407 | public function isNote(): bool |
407 | { | 408 | { |
408 | // We check empty value to get a valid result if the link has not been saved yet | 409 | // We check empty value to get a valid result if the link has not been saved yet |
409 | return empty($this->url) || startsWith($this->url, '/shaare/') || $this->url[0] === '?'; | 410 | return empty($this->url) || startsWith($this->url, '/shaare/') || $this->url[0] === '?'; |
@@ -416,14 +417,14 @@ class Bookmark | |||
416 | * - multiple spaces will be removed | 417 | * - multiple spaces will be removed |
417 | * - trailing dash in tags will be removed | 418 | * - trailing dash in tags will be removed |
418 | * | 419 | * |
419 | * @param string $tags | 420 | * @param string|null $tags |
420 | * | 421 | * |
421 | * @return $this | 422 | * @return $this |
422 | */ | 423 | */ |
423 | public function setTagsString($tags) | 424 | public function setTagsString(?string $tags): Bookmark |
424 | { | 425 | { |
425 | // Remove first '-' char in tags. | 426 | // Remove first '-' char in tags. |
426 | $tags = preg_replace('/(^| )\-/', '$1', $tags); | 427 | $tags = preg_replace('/(^| )\-/', '$1', $tags ?? ''); |
427 | // Explode all tags separted by spaces or commas | 428 | // Explode all tags separted by spaces or commas |
428 | $tags = preg_split('/[\s,]+/', $tags); | 429 | $tags = preg_split('/[\s,]+/', $tags); |
429 | // Remove eventual empty values | 430 | // Remove eventual empty values |
@@ -440,7 +441,7 @@ class Bookmark | |||
440 | * @param string $fromTag | 441 | * @param string $fromTag |
441 | * @param string $toTag | 442 | * @param string $toTag |
442 | */ | 443 | */ |
443 | public function renameTag($fromTag, $toTag) | 444 | public function renameTag(string $fromTag, string $toTag): void |
444 | { | 445 | { |
445 | if (($pos = array_search($fromTag, $this->tags)) !== false) { | 446 | if (($pos = array_search($fromTag, $this->tags)) !== false) { |
446 | $this->tags[$pos] = trim($toTag); | 447 | $this->tags[$pos] = trim($toTag); |
@@ -452,7 +453,7 @@ class Bookmark | |||
452 | * | 453 | * |
453 | * @param string $tag | 454 | * @param string $tag |
454 | */ | 455 | */ |
455 | public function deleteTag($tag) | 456 | public function deleteTag(string $tag): void |
456 | { | 457 | { |
457 | if (($pos = array_search($tag, $this->tags)) !== false) { | 458 | if (($pos = array_search($tag, $this->tags)) !== false) { |
458 | unset($this->tags[$pos]); | 459 | unset($this->tags[$pos]); |
diff --git a/application/bookmark/BookmarkArray.php b/application/bookmark/BookmarkArray.php index 3bd5eb20..67bb3b73 100644 --- a/application/bookmark/BookmarkArray.php +++ b/application/bookmark/BookmarkArray.php | |||
@@ -1,5 +1,7 @@ | |||
1 | <?php | 1 | <?php |
2 | 2 | ||
3 | declare(strict_types=1); | ||
4 | |||
3 | namespace Shaarli\Bookmark; | 5 | namespace Shaarli\Bookmark; |
4 | 6 | ||
5 | use Shaarli\Bookmark\Exception\InvalidBookmarkException; | 7 | use Shaarli\Bookmark\Exception\InvalidBookmarkException; |
@@ -187,13 +189,13 @@ class BookmarkArray implements \Iterator, \Countable, \ArrayAccess | |||
187 | /** | 189 | /** |
188 | * Returns a bookmark offset in bookmarks array from its unique ID. | 190 | * Returns a bookmark offset in bookmarks array from its unique ID. |
189 | * | 191 | * |
190 | * @param int $id Persistent ID of a bookmark. | 192 | * @param int|null $id Persistent ID of a bookmark. |
191 | * | 193 | * |
192 | * @return int Real offset in local array, or null if doesn't exist. | 194 | * @return int Real offset in local array, or null if doesn't exist. |
193 | */ | 195 | */ |
194 | protected function getBookmarkOffset($id) | 196 | protected function getBookmarkOffset(?int $id): ?int |
195 | { | 197 | { |
196 | if (isset($this->ids[$id])) { | 198 | if ($id !== null && isset($this->ids[$id])) { |
197 | return $this->ids[$id]; | 199 | return $this->ids[$id]; |
198 | } | 200 | } |
199 | return null; | 201 | return null; |
@@ -205,7 +207,7 @@ class BookmarkArray implements \Iterator, \Countable, \ArrayAccess | |||
205 | * | 207 | * |
206 | * @return int next ID. | 208 | * @return int next ID. |
207 | */ | 209 | */ |
208 | public function getNextId() | 210 | public function getNextId(): int |
209 | { | 211 | { |
210 | if (!empty($this->ids)) { | 212 | if (!empty($this->ids)) { |
211 | return max(array_keys($this->ids)) + 1; | 213 | return max(array_keys($this->ids)) + 1; |
@@ -214,11 +216,11 @@ class BookmarkArray implements \Iterator, \Countable, \ArrayAccess | |||
214 | } | 216 | } |
215 | 217 | ||
216 | /** | 218 | /** |
217 | * @param $url | 219 | * @param string $url |
218 | * | 220 | * |
219 | * @return Bookmark|null | 221 | * @return Bookmark|null |
220 | */ | 222 | */ |
221 | public function getByUrl($url) | 223 | public function getByUrl(string $url): ?Bookmark |
222 | { | 224 | { |
223 | if (! empty($url) | 225 | if (! empty($url) |
224 | && isset($this->urls[$url]) | 226 | && isset($this->urls[$url]) |
diff --git a/application/bookmark/BookmarkFileService.php b/application/bookmark/BookmarkFileService.php index 1ba00712..804b2520 100644 --- a/application/bookmark/BookmarkFileService.php +++ b/application/bookmark/BookmarkFileService.php | |||
@@ -1,9 +1,10 @@ | |||
1 | <?php | 1 | <?php |
2 | 2 | ||
3 | declare(strict_types=1); | ||
3 | 4 | ||
4 | namespace Shaarli\Bookmark; | 5 | namespace Shaarli\Bookmark; |
5 | 6 | ||
6 | 7 | use DateTime; | |
7 | use Exception; | 8 | use Exception; |
8 | use malkusch\lock\mutex\Mutex; | 9 | use malkusch\lock\mutex\Mutex; |
9 | use Shaarli\Bookmark\Exception\BookmarkNotFoundException; | 10 | use Shaarli\Bookmark\Exception\BookmarkNotFoundException; |
@@ -54,7 +55,7 @@ class BookmarkFileService implements BookmarkServiceInterface | |||
54 | /** | 55 | /** |
55 | * @inheritDoc | 56 | * @inheritDoc |
56 | */ | 57 | */ |
57 | public function __construct(ConfigManager $conf, History $history, Mutex $mutex, $isLoggedIn) | 58 | public function __construct(ConfigManager $conf, History $history, Mutex $mutex, bool $isLoggedIn) |
58 | { | 59 | { |
59 | $this->conf = $conf; | 60 | $this->conf = $conf; |
60 | $this->history = $history; | 61 | $this->history = $history; |
@@ -96,7 +97,7 @@ class BookmarkFileService implements BookmarkServiceInterface | |||
96 | /** | 97 | /** |
97 | * @inheritDoc | 98 | * @inheritDoc |
98 | */ | 99 | */ |
99 | public function findByHash($hash) | 100 | public function findByHash(string $hash): Bookmark |
100 | { | 101 | { |
101 | $bookmark = $this->bookmarkFilter->filter(BookmarkFilter::$FILTER_HASH, $hash); | 102 | $bookmark = $this->bookmarkFilter->filter(BookmarkFilter::$FILTER_HASH, $hash); |
102 | // PHP 7.3 introduced array_key_first() to avoid this hack | 103 | // PHP 7.3 introduced array_key_first() to avoid this hack |
@@ -111,7 +112,7 @@ class BookmarkFileService implements BookmarkServiceInterface | |||
111 | /** | 112 | /** |
112 | * @inheritDoc | 113 | * @inheritDoc |
113 | */ | 114 | */ |
114 | public function findByUrl($url) | 115 | public function findByUrl(string $url): ?Bookmark |
115 | { | 116 | { |
116 | return $this->bookmarks->getByUrl($url); | 117 | return $this->bookmarks->getByUrl($url); |
117 | } | 118 | } |
@@ -120,10 +121,10 @@ class BookmarkFileService implements BookmarkServiceInterface | |||
120 | * @inheritDoc | 121 | * @inheritDoc |
121 | */ | 122 | */ |
122 | public function search( | 123 | public function search( |
123 | $request = [], | 124 | array $request = [], |
124 | $visibility = null, | 125 | string $visibility = null, |
125 | $caseSensitive = false, | 126 | bool $caseSensitive = false, |
126 | $untaggedOnly = false, | 127 | bool $untaggedOnly = false, |
127 | bool $ignoreSticky = false | 128 | bool $ignoreSticky = false |
128 | ) { | 129 | ) { |
129 | if ($visibility === null) { | 130 | if ($visibility === null) { |
@@ -131,8 +132,8 @@ class BookmarkFileService implements BookmarkServiceInterface | |||
131 | } | 132 | } |
132 | 133 | ||
133 | // Filter bookmark database according to parameters. | 134 | // Filter bookmark database according to parameters. |
134 | $searchtags = isset($request['searchtags']) ? $request['searchtags'] : ''; | 135 | $searchTags = isset($request['searchtags']) ? $request['searchtags'] : ''; |
135 | $searchterm = isset($request['searchterm']) ? $request['searchterm'] : ''; | 136 | $searchTerm = isset($request['searchterm']) ? $request['searchterm'] : ''; |
136 | 137 | ||
137 | if ($ignoreSticky) { | 138 | if ($ignoreSticky) { |
138 | $this->bookmarks->reorder('DESC', true); | 139 | $this->bookmarks->reorder('DESC', true); |
@@ -140,7 +141,7 @@ class BookmarkFileService implements BookmarkServiceInterface | |||
140 | 141 | ||
141 | return $this->bookmarkFilter->filter( | 142 | return $this->bookmarkFilter->filter( |
142 | BookmarkFilter::$FILTER_TAG | BookmarkFilter::$FILTER_TEXT, | 143 | BookmarkFilter::$FILTER_TAG | BookmarkFilter::$FILTER_TEXT, |
143 | [$searchtags, $searchterm], | 144 | [$searchTags, $searchTerm], |
144 | $caseSensitive, | 145 | $caseSensitive, |
145 | $visibility, | 146 | $visibility, |
146 | $untaggedOnly | 147 | $untaggedOnly |
@@ -150,7 +151,7 @@ class BookmarkFileService implements BookmarkServiceInterface | |||
150 | /** | 151 | /** |
151 | * @inheritDoc | 152 | * @inheritDoc |
152 | */ | 153 | */ |
153 | public function get($id, $visibility = null) | 154 | public function get(int $id, string $visibility = null): Bookmark |
154 | { | 155 | { |
155 | if (! isset($this->bookmarks[$id])) { | 156 | if (! isset($this->bookmarks[$id])) { |
156 | throw new BookmarkNotFoundException(); | 157 | throw new BookmarkNotFoundException(); |
@@ -173,20 +174,17 @@ class BookmarkFileService implements BookmarkServiceInterface | |||
173 | /** | 174 | /** |
174 | * @inheritDoc | 175 | * @inheritDoc |
175 | */ | 176 | */ |
176 | public function set($bookmark, $save = true) | 177 | public function set(Bookmark $bookmark, bool $save = true): Bookmark |
177 | { | 178 | { |
178 | if (true !== $this->isLoggedIn) { | 179 | if (true !== $this->isLoggedIn) { |
179 | throw new Exception(t('You\'re not authorized to alter the datastore')); | 180 | throw new Exception(t('You\'re not authorized to alter the datastore')); |
180 | } | 181 | } |
181 | if (! $bookmark instanceof Bookmark) { | ||
182 | throw new Exception(t('Provided data is invalid')); | ||
183 | } | ||
184 | if (! isset($this->bookmarks[$bookmark->getId()])) { | 182 | if (! isset($this->bookmarks[$bookmark->getId()])) { |
185 | throw new BookmarkNotFoundException(); | 183 | throw new BookmarkNotFoundException(); |
186 | } | 184 | } |
187 | $bookmark->validate(); | 185 | $bookmark->validate(); |
188 | 186 | ||
189 | $bookmark->setUpdated(new \DateTime()); | 187 | $bookmark->setUpdated(new DateTime()); |
190 | $this->bookmarks[$bookmark->getId()] = $bookmark; | 188 | $this->bookmarks[$bookmark->getId()] = $bookmark; |
191 | if ($save === true) { | 189 | if ($save === true) { |
192 | $this->save(); | 190 | $this->save(); |
@@ -198,15 +196,12 @@ class BookmarkFileService implements BookmarkServiceInterface | |||
198 | /** | 196 | /** |
199 | * @inheritDoc | 197 | * @inheritDoc |
200 | */ | 198 | */ |
201 | public function add($bookmark, $save = true) | 199 | public function add(Bookmark $bookmark, bool $save = true): Bookmark |
202 | { | 200 | { |
203 | if (true !== $this->isLoggedIn) { | 201 | if (true !== $this->isLoggedIn) { |
204 | throw new Exception(t('You\'re not authorized to alter the datastore')); | 202 | throw new Exception(t('You\'re not authorized to alter the datastore')); |
205 | } | 203 | } |
206 | if (! $bookmark instanceof Bookmark) { | 204 | if (!empty($bookmark->getId())) { |
207 | throw new Exception(t('Provided data is invalid')); | ||
208 | } | ||
209 | if (! empty($bookmark->getId())) { | ||
210 | throw new Exception(t('This bookmarks already exists')); | 205 | throw new Exception(t('This bookmarks already exists')); |
211 | } | 206 | } |
212 | $bookmark->setId($this->bookmarks->getNextId()); | 207 | $bookmark->setId($this->bookmarks->getNextId()); |
@@ -223,14 +218,11 @@ class BookmarkFileService implements BookmarkServiceInterface | |||
223 | /** | 218 | /** |
224 | * @inheritDoc | 219 | * @inheritDoc |
225 | */ | 220 | */ |
226 | public function addOrSet($bookmark, $save = true) | 221 | public function addOrSet(Bookmark $bookmark, bool $save = true): Bookmark |
227 | { | 222 | { |
228 | if (true !== $this->isLoggedIn) { | 223 | if (true !== $this->isLoggedIn) { |
229 | throw new Exception(t('You\'re not authorized to alter the datastore')); | 224 | throw new Exception(t('You\'re not authorized to alter the datastore')); |
230 | } | 225 | } |
231 | if (! $bookmark instanceof Bookmark) { | ||
232 | throw new Exception('Provided data is invalid'); | ||
233 | } | ||
234 | if ($bookmark->getId() === null) { | 226 | if ($bookmark->getId() === null) { |
235 | return $this->add($bookmark, $save); | 227 | return $this->add($bookmark, $save); |
236 | } | 228 | } |
@@ -240,14 +232,11 @@ class BookmarkFileService implements BookmarkServiceInterface | |||
240 | /** | 232 | /** |
241 | * @inheritDoc | 233 | * @inheritDoc |
242 | */ | 234 | */ |
243 | public function remove($bookmark, $save = true) | 235 | public function remove(Bookmark $bookmark, bool $save = true): void |
244 | { | 236 | { |
245 | if (true !== $this->isLoggedIn) { | 237 | if (true !== $this->isLoggedIn) { |
246 | throw new Exception(t('You\'re not authorized to alter the datastore')); | 238 | throw new Exception(t('You\'re not authorized to alter the datastore')); |
247 | } | 239 | } |
248 | if (! $bookmark instanceof Bookmark) { | ||
249 | throw new Exception(t('Provided data is invalid')); | ||
250 | } | ||
251 | if (! isset($this->bookmarks[$bookmark->getId()])) { | 240 | if (! isset($this->bookmarks[$bookmark->getId()])) { |
252 | throw new BookmarkNotFoundException(); | 241 | throw new BookmarkNotFoundException(); |
253 | } | 242 | } |
@@ -262,7 +251,7 @@ class BookmarkFileService implements BookmarkServiceInterface | |||
262 | /** | 251 | /** |
263 | * @inheritDoc | 252 | * @inheritDoc |
264 | */ | 253 | */ |
265 | public function exists($id, $visibility = null) | 254 | public function exists(int $id, string $visibility = null): bool |
266 | { | 255 | { |
267 | if (! isset($this->bookmarks[$id])) { | 256 | if (! isset($this->bookmarks[$id])) { |
268 | return false; | 257 | return false; |
@@ -285,7 +274,7 @@ class BookmarkFileService implements BookmarkServiceInterface | |||
285 | /** | 274 | /** |
286 | * @inheritDoc | 275 | * @inheritDoc |
287 | */ | 276 | */ |
288 | public function count($visibility = null) | 277 | public function count(string $visibility = null): int |
289 | { | 278 | { |
290 | return count($this->search([], $visibility)); | 279 | return count($this->search([], $visibility)); |
291 | } | 280 | } |
@@ -293,7 +282,7 @@ class BookmarkFileService implements BookmarkServiceInterface | |||
293 | /** | 282 | /** |
294 | * @inheritDoc | 283 | * @inheritDoc |
295 | */ | 284 | */ |
296 | public function save() | 285 | public function save(): void |
297 | { | 286 | { |
298 | if (true !== $this->isLoggedIn) { | 287 | if (true !== $this->isLoggedIn) { |
299 | // TODO: raise an Exception instead | 288 | // TODO: raise an Exception instead |
@@ -308,7 +297,7 @@ class BookmarkFileService implements BookmarkServiceInterface | |||
308 | /** | 297 | /** |
309 | * @inheritDoc | 298 | * @inheritDoc |
310 | */ | 299 | */ |
311 | public function bookmarksCountPerTag($filteringTags = [], $visibility = null) | 300 | public function bookmarksCountPerTag(array $filteringTags = [], string $visibility = null): array |
312 | { | 301 | { |
313 | $bookmarks = $this->search(['searchtags' => $filteringTags], $visibility); | 302 | $bookmarks = $this->search(['searchtags' => $filteringTags], $visibility); |
314 | $tags = []; | 303 | $tags = []; |
@@ -344,13 +333,14 @@ class BookmarkFileService implements BookmarkServiceInterface | |||
344 | $keys = array_keys($tags); | 333 | $keys = array_keys($tags); |
345 | $tmpTags = array_combine($keys, $keys); | 334 | $tmpTags = array_combine($keys, $keys); |
346 | array_multisort($tags, SORT_DESC, $tmpTags, SORT_ASC, $tags); | 335 | array_multisort($tags, SORT_DESC, $tmpTags, SORT_ASC, $tags); |
336 | |||
347 | return $tags; | 337 | return $tags; |
348 | } | 338 | } |
349 | 339 | ||
350 | /** | 340 | /** |
351 | * @inheritDoc | 341 | * @inheritDoc |
352 | */ | 342 | */ |
353 | public function days() | 343 | public function days(): array |
354 | { | 344 | { |
355 | $bookmarkDays = []; | 345 | $bookmarkDays = []; |
356 | foreach ($this->search() as $bookmark) { | 346 | foreach ($this->search() as $bookmark) { |
@@ -365,7 +355,7 @@ class BookmarkFileService implements BookmarkServiceInterface | |||
365 | /** | 355 | /** |
366 | * @inheritDoc | 356 | * @inheritDoc |
367 | */ | 357 | */ |
368 | public function filterDay($request) | 358 | public function filterDay(string $request) |
369 | { | 359 | { |
370 | $visibility = $this->isLoggedIn ? BookmarkFilter::$ALL : BookmarkFilter::$PUBLIC; | 360 | $visibility = $this->isLoggedIn ? BookmarkFilter::$ALL : BookmarkFilter::$PUBLIC; |
371 | 361 | ||
@@ -375,7 +365,7 @@ class BookmarkFileService implements BookmarkServiceInterface | |||
375 | /** | 365 | /** |
376 | * @inheritDoc | 366 | * @inheritDoc |
377 | */ | 367 | */ |
378 | public function initialize() | 368 | public function initialize(): void |
379 | { | 369 | { |
380 | $initializer = new BookmarkInitializer($this); | 370 | $initializer = new BookmarkInitializer($this); |
381 | $initializer->initialize(); | 371 | $initializer->initialize(); |
@@ -388,7 +378,7 @@ class BookmarkFileService implements BookmarkServiceInterface | |||
388 | /** | 378 | /** |
389 | * Handles migration to the new database format (BookmarksArray). | 379 | * Handles migration to the new database format (BookmarksArray). |
390 | */ | 380 | */ |
391 | protected function migrate() | 381 | protected function migrate(): void |
392 | { | 382 | { |
393 | $bookmarkDb = new LegacyLinkDB( | 383 | $bookmarkDb = new LegacyLinkDB( |
394 | $this->conf->get('resource.datastore'), | 384 | $this->conf->get('resource.datastore'), |
diff --git a/application/bookmark/BookmarkFilter.php b/application/bookmark/BookmarkFilter.php index 6636bbfe..4232f114 100644 --- a/application/bookmark/BookmarkFilter.php +++ b/application/bookmark/BookmarkFilter.php | |||
@@ -1,5 +1,7 @@ | |||
1 | <?php | 1 | <?php |
2 | 2 | ||
3 | declare(strict_types=1); | ||
4 | |||
3 | namespace Shaarli\Bookmark; | 5 | namespace Shaarli\Bookmark; |
4 | 6 | ||
5 | use Exception; | 7 | use Exception; |
@@ -77,8 +79,13 @@ class BookmarkFilter | |||
77 | * | 79 | * |
78 | * @throws BookmarkNotFoundException | 80 | * @throws BookmarkNotFoundException |
79 | */ | 81 | */ |
80 | public function filter($type, $request, $casesensitive = false, $visibility = 'all', $untaggedonly = false) | 82 | public function filter( |
81 | { | 83 | string $type, |
84 | $request, | ||
85 | bool $casesensitive = false, | ||
86 | string $visibility = 'all', | ||
87 | bool $untaggedonly = false | ||
88 | ) { | ||
82 | if (!in_array($visibility, ['all', 'public', 'private'])) { | 89 | if (!in_array($visibility, ['all', 'public', 'private'])) { |
83 | $visibility = 'all'; | 90 | $visibility = 'all'; |
84 | } | 91 | } |
@@ -128,7 +135,7 @@ class BookmarkFilter | |||
128 | * | 135 | * |
129 | * @return Bookmark[] filtered bookmarks. | 136 | * @return Bookmark[] filtered bookmarks. |
130 | */ | 137 | */ |
131 | private function noFilter($visibility = 'all') | 138 | private function noFilter(string $visibility = 'all') |
132 | { | 139 | { |
133 | if ($visibility === 'all') { | 140 | if ($visibility === 'all') { |
134 | return $this->bookmarks; | 141 | return $this->bookmarks; |
@@ -151,11 +158,11 @@ class BookmarkFilter | |||
151 | * | 158 | * |
152 | * @param string $smallHash permalink hash. | 159 | * @param string $smallHash permalink hash. |
153 | * | 160 | * |
154 | * @return array $filtered array containing permalink data. | 161 | * @return Bookmark[] $filtered array containing permalink data. |
155 | * | 162 | * |
156 | * @throws \Shaarli\Bookmark\Exception\BookmarkNotFoundException if the smallhash doesn't match any link. | 163 | * @throws BookmarkNotFoundException if the smallhash doesn't match any link. |
157 | */ | 164 | */ |
158 | private function filterSmallHash($smallHash) | 165 | private function filterSmallHash(string $smallHash) |
159 | { | 166 | { |
160 | foreach ($this->bookmarks as $key => $l) { | 167 | foreach ($this->bookmarks as $key => $l) { |
161 | if ($smallHash == $l->getShortUrl()) { | 168 | if ($smallHash == $l->getShortUrl()) { |
@@ -186,9 +193,9 @@ class BookmarkFilter | |||
186 | * @param string $searchterms search query. | 193 | * @param string $searchterms search query. |
187 | * @param string $visibility Optional: return only all/private/public bookmarks. | 194 | * @param string $visibility Optional: return only all/private/public bookmarks. |
188 | * | 195 | * |
189 | * @return array search results. | 196 | * @return Bookmark[] search results. |
190 | */ | 197 | */ |
191 | private function filterFulltext($searchterms, $visibility = 'all') | 198 | private function filterFulltext(string $searchterms, string $visibility = 'all') |
192 | { | 199 | { |
193 | if (empty($searchterms)) { | 200 | if (empty($searchterms)) { |
194 | return $this->noFilter($visibility); | 201 | return $this->noFilter($visibility); |
@@ -268,7 +275,7 @@ class BookmarkFilter | |||
268 | * | 275 | * |
269 | * @return string generated regex fragment | 276 | * @return string generated regex fragment |
270 | */ | 277 | */ |
271 | private static function tag2regex($tag) | 278 | private static function tag2regex(string $tag): string |
272 | { | 279 | { |
273 | $len = strlen($tag); | 280 | $len = strlen($tag); |
274 | if (!$len || $tag === "-" || $tag === "*") { | 281 | if (!$len || $tag === "-" || $tag === "*") { |
@@ -314,13 +321,13 @@ class BookmarkFilter | |||
314 | * You can specify one or more tags, separated by space or a comma, e.g. | 321 | * You can specify one or more tags, separated by space or a comma, e.g. |
315 | * print_r($mydb->filterTags('linux programming')); | 322 | * print_r($mydb->filterTags('linux programming')); |
316 | * | 323 | * |
317 | * @param string $tags list of tags separated by commas or blank spaces. | 324 | * @param string|array $tags list of tags, separated by commas or blank spaces if passed as string. |
318 | * @param bool $casesensitive ignore case if false. | 325 | * @param bool $casesensitive ignore case if false. |
319 | * @param string $visibility Optional: return only all/private/public bookmarks. | 326 | * @param string $visibility Optional: return only all/private/public bookmarks. |
320 | * | 327 | * |
321 | * @return array filtered bookmarks. | 328 | * @return Bookmark[] filtered bookmarks. |
322 | */ | 329 | */ |
323 | public function filterTags($tags, $casesensitive = false, $visibility = 'all') | 330 | public function filterTags($tags, bool $casesensitive = false, string $visibility = 'all') |
324 | { | 331 | { |
325 | // get single tags (we may get passed an array, even though the docs say different) | 332 | // get single tags (we may get passed an array, even though the docs say different) |
326 | $inputTags = $tags; | 333 | $inputTags = $tags; |
@@ -396,9 +403,9 @@ class BookmarkFilter | |||
396 | * | 403 | * |
397 | * @param string $visibility return only all/private/public bookmarks. | 404 | * @param string $visibility return only all/private/public bookmarks. |
398 | * | 405 | * |
399 | * @return array filtered bookmarks. | 406 | * @return Bookmark[] filtered bookmarks. |
400 | */ | 407 | */ |
401 | public function filterUntagged($visibility) | 408 | public function filterUntagged(string $visibility) |
402 | { | 409 | { |
403 | $filtered = []; | 410 | $filtered = []; |
404 | foreach ($this->bookmarks as $key => $link) { | 411 | foreach ($this->bookmarks as $key => $link) { |
@@ -427,11 +434,11 @@ class BookmarkFilter | |||
427 | * @param string $day day to filter. | 434 | * @param string $day day to filter. |
428 | * @param string $visibility return only all/private/public bookmarks. | 435 | * @param string $visibility return only all/private/public bookmarks. |
429 | 436 | ||
430 | * @return array all link matching given day. | 437 | * @return Bookmark[] all link matching given day. |
431 | * | 438 | * |
432 | * @throws Exception if date format is invalid. | 439 | * @throws Exception if date format is invalid. |
433 | */ | 440 | */ |
434 | public function filterDay($day, $visibility) | 441 | public function filterDay(string $day, string $visibility) |
435 | { | 442 | { |
436 | if (!checkDateFormat('Ymd', $day)) { | 443 | if (!checkDateFormat('Ymd', $day)) { |
437 | throw new Exception('Invalid date format'); | 444 | throw new Exception('Invalid date format'); |
@@ -460,9 +467,9 @@ class BookmarkFilter | |||
460 | * @param string $tags string containing a list of tags. | 467 | * @param string $tags string containing a list of tags. |
461 | * @param bool $casesensitive will convert everything to lowercase if false. | 468 | * @param bool $casesensitive will convert everything to lowercase if false. |
462 | * | 469 | * |
463 | * @return array filtered tags string. | 470 | * @return string[] filtered tags string. |
464 | */ | 471 | */ |
465 | public static function tagsStrToArray($tags, $casesensitive) | 472 | public static function tagsStrToArray(string $tags, bool $casesensitive): array |
466 | { | 473 | { |
467 | // We use UTF-8 conversion to handle various graphemes (i.e. cyrillic, or greek) | 474 | // We use UTF-8 conversion to handle various graphemes (i.e. cyrillic, or greek) |
468 | $tagsOut = $casesensitive ? $tags : mb_convert_case($tags, MB_CASE_LOWER, 'UTF-8'); | 475 | $tagsOut = $casesensitive ? $tags : mb_convert_case($tags, MB_CASE_LOWER, 'UTF-8'); |
diff --git a/application/bookmark/BookmarkIO.php b/application/bookmark/BookmarkIO.php index 099653b0..f40fa476 100644 --- a/application/bookmark/BookmarkIO.php +++ b/application/bookmark/BookmarkIO.php | |||
@@ -1,5 +1,7 @@ | |||
1 | <?php | 1 | <?php |
2 | 2 | ||
3 | declare(strict_types=1); | ||
4 | |||
3 | namespace Shaarli\Bookmark; | 5 | namespace Shaarli\Bookmark; |
4 | 6 | ||
5 | use malkusch\lock\mutex\Mutex; | 7 | use malkusch\lock\mutex\Mutex; |
@@ -61,7 +63,7 @@ class BookmarkIO | |||
61 | /** | 63 | /** |
62 | * Reads database from disk to memory | 64 | * Reads database from disk to memory |
63 | * | 65 | * |
64 | * @return BookmarkArray instance | 66 | * @return Bookmark[] |
65 | * | 67 | * |
66 | * @throws NotWritableDataStoreException Data couldn't be loaded | 68 | * @throws NotWritableDataStoreException Data couldn't be loaded |
67 | * @throws EmptyDataStoreException Datastore file exists but does not contain any bookmark | 69 | * @throws EmptyDataStoreException Datastore file exists but does not contain any bookmark |
@@ -101,7 +103,7 @@ class BookmarkIO | |||
101 | /** | 103 | /** |
102 | * Saves the database from memory to disk | 104 | * Saves the database from memory to disk |
103 | * | 105 | * |
104 | * @param BookmarkArray $links instance. | 106 | * @param Bookmark[] $links |
105 | * | 107 | * |
106 | * @throws NotWritableDataStoreException the datastore is not writable | 108 | * @throws NotWritableDataStoreException the datastore is not writable |
107 | */ | 109 | */ |
diff --git a/application/bookmark/BookmarkInitializer.php b/application/bookmark/BookmarkInitializer.php index 815047e3..04b996f3 100644 --- a/application/bookmark/BookmarkInitializer.php +++ b/application/bookmark/BookmarkInitializer.php | |||
@@ -1,5 +1,7 @@ | |||
1 | <?php | 1 | <?php |
2 | 2 | ||
3 | declare(strict_types=1); | ||
4 | |||
3 | namespace Shaarli\Bookmark; | 5 | namespace Shaarli\Bookmark; |
4 | 6 | ||
5 | /** | 7 | /** |
@@ -23,7 +25,7 @@ class BookmarkInitializer | |||
23 | * | 25 | * |
24 | * @param BookmarkServiceInterface $bookmarkService | 26 | * @param BookmarkServiceInterface $bookmarkService |
25 | */ | 27 | */ |
26 | public function __construct($bookmarkService) | 28 | public function __construct(BookmarkServiceInterface $bookmarkService) |
27 | { | 29 | { |
28 | $this->bookmarkService = $bookmarkService; | 30 | $this->bookmarkService = $bookmarkService; |
29 | } | 31 | } |
@@ -31,7 +33,7 @@ class BookmarkInitializer | |||
31 | /** | 33 | /** |
32 | * Initialize the data store with default bookmarks | 34 | * Initialize the data store with default bookmarks |
33 | */ | 35 | */ |
34 | public function initialize() | 36 | public function initialize(): void |
35 | { | 37 | { |
36 | $bookmark = new Bookmark(); | 38 | $bookmark = new Bookmark(); |
37 | $bookmark->setTitle('quicksilver (loop) on Vimeo ' . t('(private bookmark with thumbnail demo)')); | 39 | $bookmark->setTitle('quicksilver (loop) on Vimeo ' . t('(private bookmark with thumbnail demo)')); |
diff --git a/application/bookmark/BookmarkServiceInterface.php b/application/bookmark/BookmarkServiceInterface.php index 638cfa5f..37a54d03 100644 --- a/application/bookmark/BookmarkServiceInterface.php +++ b/application/bookmark/BookmarkServiceInterface.php | |||
@@ -1,7 +1,8 @@ | |||
1 | <?php | 1 | <?php |
2 | 2 | ||
3 | namespace Shaarli\Bookmark; | 3 | declare(strict_types=1); |
4 | 4 | ||
5 | namespace Shaarli\Bookmark; | ||
5 | 6 | ||
6 | use Shaarli\Bookmark\Exception\BookmarkNotFoundException; | 7 | use Shaarli\Bookmark\Exception\BookmarkNotFoundException; |
7 | use Shaarli\Bookmark\Exception\NotWritableDataStoreException; | 8 | use Shaarli\Bookmark\Exception\NotWritableDataStoreException; |
@@ -10,6 +11,9 @@ use Shaarli\Bookmark\Exception\NotWritableDataStoreException; | |||
10 | * Class BookmarksService | 11 | * Class BookmarksService |
11 | * | 12 | * |
12 | * This is the entry point to manipulate the bookmark DB. | 13 | * This is the entry point to manipulate the bookmark DB. |
14 | * | ||
15 | * Regarding return types of a list of bookmarks, it can either be an array or an ArrayAccess implementation, | ||
16 | * so until PHP 8.0 is the minimal supported version with union return types it cannot be explicitly added. | ||
13 | */ | 17 | */ |
14 | interface BookmarkServiceInterface | 18 | interface BookmarkServiceInterface |
15 | { | 19 | { |
@@ -18,51 +22,51 @@ interface BookmarkServiceInterface | |||
18 | * | 22 | * |
19 | * @param string $hash | 23 | * @param string $hash |
20 | * | 24 | * |
21 | * @return mixed | 25 | * @return Bookmark |
22 | * | 26 | * |
23 | * @throws \Exception | 27 | * @throws \Exception |
24 | */ | 28 | */ |
25 | public function findByHash($hash); | 29 | public function findByHash(string $hash): Bookmark; |
26 | 30 | ||
27 | /** | 31 | /** |
28 | * @param $url | 32 | * @param $url |
29 | * | 33 | * |
30 | * @return Bookmark|null | 34 | * @return Bookmark|null |
31 | */ | 35 | */ |
32 | public function findByUrl($url); | 36 | public function findByUrl(string $url): ?Bookmark; |
33 | 37 | ||
34 | /** | 38 | /** |
35 | * Search bookmarks | 39 | * Search bookmarks |
36 | * | 40 | * |
37 | * @param mixed $request | 41 | * @param array $request |
38 | * @param string $visibility | 42 | * @param ?string $visibility |
39 | * @param bool $caseSensitive | 43 | * @param bool $caseSensitive |
40 | * @param bool $untaggedOnly | 44 | * @param bool $untaggedOnly |
41 | * @param bool $ignoreSticky | 45 | * @param bool $ignoreSticky |
42 | * | 46 | * |
43 | * @return Bookmark[] | 47 | * @return Bookmark[] |
44 | */ | 48 | */ |
45 | public function search( | 49 | public function search( |
46 | $request = [], | 50 | array $request = [], |
47 | $visibility = null, | 51 | string $visibility = null, |
48 | $caseSensitive = false, | 52 | bool $caseSensitive = false, |
49 | $untaggedOnly = false, | 53 | bool $untaggedOnly = false, |
50 | bool $ignoreSticky = false | 54 | bool $ignoreSticky = false |
51 | ); | 55 | ); |
52 | 56 | ||
53 | /** | 57 | /** |
54 | * Get a single bookmark by its ID. | 58 | * Get a single bookmark by its ID. |
55 | * | 59 | * |
56 | * @param int $id Bookmark ID | 60 | * @param int $id Bookmark ID |
57 | * @param string $visibility all|public|private e.g. with public, accessing a private bookmark will throw an | 61 | * @param ?string $visibility all|public|private e.g. with public, accessing a private bookmark will throw an |
58 | * exception | 62 | * exception |
59 | * | 63 | * |
60 | * @return Bookmark | 64 | * @return Bookmark |
61 | * | 65 | * |
62 | * @throws BookmarkNotFoundException | 66 | * @throws BookmarkNotFoundException |
63 | * @throws \Exception | 67 | * @throws \Exception |
64 | */ | 68 | */ |
65 | public function get($id, $visibility = null); | 69 | public function get(int $id, string $visibility = null); |
66 | 70 | ||
67 | /** | 71 | /** |
68 | * Updates an existing bookmark (depending on its ID). | 72 | * Updates an existing bookmark (depending on its ID). |
@@ -75,7 +79,7 @@ interface BookmarkServiceInterface | |||
75 | * @throws BookmarkNotFoundException | 79 | * @throws BookmarkNotFoundException |
76 | * @throws \Exception | 80 | * @throws \Exception |
77 | */ | 81 | */ |
78 | public function set($bookmark, $save = true); | 82 | public function set(Bookmark $bookmark, bool $save = true): Bookmark; |
79 | 83 | ||
80 | /** | 84 | /** |
81 | * Adds a new bookmark (the ID must be empty). | 85 | * Adds a new bookmark (the ID must be empty). |
@@ -87,7 +91,7 @@ interface BookmarkServiceInterface | |||
87 | * | 91 | * |
88 | * @throws \Exception | 92 | * @throws \Exception |
89 | */ | 93 | */ |
90 | public function add($bookmark, $save = true); | 94 | public function add(Bookmark $bookmark, bool $save = true): Bookmark; |
91 | 95 | ||
92 | /** | 96 | /** |
93 | * Adds or updates a bookmark depending on its ID: | 97 | * Adds or updates a bookmark depending on its ID: |
@@ -101,7 +105,7 @@ interface BookmarkServiceInterface | |||
101 | * | 105 | * |
102 | * @throws \Exception | 106 | * @throws \Exception |
103 | */ | 107 | */ |
104 | public function addOrSet($bookmark, $save = true); | 108 | public function addOrSet(Bookmark $bookmark, bool $save = true): Bookmark; |
105 | 109 | ||
106 | /** | 110 | /** |
107 | * Deletes a bookmark. | 111 | * Deletes a bookmark. |
@@ -111,51 +115,51 @@ interface BookmarkServiceInterface | |||
111 | * | 115 | * |
112 | * @throws \Exception | 116 | * @throws \Exception |
113 | */ | 117 | */ |
114 | public function remove($bookmark, $save = true); | 118 | public function remove(Bookmark $bookmark, bool $save = true): void; |
115 | 119 | ||
116 | /** | 120 | /** |
117 | * Get a single bookmark by its ID. | 121 | * Get a single bookmark by its ID. |
118 | * | 122 | * |
119 | * @param int $id Bookmark ID | 123 | * @param int $id Bookmark ID |
120 | * @param string $visibility all|public|private e.g. with public, accessing a private bookmark will throw an | 124 | * @param ?string $visibility all|public|private e.g. with public, accessing a private bookmark will throw an |
121 | * exception | 125 | * exception |
122 | * | 126 | * |
123 | * @return bool | 127 | * @return bool |
124 | */ | 128 | */ |
125 | public function exists($id, $visibility = null); | 129 | public function exists(int $id, string $visibility = null): bool; |
126 | 130 | ||
127 | /** | 131 | /** |
128 | * Return the number of available bookmarks for given visibility. | 132 | * Return the number of available bookmarks for given visibility. |
129 | * | 133 | * |
130 | * @param string $visibility public|private|all | 134 | * @param ?string $visibility public|private|all |
131 | * | 135 | * |
132 | * @return int Number of bookmarks | 136 | * @return int Number of bookmarks |
133 | */ | 137 | */ |
134 | public function count($visibility = null); | 138 | public function count(string $visibility = null): int; |
135 | 139 | ||
136 | /** | 140 | /** |
137 | * Write the datastore. | 141 | * Write the datastore. |
138 | * | 142 | * |
139 | * @throws NotWritableDataStoreException | 143 | * @throws NotWritableDataStoreException |
140 | */ | 144 | */ |
141 | public function save(); | 145 | public function save(): void; |
142 | 146 | ||
143 | /** | 147 | /** |
144 | * Returns the list tags appearing in the bookmarks with the given tags | 148 | * Returns the list tags appearing in the bookmarks with the given tags |
145 | * | 149 | * |
146 | * @param array $filteringTags tags selecting the bookmarks to consider | 150 | * @param array|null $filteringTags tags selecting the bookmarks to consider |
147 | * @param string $visibility process only all/private/public bookmarks | 151 | * @param string|null $visibility process only all/private/public bookmarks |
148 | * | 152 | * |
149 | * @return array tag => bookmarksCount | 153 | * @return array tag => bookmarksCount |
150 | */ | 154 | */ |
151 | public function bookmarksCountPerTag($filteringTags = [], $visibility = 'all'); | 155 | public function bookmarksCountPerTag(array $filteringTags = [], ?string $visibility = null): array; |
152 | 156 | ||
153 | /** | 157 | /** |
154 | * Returns the list of days containing articles (oldest first) | 158 | * Returns the list of days containing articles (oldest first) |
155 | * | 159 | * |
156 | * @return array containing days (in format YYYYMMDD). | 160 | * @return array containing days (in format YYYYMMDD). |
157 | */ | 161 | */ |
158 | public function days(); | 162 | public function days(): array; |
159 | 163 | ||
160 | /** | 164 | /** |
161 | * Returns the list of articles for a given day. | 165 | * Returns the list of articles for a given day. |
@@ -166,10 +170,10 @@ interface BookmarkServiceInterface | |||
166 | * | 170 | * |
167 | * @throws BookmarkNotFoundException | 171 | * @throws BookmarkNotFoundException |
168 | */ | 172 | */ |
169 | public function filterDay($request); | 173 | public function filterDay(string $request); |
170 | 174 | ||
171 | /** | 175 | /** |
172 | * Creates the default database after a fresh install. | 176 | * Creates the default database after a fresh install. |
173 | */ | 177 | */ |
174 | public function initialize(); | 178 | public function initialize(): void; |
175 | } | 179 | } |
diff --git a/application/feed/FeedBuilder.php b/application/feed/FeedBuilder.php index f6def630..f70fce4f 100644 --- a/application/feed/FeedBuilder.php +++ b/application/feed/FeedBuilder.php | |||
@@ -102,7 +102,7 @@ class FeedBuilder | |||
102 | } | 102 | } |
103 | 103 | ||
104 | // Optionally filter the results: | 104 | // Optionally filter the results: |
105 | $linksToDisplay = $this->linkDB->search($userInput, null, false, false, true); | 105 | $linksToDisplay = $this->linkDB->search($userInput ?? [], null, false, false, true); |
106 | 106 | ||
107 | $nblinksToDisplay = $this->getNbLinks(count($linksToDisplay), $userInput); | 107 | $nblinksToDisplay = $this->getNbLinks(count($linksToDisplay), $userInput); |
108 | 108 | ||
diff --git a/application/front/controller/admin/ThumbnailsController.php b/application/front/controller/admin/ThumbnailsController.php index 81c87ed0..4dc09d38 100644 --- a/application/front/controller/admin/ThumbnailsController.php +++ b/application/front/controller/admin/ThumbnailsController.php | |||
@@ -52,7 +52,7 @@ class ThumbnailsController extends ShaarliAdminController | |||
52 | } | 52 | } |
53 | 53 | ||
54 | try { | 54 | try { |
55 | $bookmark = $this->container->bookmarkService->get($id); | 55 | $bookmark = $this->container->bookmarkService->get((int) $id); |
56 | } catch (BookmarkNotFoundException $e) { | 56 | } catch (BookmarkNotFoundException $e) { |
57 | return $response->withStatus(404); | 57 | return $response->withStatus(404); |
58 | } | 58 | } |
diff --git a/application/security/LoginManager.php b/application/security/LoginManager.php index d74c3118..65048f10 100644 --- a/application/security/LoginManager.php +++ b/application/security/LoginManager.php | |||
@@ -118,7 +118,7 @@ class LoginManager | |||
118 | * | 118 | * |
119 | * @return true when the user is logged in, false otherwise | 119 | * @return true when the user is logged in, false otherwise |
120 | */ | 120 | */ |
121 | public function isLoggedIn() | 121 | public function isLoggedIn(): bool |
122 | { | 122 | { |
123 | if ($this->openShaarli) { | 123 | if ($this->openShaarli) { |
124 | return true; | 124 | return true; |