aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorArthurHoaro <arthur@hoa.ro>2021-02-04 11:11:33 +0100
committerGitHub <noreply@github.com>2021-02-04 11:11:33 +0100
commit9db1ccdf2ce8381e1f3acb581d3c6a6def095d8c (patch)
tree97a618b77d327a5f963c91522988e24db5a9e158
parent8997ae6c8e24286f7d47981eaf905e80d2481c10 (diff)
parentbcba6bd353161fab456b423e93571ab027d5423c (diff)
downloadShaarli-9db1ccdf2ce8381e1f3acb581d3c6a6def095d8c.tar.gz
Shaarli-9db1ccdf2ce8381e1f3acb581d3c6a6def095d8c.tar.zst
Shaarli-9db1ccdf2ce8381e1f3acb581d3c6a6def095d8c.zip
Merge pull request #1698 from ArthurHoaro/feature/plugins-search-filterHEADmaster
New plugin hook: ability to add custom filters to Shaarli search engine
-rw-r--r--application/api/ApiMiddleware.php1
-rw-r--r--application/bookmark/BookmarkFileService.php8
-rw-r--r--application/bookmark/BookmarkFilter.php246
-rw-r--r--application/container/ContainerBuilder.php1
-rw-r--r--application/plugin/PluginManager.php56
-rw-r--r--doc/md/dev/Plugin-system.md19
-rw-r--r--plugins/demo_plugin/demo_plugin.php33
-rw-r--r--tests/PluginManagerTest.php16
-rw-r--r--tests/api/ApiMiddlewareTest.php2
-rw-r--r--tests/api/controllers/info/InfoTest.php11
-rw-r--r--tests/api/controllers/links/DeleteLinkTest.php21
-rw-r--r--tests/api/controllers/links/GetLinkIdTest.php10
-rw-r--r--tests/api/controllers/links/GetLinksTest.php10
-rw-r--r--tests/api/controllers/links/PostLinkTest.php11
-rw-r--r--tests/api/controllers/links/PutLinkTest.php11
-rw-r--r--tests/api/controllers/tags/DeleteTagTest.php29
-rw-r--r--tests/api/controllers/tags/GetTagNameTest.php13
-rw-r--r--tests/api/controllers/tags/GetTagsTest.php15
-rw-r--r--tests/api/controllers/tags/PutTagTest.php13
-rw-r--r--tests/bookmark/BookmarkFileServiceTest.php137
-rw-r--r--tests/bookmark/BookmarkFilterTest.php65
-rw-r--r--tests/bookmark/BookmarkInitializerTest.php37
-rw-r--r--tests/feed/FeedBuilderTest.php10
-rw-r--r--tests/netscape/BookmarkExportTest.php13
-rw-r--r--tests/netscape/BookmarkImportTest.php13
-rw-r--r--tests/plugins/test/test.php7
-rw-r--r--tests/updater/UpdaterTest.php9
27 files changed, 593 insertions, 224 deletions
diff --git a/application/api/ApiMiddleware.php b/application/api/ApiMiddleware.php
index 9fb88358..cc7af18e 100644
--- a/application/api/ApiMiddleware.php
+++ b/application/api/ApiMiddleware.php
@@ -145,6 +145,7 @@ class ApiMiddleware
145 { 145 {
146 $linkDb = new BookmarkFileService( 146 $linkDb = new BookmarkFileService(
147 $conf, 147 $conf,
148 $this->container->get('pluginManager'),
148 $this->container->get('history'), 149 $this->container->get('history'),
149 new FlockMutex(fopen(SHAARLI_MUTEX_FILE, 'r'), 2), 150 new FlockMutex(fopen(SHAARLI_MUTEX_FILE, 'r'), 2),
150 true 151 true
diff --git a/application/bookmark/BookmarkFileService.php b/application/bookmark/BookmarkFileService.php
index 8ea37427..e64eeafb 100644
--- a/application/bookmark/BookmarkFileService.php
+++ b/application/bookmark/BookmarkFileService.php
@@ -15,6 +15,7 @@ use Shaarli\Formatter\BookmarkMarkdownFormatter;
15use Shaarli\History; 15use Shaarli\History;
16use Shaarli\Legacy\LegacyLinkDB; 16use Shaarli\Legacy\LegacyLinkDB;
17use Shaarli\Legacy\LegacyUpdater; 17use Shaarli\Legacy\LegacyUpdater;
18use Shaarli\Plugin\PluginManager;
18use Shaarli\Render\PageCacheManager; 19use Shaarli\Render\PageCacheManager;
19use Shaarli\Updater\UpdaterUtils; 20use Shaarli\Updater\UpdaterUtils;
20 21
@@ -40,6 +41,9 @@ class BookmarkFileService implements BookmarkServiceInterface
40 /** @var ConfigManager instance */ 41 /** @var ConfigManager instance */
41 protected $conf; 42 protected $conf;
42 43
44 /** @var PluginManager */
45 protected $pluginManager;
46
43 /** @var History instance */ 47 /** @var History instance */
44 protected $history; 48 protected $history;
45 49
@@ -57,6 +61,7 @@ class BookmarkFileService implements BookmarkServiceInterface
57 */ 61 */
58 public function __construct( 62 public function __construct(
59 ConfigManager $conf, 63 ConfigManager $conf,
64 PluginManager $pluginManager,
60 History $history, 65 History $history,
61 Mutex $mutex, 66 Mutex $mutex,
62 bool $isLoggedIn 67 bool $isLoggedIn
@@ -95,7 +100,8 @@ class BookmarkFileService implements BookmarkServiceInterface
95 } 100 }
96 } 101 }
97 102
98 $this->bookmarkFilter = new BookmarkFilter($this->bookmarks, $this->conf); 103 $this->pluginManager = $pluginManager;
104 $this->bookmarkFilter = new BookmarkFilter($this->bookmarks, $this->conf, $this->pluginManager);
99 } 105 }
100 106
101 /** 107 /**
diff --git a/application/bookmark/BookmarkFilter.php b/application/bookmark/BookmarkFilter.php
index db83c51c..8b41dbb8 100644
--- a/application/bookmark/BookmarkFilter.php
+++ b/application/bookmark/BookmarkFilter.php
@@ -4,9 +4,9 @@ declare(strict_types=1);
4 4
5namespace Shaarli\Bookmark; 5namespace Shaarli\Bookmark;
6 6
7use Exception;
8use Shaarli\Bookmark\Exception\BookmarkNotFoundException; 7use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
9use Shaarli\Config\ConfigManager; 8use Shaarli\Config\ConfigManager;
9use Shaarli\Plugin\PluginManager;
10 10
11/** 11/**
12 * Class LinkFilter. 12 * Class LinkFilter.
@@ -33,11 +33,6 @@ class BookmarkFilter
33 /** 33 /**
34 * @var string filter by day. 34 * @var string filter by day.
35 */ 35 */
36 public static $FILTER_DAY = 'FILTER_DAY';
37
38 /**
39 * @var string filter by day.
40 */
41 public static $DEFAULT = 'NO_FILTER'; 36 public static $DEFAULT = 'NO_FILTER';
42 37
43 /** @var string Visibility: all */ 38 /** @var string Visibility: all */
@@ -62,13 +57,17 @@ class BookmarkFilter
62 /** @var ConfigManager */ 57 /** @var ConfigManager */
63 protected $conf; 58 protected $conf;
64 59
60 /** @var PluginManager */
61 protected $pluginManager;
62
65 /** 63 /**
66 * @param Bookmark[] $bookmarks initialization. 64 * @param Bookmark[] $bookmarks initialization.
67 */ 65 */
68 public function __construct($bookmarks, ConfigManager $conf) 66 public function __construct($bookmarks, ConfigManager $conf, PluginManager $pluginManager)
69 { 67 {
70 $this->bookmarks = $bookmarks; 68 $this->bookmarks = $bookmarks;
71 $this->conf = $conf; 69 $this->conf = $conf;
70 $this->pluginManager = $pluginManager;
72 } 71 }
73 72
74 /** 73 /**
@@ -112,12 +111,12 @@ class BookmarkFilter
112 $filtered = $this->bookmarks; 111 $filtered = $this->bookmarks;
113 } 112 }
114 if (!empty($request[0])) { 113 if (!empty($request[0])) {
115 $filtered = (new BookmarkFilter($filtered, $this->conf)) 114 $filtered = (new BookmarkFilter($filtered, $this->conf, $this->pluginManager))
116 ->filterTags($request[0], $casesensitive, $visibility) 115 ->filterTags($request[0], $casesensitive, $visibility)
117 ; 116 ;
118 } 117 }
119 if (!empty($request[1])) { 118 if (!empty($request[1])) {
120 $filtered = (new BookmarkFilter($filtered, $this->conf)) 119 $filtered = (new BookmarkFilter($filtered, $this->conf, $this->pluginManager))
121 ->filterFulltext($request[1], $visibility) 120 ->filterFulltext($request[1], $visibility)
122 ; 121 ;
123 } 122 }
@@ -130,8 +129,6 @@ class BookmarkFilter
130 } else { 129 } else {
131 return $this->filterTags($request, $casesensitive, $visibility); 130 return $this->filterTags($request, $casesensitive, $visibility);
132 } 131 }
133 case self::$FILTER_DAY:
134 return $this->filterDay($request, $visibility);
135 default: 132 default:
136 return $this->noFilter($visibility); 133 return $this->noFilter($visibility);
137 } 134 }
@@ -146,13 +143,20 @@ class BookmarkFilter
146 */ 143 */
147 private function noFilter(string $visibility = 'all') 144 private function noFilter(string $visibility = 'all')
148 { 145 {
149 if ($visibility === 'all') {
150 return $this->bookmarks;
151 }
152
153 $out = []; 146 $out = [];
154 foreach ($this->bookmarks as $key => $value) { 147 foreach ($this->bookmarks as $key => $value) {
155 if ($value->isPrivate() && $visibility === 'private') { 148 if (
149 !$this->pluginManager->filterSearchEntry(
150 $value,
151 ['source' => 'no_filter', 'visibility' => $visibility]
152 )
153 ) {
154 continue;
155 }
156
157 if ($visibility === 'all') {
158 $out[$key] = $value;
159 } elseif ($value->isPrivate() && $visibility === 'private') {
156 $out[$key] = $value; 160 $out[$key] = $value;
157 } elseif (!$value->isPrivate() && $visibility === 'public') { 161 } elseif (!$value->isPrivate() && $visibility === 'public') {
158 $out[$key] = $value; 162 $out[$key] = $value;
@@ -233,18 +237,34 @@ class BookmarkFilter
233 } 237 }
234 238
235 // Iterate over every stored link. 239 // Iterate over every stored link.
236 foreach ($this->bookmarks as $id => $link) { 240 foreach ($this->bookmarks as $id => $bookmark) {
241 if (
242 !$this->pluginManager->filterSearchEntry(
243 $bookmark,
244 [
245 'source' => 'fulltext',
246 'searchterms' => $searchterms,
247 'andSearch' => $andSearch,
248 'exactSearch' => $exactSearch,
249 'excludeSearch' => $excludeSearch,
250 'visibility' => $visibility
251 ]
252 )
253 ) {
254 continue;
255 }
256
237 // ignore non private bookmarks when 'privatonly' is on. 257 // ignore non private bookmarks when 'privatonly' is on.
238 if ($visibility !== 'all') { 258 if ($visibility !== 'all') {
239 if (!$link->isPrivate() && $visibility === 'private') { 259 if (!$bookmark->isPrivate() && $visibility === 'private') {
240 continue; 260 continue;
241 } elseif ($link->isPrivate() && $visibility === 'public') { 261 } elseif ($bookmark->isPrivate() && $visibility === 'public') {
242 continue; 262 continue;
243 } 263 }
244 } 264 }
245 265
246 $lengths = []; 266 $lengths = [];
247 $content = $this->buildFullTextSearchableLink($link, $lengths); 267 $content = $this->buildFullTextSearchableLink($bookmark, $lengths);
248 268
249 // Be optimistic 269 // Be optimistic
250 $found = true; 270 $found = true;
@@ -270,12 +290,12 @@ class BookmarkFilter
270 } 290 }
271 291
272 if ($found !== false) { 292 if ($found !== false) {
273 $link->addAdditionalContentEntry( 293 $bookmark->addAdditionalContentEntry(
274 'search_highlight', 294 'search_highlight',
275 $this->postProcessFoundPositions($lengths, $foundPositions) 295 $this->postProcessFoundPositions($lengths, $foundPositions)
276 ); 296 );
277 297
278 $filtered[$id] = $link; 298 $filtered[$id] = $bookmark;
279 } 299 }
280 } 300 }
281 301
@@ -283,56 +303,6 @@ class BookmarkFilter
283 } 303 }
284 304
285 /** 305 /**
286 * generate a regex fragment out of a tag
287 *
288 * @param string $tag to to generate regexs from. may start with '-' to negate, contain '*' as wildcard
289 *
290 * @return string generated regex fragment
291 */
292 protected function tag2regex(string $tag): string
293 {
294 $tagsSeparator = $this->conf->get('general.tags_separator', ' ');
295 $len = strlen($tag);
296 if (!$len || $tag === "-" || $tag === "*") {
297 // nothing to search, return empty regex
298 return '';
299 }
300 if ($tag[0] === "-") {
301 // query is negated
302 $i = 1; // use offset to start after '-' character
303 $regex = '(?!'; // create negative lookahead
304 } else {
305 $i = 0; // start at first character
306 $regex = '(?='; // use positive lookahead
307 }
308 // before tag may only be the separator or the beginning
309 $regex .= '.*(?:^|' . $tagsSeparator . ')';
310 // iterate over string, separating it into placeholder and content
311 for (; $i < $len; $i++) {
312 if ($tag[$i] === '*') {
313 // placeholder found
314 $regex .= '[^' . $tagsSeparator . ']*?';
315 } else {
316 // regular characters
317 $offset = strpos($tag, '*', $i);
318 if ($offset === false) {
319 // no placeholder found, set offset to end of string
320 $offset = $len;
321 }
322 // subtract one, as we want to get before the placeholder or end of string
323 $offset -= 1;
324 // we got a tag name that we want to search for. escape any regex characters to prevent conflicts.
325 $regex .= preg_quote(substr($tag, $i, $offset - $i + 1), '/');
326 // move $i on
327 $i = $offset;
328 }
329 }
330 // after the tag may only be the separator or the end
331 $regex .= '(?:$|' . $tagsSeparator . '))';
332 return $regex;
333 }
334
335 /**
336 * Returns the list of bookmarks associated with a given list of tags 306 * Returns the list of bookmarks associated with a given list of tags
337 * 307 *
338 * You can specify one or more tags, separated by space or a comma, e.g. 308 * You can specify one or more tags, separated by space or a comma, e.g.
@@ -381,25 +351,39 @@ class BookmarkFilter
381 $filtered = []; 351 $filtered = [];
382 352
383 // iterate over each link 353 // iterate over each link
384 foreach ($this->bookmarks as $key => $link) { 354 foreach ($this->bookmarks as $key => $bookmark) {
355 if (
356 !$this->pluginManager->filterSearchEntry(
357 $bookmark,
358 [
359 'source' => 'tags',
360 'tags' => $tags,
361 'casesensitive' => $casesensitive,
362 'visibility' => $visibility
363 ]
364 )
365 ) {
366 continue;
367 }
368
385 // check level of visibility 369 // check level of visibility
386 // ignore non private bookmarks when 'privateonly' is on. 370 // ignore non private bookmarks when 'privateonly' is on.
387 if ($visibility !== 'all') { 371 if ($visibility !== 'all') {
388 if (!$link->isPrivate() && $visibility === 'private') { 372 if (!$bookmark->isPrivate() && $visibility === 'private') {
389 continue; 373 continue;
390 } elseif ($link->isPrivate() && $visibility === 'public') { 374 } elseif ($bookmark->isPrivate() && $visibility === 'public') {
391 continue; 375 continue;
392 } 376 }
393 } 377 }
394 // build search string, start with tags of current link 378 // build search string, start with tags of current link
395 $search = $link->getTagsString($tagsSeparator); 379 $search = $bookmark->getTagsString($tagsSeparator);
396 if (strlen(trim($link->getDescription())) && strpos($link->getDescription(), '#') !== false) { 380 if (strlen(trim($bookmark->getDescription())) && strpos($bookmark->getDescription(), '#') !== false) {
397 // description given and at least one possible tag found 381 // description given and at least one possible tag found
398 $descTags = []; 382 $descTags = [];
399 // find all tags in the form of #tag in the description 383 // find all tags in the form of #tag in the description
400 preg_match_all( 384 preg_match_all(
401 '/(?<![' . self::$HASHTAG_CHARS . '])#([' . self::$HASHTAG_CHARS . ']+?)\b/sm', 385 '/(?<![' . self::$HASHTAG_CHARS . '])#([' . self::$HASHTAG_CHARS . ']+?)\b/sm',
402 $link->getDescription(), 386 $bookmark->getDescription(),
403 $descTags 387 $descTags
404 ); 388 );
405 if (count($descTags[1])) { 389 if (count($descTags[1])) {
@@ -412,8 +396,9 @@ class BookmarkFilter
412 // this entry does _not_ match our regex 396 // this entry does _not_ match our regex
413 continue; 397 continue;
414 } 398 }
415 $filtered[$key] = $link; 399 $filtered[$key] = $bookmark;
416 } 400 }
401
417 return $filtered; 402 return $filtered;
418 } 403 }
419 404
@@ -427,55 +412,30 @@ class BookmarkFilter
427 public function filterUntagged(string $visibility) 412 public function filterUntagged(string $visibility)
428 { 413 {
429 $filtered = []; 414 $filtered = [];
430 foreach ($this->bookmarks as $key => $link) { 415 foreach ($this->bookmarks as $key => $bookmark) {
416 if (
417 !$this->pluginManager->filterSearchEntry(
418 $bookmark,
419 ['source' => 'untagged', 'visibility' => $visibility]
420 )
421 ) {
422 continue;
423 }
424
431 if ($visibility !== 'all') { 425 if ($visibility !== 'all') {
432 if (!$link->isPrivate() && $visibility === 'private') { 426 if (!$bookmark->isPrivate() && $visibility === 'private') {
433 continue; 427 continue;
434 } elseif ($link->isPrivate() && $visibility === 'public') { 428 } elseif ($bookmark->isPrivate() && $visibility === 'public') {
435 continue; 429 continue;
436 } 430 }
437 } 431 }
438 432
439 if (empty($link->getTags())) { 433 if (empty($bookmark->getTags())) {
440 $filtered[$key] = $link;
441 }
442 }
443
444 return $filtered;
445 }
446
447 /**
448 * Returns the list of articles for a given day, chronologically sorted
449 *
450 * Day must be in the form 'YYYYMMDD' (e.g. '20120125'), e.g.
451 * print_r($mydb->filterDay('20120125'));
452 *
453 * @param string $day day to filter.
454 * @param string $visibility return only all/private/public bookmarks.
455
456 * @return Bookmark[] all link matching given day.
457 *
458 * @throws Exception if date format is invalid.
459 */
460 public function filterDay(string $day, string $visibility)
461 {
462 if (!checkDateFormat('Ymd', $day)) {
463 throw new Exception('Invalid date format');
464 }
465
466 $filtered = [];
467 foreach ($this->bookmarks as $key => $bookmark) {
468 if ($visibility === static::$PUBLIC && $bookmark->isPrivate()) {
469 continue;
470 }
471
472 if ($bookmark->getCreated()->format('Ymd') == $day) {
473 $filtered[$key] = $bookmark; 434 $filtered[$key] = $bookmark;
474 } 435 }
475 } 436 }
476 437
477 // sort by date ASC 438 return $filtered;
478 return array_reverse($filtered, true);
479 } 439 }
480 440
481 /** 441 /**
@@ -498,6 +458,56 @@ class BookmarkFilter
498 } 458 }
499 459
500 /** 460 /**
461 * generate a regex fragment out of a tag
462 *
463 * @param string $tag to to generate regexs from. may start with '-' to negate, contain '*' as wildcard
464 *
465 * @return string generated regex fragment
466 */
467 protected function tag2regex(string $tag): string
468 {
469 $tagsSeparator = $this->conf->get('general.tags_separator', ' ');
470 $len = strlen($tag);
471 if (!$len || $tag === "-" || $tag === "*") {
472 // nothing to search, return empty regex
473 return '';
474 }
475 if ($tag[0] === "-") {
476 // query is negated
477 $i = 1; // use offset to start after '-' character
478 $regex = '(?!'; // create negative lookahead
479 } else {
480 $i = 0; // start at first character
481 $regex = '(?='; // use positive lookahead
482 }
483 // before tag may only be the separator or the beginning
484 $regex .= '.*(?:^|' . $tagsSeparator . ')';
485 // iterate over string, separating it into placeholder and content
486 for (; $i < $len; $i++) {
487 if ($tag[$i] === '*') {
488 // placeholder found
489 $regex .= '[^' . $tagsSeparator . ']*?';
490 } else {
491 // regular characters
492 $offset = strpos($tag, '*', $i);
493 if ($offset === false) {
494 // no placeholder found, set offset to end of string
495 $offset = $len;
496 }
497 // subtract one, as we want to get before the placeholder or end of string
498 $offset -= 1;
499 // we got a tag name that we want to search for. escape any regex characters to prevent conflicts.
500 $regex .= preg_quote(substr($tag, $i, $offset - $i + 1), '/');
501 // move $i on
502 $i = $offset;
503 }
504 }
505 // after the tag may only be the separator or the end
506 $regex .= '(?:$|' . $tagsSeparator . '))';
507 return $regex;
508 }
509
510 /**
501 * This method finalize the content of the foundPositions array, 511 * This method finalize the content of the foundPositions array,
502 * by associated all search results to their associated bookmark field, 512 * by associated all search results to their associated bookmark field,
503 * making sure that there is no overlapping results, etc. 513 * making sure that there is no overlapping results, etc.
diff --git a/application/container/ContainerBuilder.php b/application/container/ContainerBuilder.php
index 6d69a880..f66d75bd 100644
--- a/application/container/ContainerBuilder.php
+++ b/application/container/ContainerBuilder.php
@@ -95,6 +95,7 @@ class ContainerBuilder
95 $container['bookmarkService'] = function (ShaarliContainer $container): BookmarkServiceInterface { 95 $container['bookmarkService'] = function (ShaarliContainer $container): BookmarkServiceInterface {
96 return new BookmarkFileService( 96 return new BookmarkFileService(
97 $container->conf, 97 $container->conf,
98 $container->pluginManager,
98 $container->history, 99 $container->history,
99 new FlockMutex(fopen(SHAARLI_MUTEX_FILE, 'r'), 2), 100 new FlockMutex(fopen(SHAARLI_MUTEX_FILE, 'r'), 2),
100 $container->loginManager->isLoggedIn() 101 $container->loginManager->isLoggedIn()
diff --git a/application/plugin/PluginManager.php b/application/plugin/PluginManager.php
index 7fc0cb04..939db1ea 100644
--- a/application/plugin/PluginManager.php
+++ b/application/plugin/PluginManager.php
@@ -2,6 +2,7 @@
2 2
3namespace Shaarli\Plugin; 3namespace Shaarli\Plugin;
4 4
5use Shaarli\Bookmark\Bookmark;
5use Shaarli\Config\ConfigManager; 6use Shaarli\Config\ConfigManager;
6use Shaarli\Plugin\Exception\PluginFileNotFoundException; 7use Shaarli\Plugin\Exception\PluginFileNotFoundException;
7use Shaarli\Plugin\Exception\PluginInvalidRouteException; 8use Shaarli\Plugin\Exception\PluginInvalidRouteException;
@@ -45,6 +46,9 @@ class PluginManager
45 */ 46 */
46 protected $errors; 47 protected $errors;
47 48
49 /** @var callable[]|null Preloaded list of hook function for filterSearchEntry() */
50 protected $filterSearchEntryHooks = null;
51
48 /** 52 /**
49 * Plugins subdirectory. 53 * Plugins subdirectory.
50 * 54 *
@@ -274,6 +278,14 @@ class PluginManager
274 } 278 }
275 279
276 /** 280 /**
281 * @return array List of registered filter_search_entry hooks
282 */
283 public function getFilterSearchEntryHooks(): ?array
284 {
285 return $this->filterSearchEntryHooks;
286 }
287
288 /**
277 * Return the list of encountered errors. 289 * Return the list of encountered errors.
278 * 290 *
279 * @return array List of errors (empty array if none exists). 291 * @return array List of errors (empty array if none exists).
@@ -284,6 +296,50 @@ class PluginManager
284 } 296 }
285 297
286 /** 298 /**
299 * Apply additional filter on every search result of BookmarkFilter calling plugins hooks.
300 *
301 * @param Bookmark $bookmark To check.
302 * @param array $context Additional info about search context, depends on the search source.
303 *
304 * @return bool True if the result must be kept in search results, false otherwise.
305 */
306 public function filterSearchEntry(Bookmark $bookmark, array $context): bool
307 {
308 if ($this->filterSearchEntryHooks === null) {
309 $this->loadFilterSearchEntryHooks();
310 }
311
312 if ($this->filterSearchEntryHooks === []) {
313 return true;
314 }
315
316 foreach ($this->filterSearchEntryHooks as $filterSearchEntryHook) {
317 if ($filterSearchEntryHook($bookmark, $context) === false) {
318 return false;
319 }
320 }
321
322 return true;
323 }
324
325 /**
326 * filterSearchEntry() method will be called for every search result,
327 * so for performances we preload existing functions to invoke them directly.
328 */
329 protected function loadFilterSearchEntryHooks(): void
330 {
331 $this->filterSearchEntryHooks = [];
332
333 foreach ($this->loadedPlugins as $plugin) {
334 $hookFunction = $this->buildHookName('filter_search_entry', $plugin);
335
336 if (function_exists($hookFunction)) {
337 $this->filterSearchEntryHooks[] = $hookFunction;
338 }
339 }
340 }
341
342 /**
287 * Checks whether provided input is valid to register a new route. 343 * Checks whether provided input is valid to register a new route.
288 * It must contain keys `method`, `route`, `callable` (all strings). 344 * It must contain keys `method`, `route`, `callable` (all strings).
289 * 345 *
diff --git a/doc/md/dev/Plugin-system.md b/doc/md/dev/Plugin-system.md
index 79654011..0ada57ea 100644
--- a/doc/md/dev/Plugin-system.md
+++ b/doc/md/dev/Plugin-system.md
@@ -27,7 +27,6 @@ You should have the following tree view:
27| |---| demo_plugin.php 27| |---| demo_plugin.php
28``` 28```
29 29
30
31### Plugin initialization 30### Plugin initialization
32 31
33At the beginning of Shaarli execution, all enabled plugins are loaded. At this point, the plugin system looks for an `init()` function in the <plugin_name>.php to execute and run it if it exists. This function must be named this way, and takes the `ConfigManager` as parameter. 32At the beginning of Shaarli execution, all enabled plugins are loaded. At this point, the plugin system looks for an `init()` function in the <plugin_name>.php to execute and run it if it exists. This function must be named this way, and takes the `ConfigManager` as parameter.
@@ -209,6 +208,7 @@ If it's still not working, please [open an issue](https://github.com/shaarli/Sha
209| [save_link](#save_link) | Allow to alter the link being saved in the datastore. | 208| [save_link](#save_link) | Allow to alter the link being saved in the datastore. |
210| [delete_link](#delete_link) | Allow to do an action before a link is deleted from the datastore. | 209| [delete_link](#delete_link) | Allow to do an action before a link is deleted from the datastore. |
211| [save_plugin_parameters](#save_plugin_parameters) | Allow to manipulate plugin parameters before they're saved. | 210| [save_plugin_parameters](#save_plugin_parameters) | Allow to manipulate plugin parameters before they're saved. |
211| [filter_search_entry](#filter_search_entry) | Add custom filters to Shaarli search engine |
212 212
213 213
214#### render_header 214#### render_header
@@ -565,6 +565,23 @@ the array will contain an entry with `MYPLUGIN_PARAMETER` as a key.
565 565
566Also [special data](#special-data). 566Also [special data](#special-data).
567 567
568#### filter_search_entry
569
570Triggered for *every* bookmark when Shaarli's BookmarkService method `search()` is used.
571Any custom filter can be added to filter out bookmarks from search results.
572
573The hook **must** return either:
574 - `true` to keep bookmark entry in search result set
575 - `false` to discard bookmark entry in result set
576
577> Note: custom filters are called *before* default filters are applied.
578
579##### Parameters
580
581- `Shaarli\Bookmark\Bookmark` object: entry to evaluate
582- $context `array`: additional information provided depending on what search is currently used,
583the user request, etc.
584
568## Guide for template designers 585## Guide for template designers
569 586
570### Plugin administration 587### Plugin administration
diff --git a/plugins/demo_plugin/demo_plugin.php b/plugins/demo_plugin/demo_plugin.php
index 15cfc2c5..d89765cf 100644
--- a/plugins/demo_plugin/demo_plugin.php
+++ b/plugins/demo_plugin/demo_plugin.php
@@ -17,6 +17,7 @@ require_once __DIR__ . '/DemoPluginController.php';
17 * and check user status with _LOGGEDIN_. 17 * and check user status with _LOGGEDIN_.
18 */ 18 */
19 19
20use Shaarli\Bookmark\Bookmark;
20use Shaarli\Config\ConfigManager; 21use Shaarli\Config\ConfigManager;
21use Shaarli\Plugin\PluginManager; 22use Shaarli\Plugin\PluginManager;
22use Shaarli\Render\TemplatePage; 23use Shaarli\Render\TemplatePage;
@@ -263,6 +264,17 @@ function hook_demo_plugin_render_linklist($data)
263 } 264 }
264 $data['action_plugin'][] = $action; 265 $data['action_plugin'][] = $action;
265 266
267 // Action to trigger custom filter hiding bookmarks not containing 'e' letter in their description
268 $action = [
269 'attr' => [
270 'href' => '?e',
271 'title' => 'Hide bookmarks without "e" in their description.',
272 ],
273 'html' => 'e',
274 'on' => isset($_GET['e'])
275 ];
276 $data['action_plugin'][] = $action;
277
266 // link_plugin (for each link) 278 // link_plugin (for each link)
267 foreach ($data['links'] as &$value) { 279 foreach ($data['links'] as &$value) {
268 $value['link_plugin'][] = ' DEMO \o/'; 280 $value['link_plugin'][] = ' DEMO \o/';
@@ -487,6 +499,27 @@ function hook_demo_plugin_save_plugin_parameters($data)
487} 499}
488 500
489/** 501/**
502 * This hook is called when a search is performed, on every search entry.
503 * It allows to add custom filters, and filter out additional link.
504 *
505 * For exemple here, we hide all bookmarks not containing the letter 'e' in their description.
506 *
507 * @param Bookmark $bookmark Search entry. Note that this is a Bookmark object, and not a link array.
508 * It should NOT be altered.
509 * @param array $context Additional info on the search performed.
510 *
511 * @return bool True if the bookmark should be kept in the search result, false to discard it.
512 */
513function hook_demo_plugin_filter_search_entry(Bookmark $bookmark, array $context): bool
514{
515 if (isset($_GET['e'])) {
516 return strpos($bookmark->getDescription(), 'e') !== false;
517 }
518
519 return true;
520}
521
522/**
490 * This function is never called, but contains translation calls for GNU gettext extraction. 523 * This function is never called, but contains translation calls for GNU gettext extraction.
491 */ 524 */
492function demo_dummy_translation() 525function demo_dummy_translation()
diff --git a/tests/PluginManagerTest.php b/tests/PluginManagerTest.php
index 8947f679..75b3ae00 100644
--- a/tests/PluginManagerTest.php
+++ b/tests/PluginManagerTest.php
@@ -2,6 +2,7 @@
2 2
3namespace Shaarli\Plugin; 3namespace Shaarli\Plugin;
4 4
5use Shaarli\Bookmark\Bookmark;
5use Shaarli\Config\ConfigManager; 6use Shaarli\Config\ConfigManager;
6 7
7/** 8/**
@@ -159,4 +160,19 @@ class PluginManagerTest extends \Shaarli\TestCase
159 $errors = $this->pluginManager->getErrors(); 160 $errors = $this->pluginManager->getErrors();
160 static::assertSame(['test_route_invalid [plugin incompatibility]: trying to register invalid route.'], $errors); 161 static::assertSame(['test_route_invalid [plugin incompatibility]: trying to register invalid route.'], $errors);
161 } 162 }
163
164 public function testSearchFilterPlugin(): void
165 {
166 PluginManager::$PLUGINS_PATH = self::$pluginPath;
167 $this->pluginManager->load([self::$pluginName]);
168
169 static::assertNull($this->pluginManager->getFilterSearchEntryHooks());
170
171 static::assertTrue($this->pluginManager->filterSearchEntry(new Bookmark(), ['_result' => true]));
172
173 static::assertCount(1, $this->pluginManager->getFilterSearchEntryHooks());
174 static::assertSame('hook_test_filter_search_entry', $this->pluginManager->getFilterSearchEntryHooks()[0]);
175
176 static::assertFalse($this->pluginManager->filterSearchEntry(new Bookmark(), ['_result' => false]));
177 }
162} 178}
diff --git a/tests/api/ApiMiddlewareTest.php b/tests/api/ApiMiddlewareTest.php
index 86700840..2afac28b 100644
--- a/tests/api/ApiMiddlewareTest.php
+++ b/tests/api/ApiMiddlewareTest.php
@@ -3,6 +3,7 @@ namespace Shaarli\Api;
3 3
4use Shaarli\Config\ConfigManager; 4use Shaarli\Config\ConfigManager;
5use Shaarli\History; 5use Shaarli\History;
6use Shaarli\Plugin\PluginManager;
6use Slim\Container; 7use Slim\Container;
7use Slim\Http\Environment; 8use Slim\Http\Environment;
8use Slim\Http\Request; 9use Slim\Http\Request;
@@ -56,6 +57,7 @@ class ApiMiddlewareTest extends \Shaarli\TestCase
56 $this->container = new Container(); 57 $this->container = new Container();
57 $this->container['conf'] = $this->conf; 58 $this->container['conf'] = $this->conf;
58 $this->container['history'] = $history; 59 $this->container['history'] = $history;
60 $this->container['pluginManager'] = new PluginManager($this->conf);
59 } 61 }
60 62
61 /** 63 /**
diff --git a/tests/api/controllers/info/InfoTest.php b/tests/api/controllers/info/InfoTest.php
index 10b29ab2..2428ca43 100644
--- a/tests/api/controllers/info/InfoTest.php
+++ b/tests/api/controllers/info/InfoTest.php
@@ -5,6 +5,7 @@ use malkusch\lock\mutex\NoMutex;
5use Shaarli\Bookmark\BookmarkFileService; 5use Shaarli\Bookmark\BookmarkFileService;
6use Shaarli\Config\ConfigManager; 6use Shaarli\Config\ConfigManager;
7use Shaarli\History; 7use Shaarli\History;
8use Shaarli\Plugin\PluginManager;
8use Shaarli\TestCase; 9use Shaarli\TestCase;
9use Slim\Container; 10use Slim\Container;
10use Slim\Http\Environment; 11use Slim\Http\Environment;
@@ -55,12 +56,18 @@ class InfoTest extends TestCase
55 $this->conf->set('resource.datastore', self::$testDatastore); 56 $this->conf->set('resource.datastore', self::$testDatastore);
56 $this->refDB = new \ReferenceLinkDB(); 57 $this->refDB = new \ReferenceLinkDB();
57 $this->refDB->write(self::$testDatastore); 58 $this->refDB->write(self::$testDatastore);
58 59 $this->pluginManager = new PluginManager($this->conf);
59 $history = new History('sandbox/history.php'); 60 $history = new History('sandbox/history.php');
60 61
61 $this->container = new Container(); 62 $this->container = new Container();
62 $this->container['conf'] = $this->conf; 63 $this->container['conf'] = $this->conf;
63 $this->container['db'] = new BookmarkFileService($this->conf, $history, $mutex, true); 64 $this->container['db'] = new BookmarkFileService(
65 $this->conf,
66 $this->pluginManager,
67 $history,
68 $mutex,
69 true
70 );
64 $this->container['history'] = null; 71 $this->container['history'] = null;
65 72
66 $this->controller = new Info($this->container); 73 $this->controller = new Info($this->container);
diff --git a/tests/api/controllers/links/DeleteLinkTest.php b/tests/api/controllers/links/DeleteLinkTest.php
index 805c9be3..dc2cf917 100644
--- a/tests/api/controllers/links/DeleteLinkTest.php
+++ b/tests/api/controllers/links/DeleteLinkTest.php
@@ -7,6 +7,7 @@ use malkusch\lock\mutex\NoMutex;
7use Shaarli\Bookmark\BookmarkFileService; 7use Shaarli\Bookmark\BookmarkFileService;
8use Shaarli\Config\ConfigManager; 8use Shaarli\Config\ConfigManager;
9use Shaarli\History; 9use Shaarli\History;
10use Shaarli\Plugin\PluginManager;
10use Slim\Container; 11use Slim\Container;
11use Slim\Http\Environment; 12use Slim\Http\Environment;
12use Slim\Http\Request; 13use Slim\Http\Request;
@@ -57,6 +58,9 @@ class DeleteLinkTest extends \Shaarli\TestCase
57 /** @var NoMutex */ 58 /** @var NoMutex */
58 protected $mutex; 59 protected $mutex;
59 60
61 /** @var PluginManager */
62 protected $pluginManager;
63
60 /** 64 /**
61 * Before each test, instantiate a new Api with its config, plugins and bookmarks. 65 * Before each test, instantiate a new Api with its config, plugins and bookmarks.
62 */ 66 */
@@ -70,7 +74,14 @@ class DeleteLinkTest extends \Shaarli\TestCase
70 $refHistory = new \ReferenceHistory(); 74 $refHistory = new \ReferenceHistory();
71 $refHistory->write(self::$testHistory); 75 $refHistory->write(self::$testHistory);
72 $this->history = new History(self::$testHistory); 76 $this->history = new History(self::$testHistory);
73 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); 77 $this->pluginManager = new PluginManager($this->conf);
78 $this->bookmarkService = new BookmarkFileService(
79 $this->conf,
80 $this->pluginManager,
81 $this->history,
82 $this->mutex,
83 true
84 );
74 85
75 $this->container = new Container(); 86 $this->container = new Container();
76 $this->container['conf'] = $this->conf; 87 $this->container['conf'] = $this->conf;
@@ -105,7 +116,13 @@ class DeleteLinkTest extends \Shaarli\TestCase
105 $this->assertEquals(204, $response->getStatusCode()); 116 $this->assertEquals(204, $response->getStatusCode());
106 $this->assertEmpty((string) $response->getBody()); 117 $this->assertEmpty((string) $response->getBody());
107 118
108 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); 119 $this->bookmarkService = new BookmarkFileService(
120 $this->conf,
121 $this->pluginManager,
122 $this->history,
123 $this->mutex,
124 true
125 );
109 $this->assertFalse($this->bookmarkService->exists($id)); 126 $this->assertFalse($this->bookmarkService->exists($id));
110 127
111 $historyEntry = $this->history->getHistory()[0]; 128 $historyEntry = $this->history->getHistory()[0];
diff --git a/tests/api/controllers/links/GetLinkIdTest.php b/tests/api/controllers/links/GetLinkIdTest.php
index 1ec56ef3..c93a3b4b 100644
--- a/tests/api/controllers/links/GetLinkIdTest.php
+++ b/tests/api/controllers/links/GetLinkIdTest.php
@@ -7,6 +7,7 @@ use Shaarli\Bookmark\Bookmark;
7use Shaarli\Bookmark\BookmarkFileService; 7use Shaarli\Bookmark\BookmarkFileService;
8use Shaarli\Config\ConfigManager; 8use Shaarli\Config\ConfigManager;
9use Shaarli\History; 9use Shaarli\History;
10use Shaarli\Plugin\PluginManager;
10use Slim\Container; 11use Slim\Container;
11use Slim\Http\Environment; 12use Slim\Http\Environment;
12use Slim\Http\Request; 13use Slim\Http\Request;
@@ -67,7 +68,14 @@ class GetLinkIdTest extends \Shaarli\TestCase
67 68
68 $this->container = new Container(); 69 $this->container = new Container();
69 $this->container['conf'] = $this->conf; 70 $this->container['conf'] = $this->conf;
70 $this->container['db'] = new BookmarkFileService($this->conf, $history, $mutex, true); 71 $pluginManager = new PluginManager($this->conf);
72 $this->container['db'] = new BookmarkFileService(
73 $this->conf,
74 $pluginManager,
75 $history,
76 $mutex,
77 true
78 );
71 $this->container['history'] = null; 79 $this->container['history'] = null;
72 80
73 $this->controller = new Links($this->container); 81 $this->controller = new Links($this->container);
diff --git a/tests/api/controllers/links/GetLinksTest.php b/tests/api/controllers/links/GetLinksTest.php
index b1c46ee2..3c966732 100644
--- a/tests/api/controllers/links/GetLinksTest.php
+++ b/tests/api/controllers/links/GetLinksTest.php
@@ -7,6 +7,7 @@ use Shaarli\Bookmark\BookmarkFileService;
7use Shaarli\Bookmark\LinkDB; 7use Shaarli\Bookmark\LinkDB;
8use Shaarli\Config\ConfigManager; 8use Shaarli\Config\ConfigManager;
9use Shaarli\History; 9use Shaarli\History;
10use Shaarli\Plugin\PluginManager;
10use Slim\Container; 11use Slim\Container;
11use Slim\Http\Environment; 12use Slim\Http\Environment;
12use Slim\Http\Request; 13use Slim\Http\Request;
@@ -67,7 +68,14 @@ class GetLinksTest extends \Shaarli\TestCase
67 68
68 $this->container = new Container(); 69 $this->container = new Container();
69 $this->container['conf'] = $this->conf; 70 $this->container['conf'] = $this->conf;
70 $this->container['db'] = new BookmarkFileService($this->conf, $history, $mutex, true); 71 $pluginManager = new PluginManager($this->conf);
72 $this->container['db'] = new BookmarkFileService(
73 $this->conf,
74 $pluginManager,
75 $history,
76 $mutex,
77 true
78 );
71 $this->container['history'] = null; 79 $this->container['history'] = null;
72 80
73 $this->controller = new Links($this->container); 81 $this->controller = new Links($this->container);
diff --git a/tests/api/controllers/links/PostLinkTest.php b/tests/api/controllers/links/PostLinkTest.php
index f755e2d2..a54e4a16 100644
--- a/tests/api/controllers/links/PostLinkTest.php
+++ b/tests/api/controllers/links/PostLinkTest.php
@@ -7,6 +7,7 @@ use Shaarli\Bookmark\Bookmark;
7use Shaarli\Bookmark\BookmarkFileService; 7use Shaarli\Bookmark\BookmarkFileService;
8use Shaarli\Config\ConfigManager; 8use Shaarli\Config\ConfigManager;
9use Shaarli\History; 9use Shaarli\History;
10use Shaarli\Plugin\PluginManager;
10use Shaarli\TestCase; 11use Shaarli\TestCase;
11use Slim\Container; 12use Slim\Container;
12use Slim\Http\Environment; 13use Slim\Http\Environment;
@@ -81,8 +82,14 @@ class PostLinkTest extends TestCase
81 $refHistory = new \ReferenceHistory(); 82 $refHistory = new \ReferenceHistory();
82 $refHistory->write(self::$testHistory); 83 $refHistory->write(self::$testHistory);
83 $this->history = new History(self::$testHistory); 84 $this->history = new History(self::$testHistory);
84 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $mutex, true); 85 $pluginManager = new PluginManager($this->conf);
85 86 $this->bookmarkService = new BookmarkFileService(
87 $this->conf,
88 $pluginManager,
89 $this->history,
90 $mutex,
91 true
92 );
86 $this->container = new Container(); 93 $this->container = new Container();
87 $this->container['conf'] = $this->conf; 94 $this->container['conf'] = $this->conf;
88 $this->container['db'] = $this->bookmarkService; 95 $this->container['db'] = $this->bookmarkService;
diff --git a/tests/api/controllers/links/PutLinkTest.php b/tests/api/controllers/links/PutLinkTest.php
index fe24f2eb..ed14d5f8 100644
--- a/tests/api/controllers/links/PutLinkTest.php
+++ b/tests/api/controllers/links/PutLinkTest.php
@@ -8,6 +8,7 @@ use Shaarli\Bookmark\Bookmark;
8use Shaarli\Bookmark\BookmarkFileService; 8use Shaarli\Bookmark\BookmarkFileService;
9use Shaarli\Config\ConfigManager; 9use Shaarli\Config\ConfigManager;
10use Shaarli\History; 10use Shaarli\History;
11use Shaarli\Plugin\PluginManager;
11use Slim\Container; 12use Slim\Container;
12use Slim\Http\Environment; 13use Slim\Http\Environment;
13use Slim\Http\Request; 14use Slim\Http\Request;
@@ -73,8 +74,14 @@ class PutLinkTest extends \Shaarli\TestCase
73 $refHistory = new \ReferenceHistory(); 74 $refHistory = new \ReferenceHistory();
74 $refHistory->write(self::$testHistory); 75 $refHistory->write(self::$testHistory);
75 $this->history = new History(self::$testHistory); 76 $this->history = new History(self::$testHistory);
76 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $mutex, true); 77 $pluginManager = new PluginManager($this->conf);
77 78 $this->bookmarkService = new BookmarkFileService(
79 $this->conf,
80 $pluginManager,
81 $this->history,
82 $mutex,
83 true
84 );
78 $this->container = new Container(); 85 $this->container = new Container();
79 $this->container['conf'] = $this->conf; 86 $this->container['conf'] = $this->conf;
80 $this->container['db'] = $this->bookmarkService; 87 $this->container['db'] = $this->bookmarkService;
diff --git a/tests/api/controllers/tags/DeleteTagTest.php b/tests/api/controllers/tags/DeleteTagTest.php
index 37f07229..c0f8a6a9 100644
--- a/tests/api/controllers/tags/DeleteTagTest.php
+++ b/tests/api/controllers/tags/DeleteTagTest.php
@@ -8,6 +8,7 @@ use Shaarli\Bookmark\BookmarkFileService;
8use Shaarli\Bookmark\LinkDB; 8use Shaarli\Bookmark\LinkDB;
9use Shaarli\Config\ConfigManager; 9use Shaarli\Config\ConfigManager;
10use Shaarli\History; 10use Shaarli\History;
11use Shaarli\Plugin\PluginManager;
11use Slim\Container; 12use Slim\Container;
12use Slim\Http\Environment; 13use Slim\Http\Environment;
13use Slim\Http\Request; 14use Slim\Http\Request;
@@ -55,6 +56,9 @@ class DeleteTagTest extends \Shaarli\TestCase
55 */ 56 */
56 protected $controller; 57 protected $controller;
57 58
59 /** @var PluginManager */
60 protected $pluginManager;
61
58 /** @var NoMutex */ 62 /** @var NoMutex */
59 protected $mutex; 63 protected $mutex;
60 64
@@ -71,7 +75,14 @@ class DeleteTagTest extends \Shaarli\TestCase
71 $refHistory = new \ReferenceHistory(); 75 $refHistory = new \ReferenceHistory();
72 $refHistory->write(self::$testHistory); 76 $refHistory->write(self::$testHistory);
73 $this->history = new History(self::$testHistory); 77 $this->history = new History(self::$testHistory);
74 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); 78 $this->pluginManager = new PluginManager($this->conf);
79 $this->bookmarkService = new BookmarkFileService(
80 $this->conf,
81 $this->pluginManager,
82 $this->history,
83 $this->mutex,
84 true
85 );
75 86
76 $this->container = new Container(); 87 $this->container = new Container();
77 $this->container['conf'] = $this->conf; 88 $this->container['conf'] = $this->conf;
@@ -107,7 +118,13 @@ class DeleteTagTest extends \Shaarli\TestCase
107 $this->assertEquals(204, $response->getStatusCode()); 118 $this->assertEquals(204, $response->getStatusCode());
108 $this->assertEmpty((string) $response->getBody()); 119 $this->assertEmpty((string) $response->getBody());
109 120
110 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); 121 $this->bookmarkService = new BookmarkFileService(
122 $this->conf,
123 $this->pluginManager,
124 $this->history,
125 $this->mutex,
126 true
127 );
111 $tags = $this->bookmarkService->bookmarksCountPerTag(); 128 $tags = $this->bookmarkService->bookmarksCountPerTag();
112 $this->assertFalse(isset($tags[$tagName])); 129 $this->assertFalse(isset($tags[$tagName]));
113 130
@@ -141,7 +158,13 @@ class DeleteTagTest extends \Shaarli\TestCase
141 $this->assertEquals(204, $response->getStatusCode()); 158 $this->assertEquals(204, $response->getStatusCode());
142 $this->assertEmpty((string) $response->getBody()); 159 $this->assertEmpty((string) $response->getBody());
143 160
144 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); 161 $this->bookmarkService = new BookmarkFileService(
162 $this->conf,
163 $this->pluginManager,
164 $this->history,
165 $this->mutex,
166 true
167 );
145 $tags = $this->bookmarkService->bookmarksCountPerTag(); 168 $tags = $this->bookmarkService->bookmarksCountPerTag();
146 $this->assertFalse(isset($tags[$tagName])); 169 $this->assertFalse(isset($tags[$tagName]));
147 $this->assertTrue($tags[strtolower($tagName)] > 0); 170 $this->assertTrue($tags[strtolower($tagName)] > 0);
diff --git a/tests/api/controllers/tags/GetTagNameTest.php b/tests/api/controllers/tags/GetTagNameTest.php
index 878de5a4..0ad71495 100644
--- a/tests/api/controllers/tags/GetTagNameTest.php
+++ b/tests/api/controllers/tags/GetTagNameTest.php
@@ -7,6 +7,7 @@ use Shaarli\Bookmark\BookmarkFileService;
7use Shaarli\Bookmark\LinkDB; 7use Shaarli\Bookmark\LinkDB;
8use Shaarli\Config\ConfigManager; 8use Shaarli\Config\ConfigManager;
9use Shaarli\History; 9use Shaarli\History;
10use Shaarli\Plugin\PluginManager;
10use Slim\Container; 11use Slim\Container;
11use Slim\Http\Environment; 12use Slim\Http\Environment;
12use Slim\Http\Request; 13use Slim\Http\Request;
@@ -46,6 +47,9 @@ class GetTagNameTest extends \Shaarli\TestCase
46 */ 47 */
47 protected $controller; 48 protected $controller;
48 49
50 /** @var PluginManager */
51 protected $pluginManager;
52
49 /** 53 /**
50 * Number of JSON fields per link. 54 * Number of JSON fields per link.
51 */ 55 */
@@ -65,7 +69,14 @@ class GetTagNameTest extends \Shaarli\TestCase
65 69
66 $this->container = new Container(); 70 $this->container = new Container();
67 $this->container['conf'] = $this->conf; 71 $this->container['conf'] = $this->conf;
68 $this->container['db'] = new BookmarkFileService($this->conf, $history, $mutex, true); 72 $this->pluginManager = new PluginManager($this->conf);
73 $this->container['db'] = new BookmarkFileService(
74 $this->conf,
75 $this->pluginManager,
76 $history,
77 $mutex,
78 true
79 );
69 $this->container['history'] = null; 80 $this->container['history'] = null;
70 81
71 $this->controller = new Tags($this->container); 82 $this->controller = new Tags($this->container);
diff --git a/tests/api/controllers/tags/GetTagsTest.php b/tests/api/controllers/tags/GetTagsTest.php
index b565a8c4..a4b62c51 100644
--- a/tests/api/controllers/tags/GetTagsTest.php
+++ b/tests/api/controllers/tags/GetTagsTest.php
@@ -6,6 +6,7 @@ use Shaarli\Bookmark\BookmarkFileService;
6use Shaarli\Bookmark\LinkDB; 6use Shaarli\Bookmark\LinkDB;
7use Shaarli\Config\ConfigManager; 7use Shaarli\Config\ConfigManager;
8use Shaarli\History; 8use Shaarli\History;
9use Shaarli\Plugin\PluginManager;
9use Slim\Container; 10use Slim\Container;
10use Slim\Http\Environment; 11use Slim\Http\Environment;
11use Slim\Http\Request; 12use Slim\Http\Request;
@@ -50,6 +51,9 @@ class GetTagsTest extends \Shaarli\TestCase
50 */ 51 */
51 protected $controller; 52 protected $controller;
52 53
54 /** @var PluginManager */
55 protected $pluginManager;
56
53 /** 57 /**
54 * Number of JSON field per link. 58 * Number of JSON field per link.
55 */ 59 */
@@ -66,9 +70,14 @@ class GetTagsTest extends \Shaarli\TestCase
66 $this->refDB = new \ReferenceLinkDB(); 70 $this->refDB = new \ReferenceLinkDB();
67 $this->refDB->write(self::$testDatastore); 71 $this->refDB->write(self::$testDatastore);
68 $history = new History('sandbox/history.php'); 72 $history = new History('sandbox/history.php');
69 73 $this->pluginManager = new PluginManager($this->conf);
70 $this->bookmarkService = new BookmarkFileService($this->conf, $history, $mutex, true); 74 $this->bookmarkService = new BookmarkFileService(
71 75 $this->conf,
76 $this->pluginManager,
77 $history,
78 $mutex,
79 true
80 );
72 $this->container = new Container(); 81 $this->container = new Container();
73 $this->container['conf'] = $this->conf; 82 $this->container['conf'] = $this->conf;
74 $this->container['db'] = $this->bookmarkService; 83 $this->container['db'] = $this->bookmarkService;
diff --git a/tests/api/controllers/tags/PutTagTest.php b/tests/api/controllers/tags/PutTagTest.php
index c73f6d3b..045473e6 100644
--- a/tests/api/controllers/tags/PutTagTest.php
+++ b/tests/api/controllers/tags/PutTagTest.php
@@ -8,6 +8,7 @@ use Shaarli\Bookmark\BookmarkFileService;
8use Shaarli\Bookmark\LinkDB; 8use Shaarli\Bookmark\LinkDB;
9use Shaarli\Config\ConfigManager; 9use Shaarli\Config\ConfigManager;
10use Shaarli\History; 10use Shaarli\History;
11use Shaarli\Plugin\PluginManager;
11use Slim\Container; 12use Slim\Container;
12use Slim\Http\Environment; 13use Slim\Http\Environment;
13use Slim\Http\Request; 14use Slim\Http\Request;
@@ -55,6 +56,9 @@ class PutTagTest extends \Shaarli\TestCase
55 */ 56 */
56 protected $controller; 57 protected $controller;
57 58
59 /** @var PluginManager */
60 protected $pluginManager;
61
58 /** 62 /**
59 * Number of JSON field per link. 63 * Number of JSON field per link.
60 */ 64 */
@@ -73,7 +77,14 @@ class PutTagTest extends \Shaarli\TestCase
73 $refHistory = new \ReferenceHistory(); 77 $refHistory = new \ReferenceHistory();
74 $refHistory->write(self::$testHistory); 78 $refHistory->write(self::$testHistory);
75 $this->history = new History(self::$testHistory); 79 $this->history = new History(self::$testHistory);
76 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $mutex, true); 80 $this->pluginManager = new PluginManager($this->conf);
81 $this->bookmarkService = new BookmarkFileService(
82 $this->conf,
83 $this->pluginManager,
84 $this->history,
85 $mutex,
86 true
87 );
77 88
78 $this->container = new Container(); 89 $this->container = new Container();
79 $this->container['conf'] = $this->conf; 90 $this->container['conf'] = $this->conf;
diff --git a/tests/bookmark/BookmarkFileServiceTest.php b/tests/bookmark/BookmarkFileServiceTest.php
index d1af3fb0..1d250719 100644
--- a/tests/bookmark/BookmarkFileServiceTest.php
+++ b/tests/bookmark/BookmarkFileServiceTest.php
@@ -14,6 +14,7 @@ use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
14use Shaarli\Config\ConfigManager; 14use Shaarli\Config\ConfigManager;
15use Shaarli\Formatter\BookmarkMarkdownFormatter; 15use Shaarli\Formatter\BookmarkMarkdownFormatter;
16use Shaarli\History; 16use Shaarli\History;
17use Shaarli\Plugin\PluginManager;
17use Shaarli\TestCase; 18use Shaarli\TestCase;
18 19
19/** 20/**
@@ -56,6 +57,9 @@ class BookmarkFileServiceTest extends TestCase
56 /** @var NoMutex */ 57 /** @var NoMutex */
57 protected $mutex; 58 protected $mutex;
58 59
60 /** @var PluginManager */
61 protected $pluginManager;
62
59 /** 63 /**
60 * Instantiates public and private LinkDBs with test data 64 * Instantiates public and private LinkDBs with test data
61 * 65 *
@@ -93,8 +97,21 @@ class BookmarkFileServiceTest extends TestCase
93 $this->refDB = new \ReferenceLinkDB(); 97 $this->refDB = new \ReferenceLinkDB();
94 $this->refDB->write(self::$testDatastore); 98 $this->refDB->write(self::$testDatastore);
95 $this->history = new History('sandbox/history.php'); 99 $this->history = new History('sandbox/history.php');
96 $this->publicLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, false); 100 $this->pluginManager = new PluginManager($this->conf);
97 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); 101 $this->publicLinkDB = new BookmarkFileService(
102 $this->conf,
103 $this->pluginManager,
104 $this->history,
105 $this->mutex,
106 false
107 );
108 $this->privateLinkDB = new BookmarkFileService(
109 $this->conf,
110 $this->pluginManager,
111 $this->history,
112 $this->mutex,
113 true
114 );
98 } 115 }
99 116
100 /** 117 /**
@@ -111,7 +128,13 @@ class BookmarkFileServiceTest extends TestCase
111 $db = self::getMethod('migrate'); 128 $db = self::getMethod('migrate');
112 $db->invokeArgs($this->privateLinkDB, []); 129 $db->invokeArgs($this->privateLinkDB, []);
113 130
114 $db = new \FakeBookmarkService($this->conf, $this->history, $this->mutex, true); 131 $db = new \FakeBookmarkService(
132 $this->conf,
133 $this->pluginManager,
134 $this->history,
135 $this->mutex,
136 true
137 );
115 $this->assertInstanceOf(BookmarkArray::class, $db->getBookmarks()); 138 $this->assertInstanceOf(BookmarkArray::class, $db->getBookmarks());
116 $this->assertEquals($this->refDB->countLinks(), $db->count()); 139 $this->assertEquals($this->refDB->countLinks(), $db->count());
117 } 140 }
@@ -180,7 +203,13 @@ class BookmarkFileServiceTest extends TestCase
180 $this->assertEquals($updated, $bookmark->getUpdated()); 203 $this->assertEquals($updated, $bookmark->getUpdated());
181 204
182 // reload from file 205 // reload from file
183 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); 206 $this->privateLinkDB = new \FakeBookmarkService(
207 $this->conf,
208 $this->pluginManager,
209 $this->history,
210 $this->mutex,
211 true
212 );
184 213
185 $bookmark = $this->privateLinkDB->get(43); 214 $bookmark = $this->privateLinkDB->get(43);
186 $this->assertEquals(43, $bookmark->getId()); 215 $this->assertEquals(43, $bookmark->getId());
@@ -218,7 +247,13 @@ class BookmarkFileServiceTest extends TestCase
218 $this->assertNull($bookmark->getUpdated()); 247 $this->assertNull($bookmark->getUpdated());
219 248
220 // reload from file 249 // reload from file
221 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); 250 $this->privateLinkDB = new BookmarkFileService(
251 $this->conf,
252 $this->pluginManager,
253 $this->history,
254 $this->mutex,
255 true
256 );
222 257
223 $bookmark = $this->privateLinkDB->get(43); 258 $bookmark = $this->privateLinkDB->get(43);
224 $this->assertEquals(43, $bookmark->getId()); 259 $this->assertEquals(43, $bookmark->getId());
@@ -248,7 +283,13 @@ class BookmarkFileServiceTest extends TestCase
248 $this->assertEquals(43, $bookmark->getId()); 283 $this->assertEquals(43, $bookmark->getId());
249 284
250 // reload from file 285 // reload from file
251 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); 286 $this->privateLinkDB = new BookmarkFileService(
287 $this->conf,
288 $this->pluginManager,
289 $this->history,
290 $this->mutex,
291 true
292 );
252 293
253 $this->privateLinkDB->get(43); 294 $this->privateLinkDB->get(43);
254 } 295 }
@@ -309,7 +350,13 @@ class BookmarkFileServiceTest extends TestCase
309 $this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getUpdated()); 350 $this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getUpdated());
310 351
311 // reload from file 352 // reload from file
312 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); 353 $this->privateLinkDB = new BookmarkFileService(
354 $this->conf,
355 $this->pluginManager,
356 $this->history,
357 $this->mutex,
358 true
359 );
313 360
314 $bookmark = $this->privateLinkDB->get(42); 361 $bookmark = $this->privateLinkDB->get(42);
315 $this->assertEquals(42, $bookmark->getId()); 362 $this->assertEquals(42, $bookmark->getId());
@@ -350,7 +397,13 @@ class BookmarkFileServiceTest extends TestCase
350 $this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getUpdated()); 397 $this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getUpdated());
351 398
352 // reload from file 399 // reload from file
353 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); 400 $this->privateLinkDB = new BookmarkFileService(
401 $this->conf,
402 $this->pluginManager,
403 $this->history,
404 $this->mutex,
405 true
406 );
354 407
355 $bookmark = $this->privateLinkDB->get(42); 408 $bookmark = $this->privateLinkDB->get(42);
356 $this->assertEquals(42, $bookmark->getId()); 409 $this->assertEquals(42, $bookmark->getId());
@@ -383,7 +436,13 @@ class BookmarkFileServiceTest extends TestCase
383 $this->assertEquals($title, $bookmark->getTitle()); 436 $this->assertEquals($title, $bookmark->getTitle());
384 437
385 // reload from file 438 // reload from file
386 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); 439 $this->privateLinkDB = new BookmarkFileService(
440 $this->conf,
441 $this->pluginManager,
442 $this->history,
443 $this->mutex,
444 true
445 );
387 446
388 $bookmark = $this->privateLinkDB->get(42); 447 $bookmark = $this->privateLinkDB->get(42);
389 $this->assertEquals(42, $bookmark->getId()); 448 $this->assertEquals(42, $bookmark->getId());
@@ -436,7 +495,13 @@ class BookmarkFileServiceTest extends TestCase
436 $this->assertEquals(43, $bookmark->getId()); 495 $this->assertEquals(43, $bookmark->getId());
437 496
438 // reload from file 497 // reload from file
439 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); 498 $this->privateLinkDB = new BookmarkFileService(
499 $this->conf,
500 $this->pluginManager,
501 $this->history,
502 $this->mutex,
503 true
504 );
440 505
441 $bookmark = $this->privateLinkDB->get(43); 506 $bookmark = $this->privateLinkDB->get(43);
442 $this->assertEquals(43, $bookmark->getId()); 507 $this->assertEquals(43, $bookmark->getId());
@@ -456,7 +521,13 @@ class BookmarkFileServiceTest extends TestCase
456 $this->assertEquals($title, $bookmark->getTitle()); 521 $this->assertEquals($title, $bookmark->getTitle());
457 522
458 // reload from file 523 // reload from file
459 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); 524 $this->privateLinkDB = new BookmarkFileService(
525 $this->conf,
526 $this->pluginManager,
527 $this->history,
528 $this->mutex,
529 true
530 );
460 531
461 $bookmark = $this->privateLinkDB->get(42); 532 $bookmark = $this->privateLinkDB->get(42);
462 $this->assertEquals(42, $bookmark->getId()); 533 $this->assertEquals(42, $bookmark->getId());
@@ -488,7 +559,13 @@ class BookmarkFileServiceTest extends TestCase
488 $this->assertEquals($title, $bookmark->getTitle()); 559 $this->assertEquals($title, $bookmark->getTitle());
489 560
490 // reload from file 561 // reload from file
491 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); 562 $this->privateLinkDB = new BookmarkFileService(
563 $this->conf,
564 $this->pluginManager,
565 $this->history,
566 $this->mutex,
567 true
568 );
492 569
493 $bookmark = $this->privateLinkDB->get(42); 570 $bookmark = $this->privateLinkDB->get(42);
494 $this->assertEquals(42, $bookmark->getId()); 571 $this->assertEquals(42, $bookmark->getId());
@@ -514,7 +591,13 @@ class BookmarkFileServiceTest extends TestCase
514 $this->assertInstanceOf(BookmarkNotFoundException::class, $exception); 591 $this->assertInstanceOf(BookmarkNotFoundException::class, $exception);
515 592
516 // reload from file 593 // reload from file
517 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); 594 $this->privateLinkDB = new BookmarkFileService(
595 $this->conf,
596 $this->pluginManager,
597 $this->history,
598 $this->mutex,
599 true
600 );
518 601
519 $this->privateLinkDB->get(42); 602 $this->privateLinkDB->get(42);
520 } 603 }
@@ -607,7 +690,7 @@ class BookmarkFileServiceTest extends TestCase
607 690
608 $conf = new ConfigManager('tests/utils/config/configJson'); 691 $conf = new ConfigManager('tests/utils/config/configJson');
609 $conf->set('resource.datastore', 'null/store.db'); 692 $conf->set('resource.datastore', 'null/store.db');
610 new BookmarkFileService($conf, $this->history, $this->mutex, true); 693 new BookmarkFileService($conf, $this->pluginManager, $this->history, $this->mutex, true);
611 } 694 }
612 695
613 /** 696 /**
@@ -617,7 +700,7 @@ class BookmarkFileServiceTest extends TestCase
617 { 700 {
618 unlink(self::$testDatastore); 701 unlink(self::$testDatastore);
619 $this->assertFileNotExists(self::$testDatastore); 702 $this->assertFileNotExists(self::$testDatastore);
620 new BookmarkFileService($this->conf, $this->history, $this->mutex, true); 703 new BookmarkFileService($this->conf, $this->pluginManager, $this->history, $this->mutex, true);
621 $this->assertFileExists(self::$testDatastore); 704 $this->assertFileExists(self::$testDatastore);
622 705
623 // ensure the correct data has been written 706 // ensure the correct data has been written
@@ -631,7 +714,7 @@ class BookmarkFileServiceTest extends TestCase
631 { 714 {
632 unlink(self::$testDatastore); 715 unlink(self::$testDatastore);
633 $this->assertFileNotExists(self::$testDatastore); 716 $this->assertFileNotExists(self::$testDatastore);
634 $db = new \FakeBookmarkService($this->conf, $this->history, $this->mutex, false); 717 $db = new \FakeBookmarkService($this->conf, $this->pluginManager, $this->history, $this->mutex, false);
635 $this->assertFileNotExists(self::$testDatastore); 718 $this->assertFileNotExists(self::$testDatastore);
636 $this->assertInstanceOf(BookmarkArray::class, $db->getBookmarks()); 719 $this->assertInstanceOf(BookmarkArray::class, $db->getBookmarks());
637 $this->assertCount(0, $db->getBookmarks()); 720 $this->assertCount(0, $db->getBookmarks());
@@ -664,13 +747,13 @@ class BookmarkFileServiceTest extends TestCase
664 */ 747 */
665 public function testSave() 748 public function testSave()
666 { 749 {
667 $testDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); 750 $testDB = new BookmarkFileService($this->conf, $this->pluginManager, $this->history, $this->mutex, true);
668 $dbSize = $testDB->count(); 751 $dbSize = $testDB->count();
669 752
670 $bookmark = new Bookmark(); 753 $bookmark = new Bookmark();
671 $testDB->add($bookmark); 754 $testDB->add($bookmark);
672 755
673 $testDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); 756 $testDB = new BookmarkFileService($this->conf, $this->pluginManager, $this->history, $this->mutex, true);
674 $this->assertEquals($dbSize + 1, $testDB->count()); 757 $this->assertEquals($dbSize + 1, $testDB->count());
675 } 758 }
676 759
@@ -680,7 +763,7 @@ class BookmarkFileServiceTest extends TestCase
680 public function testCountHiddenPublic() 763 public function testCountHiddenPublic()
681 { 764 {
682 $this->conf->set('privacy.hide_public_links', true); 765 $this->conf->set('privacy.hide_public_links', true);
683 $linkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, false); 766 $linkDB = new BookmarkFileService($this->conf, $this->pluginManager, $this->history, $this->mutex, false);
684 767
685 $this->assertEquals(0, $linkDB->count()); 768 $this->assertEquals(0, $linkDB->count());
686 } 769 }
@@ -906,7 +989,13 @@ class BookmarkFileServiceTest extends TestCase
906 $bookmark->addAdditionalContentEntry('private_key', $privateKey); 989 $bookmark->addAdditionalContentEntry('private_key', $privateKey);
907 $this->privateLinkDB->save(); 990 $this->privateLinkDB->save();
908 991
909 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, false); 992 $this->privateLinkDB = new BookmarkFileService(
993 $this->conf,
994 $this->pluginManager,
995 $this->history,
996 $this->mutex,
997 false
998 );
910 $bookmark = $this->privateLinkDB->findByHash($hash, $privateKey); 999 $bookmark = $this->privateLinkDB->findByHash($hash, $privateKey);
911 1000
912 static::assertSame(6, $bookmark->getId()); 1001 static::assertSame(6, $bookmark->getId());
@@ -1152,7 +1241,13 @@ class BookmarkFileServiceTest extends TestCase
1152 public function testGetLatestEmptyDatastore(): void 1241 public function testGetLatestEmptyDatastore(): void
1153 { 1242 {
1154 unlink($this->conf->get('resource.datastore')); 1243 unlink($this->conf->get('resource.datastore'));
1155 $this->publicLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, false); 1244 $this->publicLinkDB = new BookmarkFileService(
1245 $this->conf,
1246 $this->pluginManager,
1247 $this->history,
1248 $this->mutex,
1249 false
1250 );
1156 1251
1157 $bookmark = $this->publicLinkDB->getLatest(); 1252 $bookmark = $this->publicLinkDB->getLatest();
1158 1253
diff --git a/tests/bookmark/BookmarkFilterTest.php b/tests/bookmark/BookmarkFilterTest.php
index 835674f2..79be807d 100644
--- a/tests/bookmark/BookmarkFilterTest.php
+++ b/tests/bookmark/BookmarkFilterTest.php
@@ -6,6 +6,7 @@ use malkusch\lock\mutex\NoMutex;
6use ReferenceLinkDB; 6use ReferenceLinkDB;
7use Shaarli\Config\ConfigManager; 7use Shaarli\Config\ConfigManager;
8use Shaarli\History; 8use Shaarli\History;
9use Shaarli\Plugin\PluginManager;
9use Shaarli\TestCase; 10use Shaarli\TestCase;
10 11
11/** 12/**
@@ -32,19 +33,24 @@ class BookmarkFilterTest extends TestCase
32 */ 33 */
33 protected static $bookmarkService; 34 protected static $bookmarkService;
34 35
36 /** @var PluginManager */
37 protected static $pluginManager;
38
35 /** 39 /**
36 * Instantiate linkFilter with ReferenceLinkDB data. 40 * Instantiate linkFilter with ReferenceLinkDB data.
37 */ 41 */
38 public static function setUpBeforeClass(): void 42 public static function setUpBeforeClass(): void
39 { 43 {
44
40 $mutex = new NoMutex(); 45 $mutex = new NoMutex();
41 $conf = new ConfigManager('tests/utils/config/configJson'); 46 $conf = new ConfigManager('tests/utils/config/configJson');
42 $conf->set('resource.datastore', self::$testDatastore); 47 $conf->set('resource.datastore', self::$testDatastore);
48 static::$pluginManager = new PluginManager($conf);
43 self::$refDB = new \ReferenceLinkDB(); 49 self::$refDB = new \ReferenceLinkDB();
44 self::$refDB->write(self::$testDatastore); 50 self::$refDB->write(self::$testDatastore);
45 $history = new History('sandbox/history.php'); 51 $history = new History('sandbox/history.php');
46 self::$bookmarkService = new \FakeBookmarkService($conf, $history, $mutex, true); 52 self::$bookmarkService = new \FakeBookmarkService($conf, static::$pluginManager, $history, $mutex, true);
47 self::$linkFilter = new BookmarkFilter(self::$bookmarkService->getBookmarks(), $conf); 53 self::$linkFilter = new BookmarkFilter(self::$bookmarkService->getBookmarks(), $conf, static::$pluginManager);
48 } 54 }
49 55
50 /** 56 /**
@@ -179,61 +185,6 @@ class BookmarkFilterTest extends TestCase
179 } 185 }
180 186
181 /** 187 /**
182 * Return bookmarks for a given day
183 */
184 public function testFilterDay()
185 {
186 $this->assertEquals(
187 4,
188 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, '20121206'))
189 );
190 }
191
192 /**
193 * Return bookmarks for a given day
194 */
195 public function testFilterDayRestrictedVisibility(): void
196 {
197 $this->assertEquals(
198 3,
199 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, '20121206', false, BookmarkFilter::$PUBLIC))
200 );
201 }
202
203 /**
204 * 404 - day not found
205 */
206 public function testFilterUnknownDay()
207 {
208 $this->assertEquals(
209 0,
210 count(self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, '19700101'))
211 );
212 }
213
214 /**
215 * Use an invalid date format
216 */
217 public function testFilterInvalidDayWithChars()
218 {
219 $this->expectException(\Exception::class);
220 $this->expectExceptionMessageRegExp('/Invalid date format/');
221
222 self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, 'Rainy day, dream away');
223 }
224
225 /**
226 * Use an invalid date format
227 */
228 public function testFilterInvalidDayDigits()
229 {
230 $this->expectException(\Exception::class);
231 $this->expectExceptionMessageRegExp('/Invalid date format/');
232
233 self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, '20');
234 }
235
236 /**
237 * Retrieve a link entry with its hash 188 * Retrieve a link entry with its hash
238 */ 189 */
239 public function testFilterSmallHash() 190 public function testFilterSmallHash()
diff --git a/tests/bookmark/BookmarkInitializerTest.php b/tests/bookmark/BookmarkInitializerTest.php
index 0c8420ce..351807c1 100644
--- a/tests/bookmark/BookmarkInitializerTest.php
+++ b/tests/bookmark/BookmarkInitializerTest.php
@@ -5,6 +5,7 @@ namespace Shaarli\Bookmark;
5use malkusch\lock\mutex\NoMutex; 5use malkusch\lock\mutex\NoMutex;
6use Shaarli\Config\ConfigManager; 6use Shaarli\Config\ConfigManager;
7use Shaarli\History; 7use Shaarli\History;
8use Shaarli\Plugin\PluginManager;
8use Shaarli\TestCase; 9use Shaarli\TestCase;
9 10
10/** 11/**
@@ -38,6 +39,9 @@ class BookmarkInitializerTest extends TestCase
38 /** @var NoMutex */ 39 /** @var NoMutex */
39 protected $mutex; 40 protected $mutex;
40 41
42 /** @var PluginManager */
43 protected $pluginManager;
44
41 /** 45 /**
42 * Initialize an empty BookmarkFileService 46 * Initialize an empty BookmarkFileService
43 */ 47 */
@@ -51,8 +55,15 @@ class BookmarkInitializerTest extends TestCase
51 copy('tests/utils/config/configJson.json.php', self::$testConf .'.json.php'); 55 copy('tests/utils/config/configJson.json.php', self::$testConf .'.json.php');
52 $this->conf = new ConfigManager(self::$testConf); 56 $this->conf = new ConfigManager(self::$testConf);
53 $this->conf->set('resource.datastore', self::$testDatastore); 57 $this->conf->set('resource.datastore', self::$testDatastore);
58 $this->pluginManager = new PluginManager($this->conf);
54 $this->history = new History('sandbox/history.php'); 59 $this->history = new History('sandbox/history.php');
55 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); 60 $this->bookmarkService = new BookmarkFileService(
61 $this->conf,
62 $this->pluginManager,
63 $this->history,
64 $this->mutex,
65 true
66 );
56 67
57 $this->initializer = new BookmarkInitializer($this->bookmarkService); 68 $this->initializer = new BookmarkInitializer($this->bookmarkService);
58 } 69 }
@@ -64,7 +75,13 @@ class BookmarkInitializerTest extends TestCase
64 { 75 {
65 $refDB = new \ReferenceLinkDB(); 76 $refDB = new \ReferenceLinkDB();
66 $refDB->write(self::$testDatastore); 77 $refDB->write(self::$testDatastore);
67 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); 78 $this->bookmarkService = new BookmarkFileService(
79 $this->conf,
80 $this->pluginManager,
81 $this->history,
82 $this->mutex,
83 true
84 );
68 $this->initializer = new BookmarkInitializer($this->bookmarkService); 85 $this->initializer = new BookmarkInitializer($this->bookmarkService);
69 86
70 $this->initializer->initialize(); 87 $this->initializer->initialize();
@@ -95,7 +112,13 @@ class BookmarkInitializerTest extends TestCase
95 $this->bookmarkService->save(); 112 $this->bookmarkService->save();
96 113
97 // Reload from file 114 // Reload from file
98 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); 115 $this->bookmarkService = new BookmarkFileService(
116 $this->conf,
117 $this->pluginManager,
118 $this->history,
119 $this->mutex,
120 true
121 );
99 $this->assertEquals($refDB->countLinks() + 3, $this->bookmarkService->count()); 122 $this->assertEquals($refDB->countLinks() + 3, $this->bookmarkService->count());
100 123
101 $bookmark = $this->bookmarkService->get(43); 124 $bookmark = $this->bookmarkService->get(43);
@@ -126,7 +149,13 @@ class BookmarkInitializerTest extends TestCase
126 public function testInitializeNonExistentDataStore(): void 149 public function testInitializeNonExistentDataStore(): void
127 { 150 {
128 $this->conf->set('resource.datastore', static::$testDatastore . '_empty'); 151 $this->conf->set('resource.datastore', static::$testDatastore . '_empty');
129 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); 152 $this->bookmarkService = new BookmarkFileService(
153 $this->conf,
154 $this->pluginManager,
155 $this->history,
156 $this->mutex,
157 true
158 );
130 159
131 $this->initializer->initialize(); 160 $this->initializer->initialize();
132 161
diff --git a/tests/feed/FeedBuilderTest.php b/tests/feed/FeedBuilderTest.php
index 6b9204eb..fe092f78 100644
--- a/tests/feed/FeedBuilderTest.php
+++ b/tests/feed/FeedBuilderTest.php
@@ -11,6 +11,7 @@ use Shaarli\Bookmark\LinkDB;
11use Shaarli\Config\ConfigManager; 11use Shaarli\Config\ConfigManager;
12use Shaarli\Formatter\FormatterFactory; 12use Shaarli\Formatter\FormatterFactory;
13use Shaarli\History; 13use Shaarli\History;
14use Shaarli\Plugin\PluginManager;
14use Shaarli\TestCase; 15use Shaarli\TestCase;
15 16
16/** 17/**
@@ -55,8 +56,15 @@ class FeedBuilderTest extends TestCase
55 $refLinkDB->write(self::$testDatastore); 56 $refLinkDB->write(self::$testDatastore);
56 $history = new History('sandbox/history.php'); 57 $history = new History('sandbox/history.php');
57 $factory = new FormatterFactory($conf, true); 58 $factory = new FormatterFactory($conf, true);
59 $pluginManager = new PluginManager($conf);
58 self::$formatter = $factory->getFormatter(); 60 self::$formatter = $factory->getFormatter();
59 self::$bookmarkService = new BookmarkFileService($conf, $history, $mutex, true); 61 self::$bookmarkService = new BookmarkFileService(
62 $conf,
63 $pluginManager,
64 $history,
65 $mutex,
66 true
67 );
60 68
61 self::$serverInfo = array( 69 self::$serverInfo = array(
62 'HTTPS' => 'Off', 70 'HTTPS' => 'Off',
diff --git a/tests/netscape/BookmarkExportTest.php b/tests/netscape/BookmarkExportTest.php
index ad288f78..b8a88cd8 100644
--- a/tests/netscape/BookmarkExportTest.php
+++ b/tests/netscape/BookmarkExportTest.php
@@ -8,6 +8,7 @@ use Shaarli\Config\ConfigManager;
8use Shaarli\Formatter\BookmarkFormatter; 8use Shaarli\Formatter\BookmarkFormatter;
9use Shaarli\Formatter\FormatterFactory; 9use Shaarli\Formatter\FormatterFactory;
10use Shaarli\History; 10use Shaarli\History;
11use Shaarli\Plugin\PluginManager;
11use Shaarli\TestCase; 12use Shaarli\TestCase;
12 13
13require_once 'tests/utils/ReferenceLinkDB.php'; 14require_once 'tests/utils/ReferenceLinkDB.php';
@@ -47,6 +48,9 @@ class BookmarkExportTest extends TestCase
47 */ 48 */
48 protected static $history; 49 protected static $history;
49 50
51 /** @var PluginManager */
52 protected static $pluginManager;
53
50 /** 54 /**
51 * @var NetscapeBookmarkUtils 55 * @var NetscapeBookmarkUtils
52 */ 56 */
@@ -63,7 +67,14 @@ class BookmarkExportTest extends TestCase
63 static::$refDb = new \ReferenceLinkDB(); 67 static::$refDb = new \ReferenceLinkDB();
64 static::$refDb->write(static::$testDatastore); 68 static::$refDb->write(static::$testDatastore);
65 static::$history = new History('sandbox/history.php'); 69 static::$history = new History('sandbox/history.php');
66 static::$bookmarkService = new BookmarkFileService(static::$conf, static::$history, $mutex, true); 70 static::$pluginManager = new PluginManager(static::$conf);
71 static::$bookmarkService = new BookmarkFileService(
72 static::$conf,
73 static::$pluginManager,
74 static::$history,
75 $mutex,
76 true
77 );
67 $factory = new FormatterFactory(static::$conf, true); 78 $factory = new FormatterFactory(static::$conf, true);
68 static::$formatter = $factory->getFormatter('raw'); 79 static::$formatter = $factory->getFormatter('raw');
69 } 80 }
diff --git a/tests/netscape/BookmarkImportTest.php b/tests/netscape/BookmarkImportTest.php
index 6856ebca..ecd33ea1 100644
--- a/tests/netscape/BookmarkImportTest.php
+++ b/tests/netscape/BookmarkImportTest.php
@@ -10,6 +10,7 @@ use Shaarli\Bookmark\BookmarkFileService;
10use Shaarli\Bookmark\BookmarkFilter; 10use Shaarli\Bookmark\BookmarkFilter;
11use Shaarli\Config\ConfigManager; 11use Shaarli\Config\ConfigManager;
12use Shaarli\History; 12use Shaarli\History;
13use Shaarli\Plugin\PluginManager;
13use Shaarli\TestCase; 14use Shaarli\TestCase;
14use Slim\Http\UploadedFile; 15use Slim\Http\UploadedFile;
15 16
@@ -71,6 +72,9 @@ class BookmarkImportTest extends TestCase
71 */ 72 */
72 protected $netscapeBookmarkUtils; 73 protected $netscapeBookmarkUtils;
73 74
75 /** @var PluginManager */
76 protected $pluginManager;
77
74 /** 78 /**
75 * @var string Save the current timezone. 79 * @var string Save the current timezone.
76 */ 80 */
@@ -99,7 +103,14 @@ class BookmarkImportTest extends TestCase
99 $this->conf->set('resource.page_cache', $this->pagecache); 103 $this->conf->set('resource.page_cache', $this->pagecache);
100 $this->conf->set('resource.datastore', self::$testDatastore); 104 $this->conf->set('resource.datastore', self::$testDatastore);
101 $this->history = new History(self::$historyFilePath); 105 $this->history = new History(self::$historyFilePath);
102 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $mutex, true); 106 $this->pluginManager = new PluginManager($this->conf);
107 $this->bookmarkService = new BookmarkFileService(
108 $this->conf,
109 $this->pluginManager,
110 $this->history,
111 $mutex,
112 true
113 );
103 $this->netscapeBookmarkUtils = new NetscapeBookmarkUtils($this->bookmarkService, $this->conf, $this->history); 114 $this->netscapeBookmarkUtils = new NetscapeBookmarkUtils($this->bookmarkService, $this->conf, $this->history);
104 } 115 }
105 116
diff --git a/tests/plugins/test/test.php b/tests/plugins/test/test.php
index 34cd339e..8dbb3f94 100644
--- a/tests/plugins/test/test.php
+++ b/tests/plugins/test/test.php
@@ -1,5 +1,7 @@
1<?php 1<?php
2 2
3use Shaarli\Bookmark\Bookmark;
4
3/** 5/**
4 * Hook for test. 6 * Hook for test.
5 * 7 *
@@ -43,3 +45,8 @@ function test_register_routes(): array
43 ], 45 ],
44 ]; 46 ];
45} 47}
48
49function hook_test_filter_search_entry(Bookmark $bookmark, array $context): bool
50{
51 return $context['_result'];
52}
diff --git a/tests/updater/UpdaterTest.php b/tests/updater/UpdaterTest.php
index cadd8265..a8539d63 100644
--- a/tests/updater/UpdaterTest.php
+++ b/tests/updater/UpdaterTest.php
@@ -7,6 +7,7 @@ use Shaarli\Bookmark\BookmarkFileService;
7use Shaarli\Bookmark\BookmarkServiceInterface; 7use Shaarli\Bookmark\BookmarkServiceInterface;
8use Shaarli\Config\ConfigManager; 8use Shaarli\Config\ConfigManager;
9use Shaarli\History; 9use Shaarli\History;
10use Shaarli\Plugin\PluginManager;
10use Shaarli\TestCase; 11use Shaarli\TestCase;
11 12
12 13
@@ -51,7 +52,13 @@ class UpdaterTest extends TestCase
51 52
52 copy('tests/utils/config/configJson.json.php', self::$configFile .'.json.php'); 53 copy('tests/utils/config/configJson.json.php', self::$configFile .'.json.php');
53 $this->conf = new ConfigManager(self::$configFile); 54 $this->conf = new ConfigManager(self::$configFile);
54 $this->bookmarkService = new BookmarkFileService($this->conf, $this->createMock(History::class), $mutex, true); 55 $this->bookmarkService = new BookmarkFileService(
56 $this->conf,
57 $this->createMock(PluginManager::class),
58 $this->createMock(History::class),
59 $mutex,
60 true
61 );
55 $this->updater = new Updater([], $this->bookmarkService, $this->conf, true); 62 $this->updater = new Updater([], $this->bookmarkService, $this->conf, true);
56 } 63 }
57 64