]> git.immae.eu Git - github/shaarli/Shaarli.git/commitdiff
Add exclusion in tag search
authorArthurHoaro <arthur@hoa.ro>
Wed, 20 Jan 2016 22:34:33 +0000 (23:34 +0100)
committerArthurHoaro <arthur@hoa.ro>
Mon, 15 Feb 2016 19:40:39 +0000 (20:40 +0100)
  * Searching '-mytag' will now exlude all shaares with 'mytag' tag.
  * All tags starting with a '-' are renamed without it (through the Updater).
  * Unit tests.

Minor code changes:

 * LinkDB->filter() can now take no parameters (get all link depending on logged status).
 * tagsStrToArray() is now static and filters blank tags.

application/LinkDB.php
application/LinkFilter.php
application/Updater.php
tests/LinkDBTest.php
tests/LinkFilterTest.php
tests/Updater/UpdaterTest.php
tests/utils/ReferenceLinkDB.php

index a95b3f36eacf1acd66f18c0bed2e5567a4858a89..416aa0d3051a92e6f092ce3314612d0f811d3d5e 100644 (file)
@@ -340,7 +340,7 @@ You use the community supported version of the original Shaarli project, by Seba
      *
      * @return array filtered links
      */
-    public function filter($type, $request, $casesensitive = false, $privateonly = false)
+    public function filter($type = '', $request = '', $casesensitive = false, $privateonly = false)
     {
         $linkFilter = new LinkFilter($this->_links);
         $requestFilter = is_array($request) ? implode(' ', $request) : $request;
index 096d3b04049580d4549055b2bd6c7c98ddad4f7d..ceb47d16c21133e670c20066d126aa23019ed816 100644 (file)
@@ -209,19 +209,33 @@ class LinkFilter
      */
     public function filterTags($tags, $casesensitive = false, $privateonly = false)
     {
-        $searchtags = $this->tagsStrToArray($tags, $casesensitive);
+        $searchtags = self::tagsStrToArray($tags, $casesensitive);
         $filtered = array();
+        if (empty($searchtags)) {
+            return $filtered;
+        }
 
-        foreach ($this->links as $l) {
+        foreach ($this->links as $link) {
             // ignore non private links when 'privatonly' is on.
-            if (! $l['private'] && $privateonly === true) {
+            if (! $link['private'] && $privateonly === true) {
                 continue;
             }
 
-            $linktags = $this->tagsStrToArray($l['tags'], $casesensitive);
+            $linktags = self::tagsStrToArray($link['tags'], $casesensitive);
 
-            if (count(array_intersect($linktags, $searchtags)) == count($searchtags)) {
-                $filtered[$l['linkdate']] = $l;
+            $found = true;
+            for ($i = 0 ; $i < count($searchtags) && $found; $i++) {
+                // Exclusive search, quit if tag found.
+                // Or, tag not found in the link, quit.
+                if (($searchtags[$i][0] == '-' && in_array(substr($searchtags[$i], 1), $linktags))
+                    || ($searchtags[$i][0] != '-') && ! in_array($searchtags[$i], $linktags)
+                ) {
+                    $found = false;
+                }
+            }
+
+            if ($found) {
+                $filtered[$link['linkdate']] = $link;
             }
         }
         krsort($filtered);
@@ -266,12 +280,12 @@ class LinkFilter
      *
      * @return array filtered tags string.
     */
-    public function tagsStrToArray($tags, $casesensitive)
+    public static function tagsStrToArray($tags, $casesensitive)
     {
         // We use UTF-8 conversion to handle various graphemes (i.e. cyrillic, or greek)
         $tagsOut = $casesensitive ? $tags : mb_convert_case($tags, MB_CASE_LOWER, 'UTF-8');
         $tagsOut = str_replace(',', ' ', $tagsOut);
 
-        return explode(' ', trim($tagsOut));
+        return array_filter(explode(' ', trim($tagsOut)), 'strlen');
     }
 }
index 20ae0c4dda02176e4ce10aaf8d1e6ddd83b5ba95..773a1ffa1d8187e016e8ccbfb9200a1c5824bc01 100644 (file)
@@ -131,6 +131,21 @@ class Updater
 
         return true;
     }
+
+    /**
+     * Rename tags starting with a '-' to work with tag exclusion search.
+     */
+    public function updateMethodRenameDashTags()
+    {
+        $linklist = $this->linkDB->filter();
+        foreach ($linklist as $link) {
+            $link['tags'] = preg_replace('/(^| )\-/', '$1', $link['tags']);
+            $link['tags'] = implode(' ', array_unique(LinkFilter::tagsStrToArray($link['tags'], true)));
+            $this->linkDB[$link['linkdate']] = $link;
+        }
+        $this->linkDB->savedb($this->config['config']['PAGECACHE']);
+        return true;
+    }
 }
 
 /**
index 3b1a20572a75d428724c8dcf37f50a0f1edb4ff7..06edea79201a2fe18ea53cf9a7277b95153b055e 100644 (file)
@@ -276,7 +276,8 @@ class LinkDBTest extends PHPUnit_Framework_TestCase
                 'media' => 1,
                 'software' => 1,
                 'stallman' => 1,
-                'free' => 1
+                'free' => 1,
+                '-exclude' => 1,
             ),
             self::$publicLinkDB->allTags()
         );
@@ -295,7 +296,8 @@ class LinkDBTest extends PHPUnit_Framework_TestCase
                 'html' => 1,
                 'w3c' => 1,
                 'css' => 1,
-                'Mercurial' => 1
+                'Mercurial' => 1,
+                '-exclude' => 1,
             ),
             self::$privateLinkDB->allTags()
         );
index 5fb2423f6a737d0ba1d22be370f5bf09ebcf37c2..164af0d4fa83f683a2a1b8c789a0c2f8c1406de9 100644 (file)
@@ -254,4 +254,20 @@ class LinkFilterTest extends PHPUnit_Framework_TestCase
             count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, 'free software'))
         );
     }
+
+    /**
+     * Tag search with exclusion.
+     */
+    public function testTagFilterWithExclusion()
+    {
+        $this->assertEquals(
+            1,
+            count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, 'gnu -free'))
+        );
+
+        $this->assertEquals(
+            5,
+            count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, '-free'))
+        );
+    }
 }
index 63ed5e0364d0c19b977b3012dbb56445c663b663..84b82350390fbc207b14d483a53f6fe41b610096 100644 (file)
@@ -13,6 +13,11 @@ class UpdaterTest extends PHPUnit_Framework_TestCase
      */
     private static $configFields;
 
+    /**
+     * @var string Path to test datastore.
+     */
+    protected static $testDatastore = 'sandbox/datastore.php';
+
     /**
      * Executed before each test.
      */
@@ -31,6 +36,7 @@ class UpdaterTest extends PHPUnit_Framework_TestCase
             'config' => array(
                 'CONFIG_FILE' => 'tests/Updater/config.php',
                 'DATADIR' => 'tests/Updater',
+                'PAGECACHE' => 'sandbox/pagecache',
                 'config1' => 'config1data',
                 'config2' => 'config2data',
             )
@@ -224,4 +230,16 @@ class UpdaterTest extends PHPUnit_Framework_TestCase
         include self::$configFields['config']['CONFIG_FILE'];
         $this->assertEquals(self::$configFields['login'], $GLOBALS['login']);
     }
+
+    public function testRenameDashTags()
+    {
+        $refDB = new ReferenceLinkDB();
+        $refDB->write(self::$testDatastore);
+        $linkDB = new LinkDB(self::$testDatastore, true, false);
+        $this->assertEmpty($linkDB->filter(LinkFilter::$FILTER_TAG, 'exclude'));
+        $updater = new Updater(array(), self::$configFields, $linkDB, true);
+        $updater->updateMethodRenameDashTags();
+        var_dump($linkDB->filter(LinkFilter::$FILTER_TAG, 'exclude'));
+        $this->assertNotEmpty($linkDB->filter(LinkFilter::$FILTER_TAG, 'exclude'));
+    }
 }
index 011317ef970eb3ea9834ebc8b3834a04e0a00435..2f188d29168c93e77a545190495d871108ef12c0 100644 (file)
@@ -19,7 +19,7 @@ class ReferenceLinkDB
             'Richard Stallman and the Free Software Revolution',
             0,
             '20150310_114633',
-            'free gnu software stallman'
+            'free gnu software stallman -exclude'
         );
 
         $this->addLink(