]> BookStack Code Mirror - bookstack/blobdiff - app/Repos/EntityRepo.php
replace GPL diff lib with MIT lib
[bookstack] / app / Repos / EntityRepo.php
index 6b4076e6e2c8646b86002e32b5d06bc1a831d75e..012a649676b7c8c9df8b87292c6adeacd4161345 100644 (file)
@@ -6,6 +6,7 @@ use BookStack\Entity;
 use BookStack\Page;
 use BookStack\Services\PermissionService;
 use BookStack\User;
+use Illuminate\Support\Facades\Log;
 
 class EntityRepo
 {
@@ -30,6 +31,12 @@ class EntityRepo
      */
     protected $permissionService;
 
+    /**
+     * Acceptable operators to be used in a query
+     * @var array
+     */
+    protected $queryOperators = ['<=', '>=', '=', '<', '>', 'like', '!='];
+
     /**
      * EntityService constructor.
      */
@@ -163,6 +170,7 @@ class EntityRepo
      */
     protected function prepareSearchTerms($termString)
     {
+        $termString = $this->cleanSearchTermString($termString);
         preg_match_all('/"(.*?)"/', $termString, $matches);
         if (count($matches[1]) > 0) {
             $terms = $matches[1];
@@ -174,5 +182,93 @@ class EntityRepo
         return $terms;
     }
 
+    /**
+     * Removes any special search notation that should not
+     * be used in a full-text search.
+     * @param $termString
+     * @return mixed
+     */
+    protected function cleanSearchTermString($termString)
+    {
+        // Strip tag searches
+        $termString = preg_replace('/\[.*?\]/', '', $termString);
+        // Reduced multiple spacing into single spacing
+        $termString = preg_replace("/\s{2,}/", " ", $termString);
+        return $termString;
+    }
+
+    /**
+     * Get the available query operators as a regex escaped list.
+     * @return mixed
+     */
+    protected function getRegexEscapedOperators()
+    {
+        $escapedOperators = [];
+        foreach ($this->queryOperators as $operator) {
+            $escapedOperators[] = preg_quote($operator);
+        }
+        return join('|', $escapedOperators);
+    }
+
+    /**
+     * Parses advanced search notations and adds them to the db query.
+     * @param $query
+     * @param $termString
+     * @return mixed
+     */
+    protected function addAdvancedSearchQueries($query, $termString)
+    {
+        $escapedOperators = $this->getRegexEscapedOperators();
+        // Look for tag searches
+        preg_match_all("/\[(.*?)((${escapedOperators})(.*?))?\]/", $termString, $tags);
+        if (count($tags[0]) > 0) {
+            $this->applyTagSearches($query, $tags);
+        }
+
+        return $query;
+    }
+
+    /**
+     * Apply extracted tag search terms onto a entity query.
+     * @param $query
+     * @param $tags
+     * @return mixed
+     */
+    protected function applyTagSearches($query, $tags) {
+        $query->where(function($query) use ($tags) {
+            foreach ($tags[1] as $index => $tagName) {
+                $query->whereHas('tags', function($query) use ($tags, $index, $tagName) {
+                    $tagOperator = $tags[3][$index];
+                    $tagValue = $tags[4][$index];
+                    if (!empty($tagOperator) && !empty($tagValue) && in_array($tagOperator, $this->queryOperators)) {
+                        if (is_numeric($tagValue) && $tagOperator !== 'like') {
+                            // We have to do a raw sql query for this since otherwise PDO will quote the value and MySQL will
+                            // search the value as a string which prevents being able to do number-based operations
+                            // on the tag values. We ensure it has a numeric value and then cast it just to be sure.
+                            $tagValue = (float) trim($query->getConnection()->getPdo()->quote($tagValue), "'");
+                            $query->where('name', '=', $tagName)->whereRaw("value ${tagOperator} ${tagValue}");
+                        } else {
+                            $query->where('name', '=', $tagName)->where('value', $tagOperator, $tagValue);
+                        }
+                    } else {
+                        $query->where('name', '=', $tagName);
+                    }
+                });
+            }
+        });
+        return $query;
+    }
+
+}
+
+
+
+
+
+
+
+
+
+
+
 
-}
\ No newline at end of file