aboutsummaryrefslogtreecommitdiffhomepage
path: root/application/bookmark/BookmarkFilter.php
diff options
context:
space:
mode:
Diffstat (limited to 'application/bookmark/BookmarkFilter.php')
-rw-r--r--application/bookmark/BookmarkFilter.php47
1 files changed, 31 insertions, 16 deletions
diff --git a/application/bookmark/BookmarkFilter.php b/application/bookmark/BookmarkFilter.php
index c79386ea..5d8733dc 100644
--- a/application/bookmark/BookmarkFilter.php
+++ b/application/bookmark/BookmarkFilter.php
@@ -6,6 +6,7 @@ namespace Shaarli\Bookmark;
6 6
7use Exception; 7use Exception;
8use Shaarli\Bookmark\Exception\BookmarkNotFoundException; 8use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
9use Shaarli\Config\ConfigManager;
9 10
10/** 11/**
11 * Class LinkFilter. 12 * Class LinkFilter.
@@ -58,12 +59,16 @@ class BookmarkFilter
58 */ 59 */
59 private $bookmarks; 60 private $bookmarks;
60 61
62 /** @var ConfigManager */
63 protected $conf;
64
61 /** 65 /**
62 * @param Bookmark[] $bookmarks initialization. 66 * @param Bookmark[] $bookmarks initialization.
63 */ 67 */
64 public function __construct($bookmarks) 68 public function __construct($bookmarks, ConfigManager $conf)
65 { 69 {
66 $this->bookmarks = $bookmarks; 70 $this->bookmarks = $bookmarks;
71 $this->conf = $conf;
67 } 72 }
68 73
69 /** 74 /**
@@ -107,10 +112,14 @@ class BookmarkFilter
107 $filtered = $this->bookmarks; 112 $filtered = $this->bookmarks;
108 } 113 }
109 if (!empty($request[0])) { 114 if (!empty($request[0])) {
110 $filtered = (new BookmarkFilter($filtered))->filterTags($request[0], $casesensitive, $visibility); 115 $filtered = (new BookmarkFilter($filtered, $this->conf))
116 ->filterTags($request[0], $casesensitive, $visibility)
117 ;
111 } 118 }
112 if (!empty($request[1])) { 119 if (!empty($request[1])) {
113 $filtered = (new BookmarkFilter($filtered))->filterFulltext($request[1], $visibility); 120 $filtered = (new BookmarkFilter($filtered, $this->conf))
121 ->filterFulltext($request[1], $visibility)
122 ;
114 } 123 }
115 return $filtered; 124 return $filtered;
116 case self::$FILTER_TEXT: 125 case self::$FILTER_TEXT:
@@ -280,8 +289,9 @@ class BookmarkFilter
280 * 289 *
281 * @return string generated regex fragment 290 * @return string generated regex fragment
282 */ 291 */
283 private static function tag2regex(string $tag): string 292 protected function tag2regex(string $tag): string
284 { 293 {
294 $tagsSeparator = $this->conf->get('general.tags_separator', ' ');
285 $len = strlen($tag); 295 $len = strlen($tag);
286 if (!$len || $tag === "-" || $tag === "*") { 296 if (!$len || $tag === "-" || $tag === "*") {
287 // nothing to search, return empty regex 297 // nothing to search, return empty regex
@@ -295,12 +305,13 @@ class BookmarkFilter
295 $i = 0; // start at first character 305 $i = 0; // start at first character
296 $regex = '(?='; // use positive lookahead 306 $regex = '(?='; // use positive lookahead
297 } 307 }
298 $regex .= '.*(?:^| )'; // before tag may only be a space or the beginning 308 // before tag may only be the separator or the beginning
309 $regex .= '.*(?:^|' . $tagsSeparator . ')';
299 // iterate over string, separating it into placeholder and content 310 // iterate over string, separating it into placeholder and content
300 for (; $i < $len; $i++) { 311 for (; $i < $len; $i++) {
301 if ($tag[$i] === '*') { 312 if ($tag[$i] === '*') {
302 // placeholder found 313 // placeholder found
303 $regex .= '[^ ]*?'; 314 $regex .= '[^' . $tagsSeparator . ']*?';
304 } else { 315 } else {
305 // regular characters 316 // regular characters
306 $offset = strpos($tag, '*', $i); 317 $offset = strpos($tag, '*', $i);
@@ -316,7 +327,8 @@ class BookmarkFilter
316 $i = $offset; 327 $i = $offset;
317 } 328 }
318 } 329 }
319 $regex .= '(?:$| ))'; // after the tag may only be a space or the end 330 // after the tag may only be the separator or the end
331 $regex .= '(?:$|' . $tagsSeparator . '))';
320 return $regex; 332 return $regex;
321 } 333 }
322 334
@@ -334,14 +346,15 @@ class BookmarkFilter
334 */ 346 */
335 public function filterTags($tags, bool $casesensitive = false, string $visibility = 'all') 347 public function filterTags($tags, bool $casesensitive = false, string $visibility = 'all')
336 { 348 {
349 $tagsSeparator = $this->conf->get('general.tags_separator', ' ');
337 // get single tags (we may get passed an array, even though the docs say different) 350 // get single tags (we may get passed an array, even though the docs say different)
338 $inputTags = $tags; 351 $inputTags = $tags;
339 if (!is_array($tags)) { 352 if (!is_array($tags)) {
340 // we got an input string, split tags 353 // we got an input string, split tags
341 $inputTags = preg_split('/(?:\s+)|,/', $inputTags, -1, PREG_SPLIT_NO_EMPTY); 354 $inputTags = tags_str2array($inputTags, $tagsSeparator);
342 } 355 }
343 356
344 if (!count($inputTags)) { 357 if (count($inputTags) === 0) {
345 // no input tags 358 // no input tags
346 return $this->noFilter($visibility); 359 return $this->noFilter($visibility);
347 } 360 }
@@ -358,7 +371,7 @@ class BookmarkFilter
358 } 371 }
359 372
360 // build regex from all tags 373 // build regex from all tags
361 $re = '/^' . implode(array_map("self::tag2regex", $inputTags)) . '.*$/'; 374 $re = '/^' . implode(array_map([$this, 'tag2regex'], $inputTags)) . '.*$/';
362 if (!$casesensitive) { 375 if (!$casesensitive) {
363 // make regex case insensitive 376 // make regex case insensitive
364 $re .= 'i'; 377 $re .= 'i';
@@ -378,7 +391,8 @@ class BookmarkFilter
378 continue; 391 continue;
379 } 392 }
380 } 393 }
381 $search = $link->getTagsString(); // build search string, start with tags of current link 394 // build search string, start with tags of current link
395 $search = $link->getTagsString($tagsSeparator);
382 if (strlen(trim($link->getDescription())) && strpos($link->getDescription(), '#') !== false) { 396 if (strlen(trim($link->getDescription())) && strpos($link->getDescription(), '#') !== false) {
383 // description given and at least one possible tag found 397 // description given and at least one possible tag found
384 $descTags = array(); 398 $descTags = array();
@@ -390,9 +404,9 @@ class BookmarkFilter
390 ); 404 );
391 if (count($descTags[1])) { 405 if (count($descTags[1])) {
392 // there were some tags in the description, add them to the search string 406 // there were some tags in the description, add them to the search string
393 $search .= ' ' . implode(' ', $descTags[1]); 407 $search .= $tagsSeparator . tags_array2str($descTags[1], $tagsSeparator);
394 } 408 }
395 }; 409 }
396 // match regular expression with search string 410 // match regular expression with search string
397 if (!preg_match($re, $search)) { 411 if (!preg_match($re, $search)) {
398 // this entry does _not_ match our regex 412 // this entry does _not_ match our regex
@@ -422,7 +436,7 @@ class BookmarkFilter
422 } 436 }
423 } 437 }
424 438
425 if (empty(trim($link->getTagsString()))) { 439 if (empty($link->getTags())) {
426 $filtered[$key] = $link; 440 $filtered[$key] = $link;
427 } 441 }
428 } 442 }
@@ -537,10 +551,11 @@ class BookmarkFilter
537 */ 551 */
538 protected function buildFullTextSearchableLink(Bookmark $link, array &$lengths): string 552 protected function buildFullTextSearchableLink(Bookmark $link, array &$lengths): string
539 { 553 {
554 $tagString = $link->getTagsString($this->conf->get('general.tags_separator', ' '));
540 $content = mb_convert_case($link->getTitle(), MB_CASE_LOWER, 'UTF-8') .'\\'; 555 $content = mb_convert_case($link->getTitle(), MB_CASE_LOWER, 'UTF-8') .'\\';
541 $content .= mb_convert_case($link->getDescription(), MB_CASE_LOWER, 'UTF-8') .'\\'; 556 $content .= mb_convert_case($link->getDescription(), MB_CASE_LOWER, 'UTF-8') .'\\';
542 $content .= mb_convert_case($link->getUrl(), MB_CASE_LOWER, 'UTF-8') .'\\'; 557 $content .= mb_convert_case($link->getUrl(), MB_CASE_LOWER, 'UTF-8') .'\\';
543 $content .= mb_convert_case($link->getTagsString(), MB_CASE_LOWER, 'UTF-8') .'\\'; 558 $content .= mb_convert_case($tagString, MB_CASE_LOWER, 'UTF-8') .'\\';
544 559
545 $lengths['title'] = ['start' => 0, 'end' => mb_strlen($link->getTitle())]; 560 $lengths['title'] = ['start' => 0, 'end' => mb_strlen($link->getTitle())];
546 $nextField = $lengths['title']['end'] + 1; 561 $nextField = $lengths['title']['end'] + 1;
@@ -548,7 +563,7 @@ class BookmarkFilter
548 $nextField = $lengths['description']['end'] + 1; 563 $nextField = $lengths['description']['end'] + 1;
549 $lengths['url'] = ['start' => $nextField, 'end' => $nextField + mb_strlen($link->getUrl())]; 564 $lengths['url'] = ['start' => $nextField, 'end' => $nextField + mb_strlen($link->getUrl())];
550 $nextField = $lengths['url']['end'] + 1; 565 $nextField = $lengths['url']['end'] + 1;
551 $lengths['tags'] = ['start' => $nextField, 'end' => $nextField + mb_strlen($link->getTagsString())]; 566 $lengths['tags'] = ['start' => $nextField, 'end' => $nextField + mb_strlen($tagString)];
552 567
553 return $content; 568 return $content;
554 } 569 }