]> BookStack Code Mirror - bookstack/blobdiff - app/Entities/Tools/SearchOptions.php
Updated minimum php version from 7.3 to 7.4
[bookstack] / app / Entities / Tools / SearchOptions.php
index 6c03c57a6105ce7a36e4c311e2b2f75ba3b13149..99271058e2306412d10d14b76a888c8ecd70d371 100644 (file)
@@ -1,10 +1,11 @@
-<?php namespace BookStack\Entities\Tools;
+<?php
+
+namespace BookStack\Entities\Tools;
 
 use Illuminate\Http\Request;
 
 class SearchOptions
 {
-
     /**
      * @var array
      */
@@ -28,13 +29,14 @@ class SearchOptions
     /**
      * Create a new instance from a search string.
      */
-    public static function fromString(string $search): SearchOptions
+    public static function fromString(string $search): self
     {
         $decoded = static::decode($search);
-        $instance = new static();
+        $instance = new SearchOptions();
         foreach ($decoded as $type => $value) {
             $instance->$type = $value;
         }
+
         return $instance;
     }
 
@@ -43,7 +45,7 @@ class SearchOptions
      * Will look for a classic string term and use that
      * Otherwise we'll use the details from an advanced search form.
      */
-    public static function fromRequest(Request $request): SearchOptions
+    public static function fromRequest(Request $request): self
     {
         if (!$request->has('search') && !$request->has('term')) {
             return static::fromString('');
@@ -53,20 +55,28 @@ class SearchOptions
             return static::fromString($request->get('term'));
         }
 
-        $instance = new static();
+        $instance = new SearchOptions();
         $inputs = $request->only(['search', 'types', 'filters', 'exact', 'tags']);
-        $instance->searches = explode(' ', $inputs['search'] ?? []);
-        $instance->exacts = array_filter($inputs['exact'] ?? []);
+
+        $parsedStandardTerms = static::parseStandardTermString($inputs['search'] ?? '');
+        $instance->searches = $parsedStandardTerms['terms'];
+        $instance->exacts = $parsedStandardTerms['exacts'];
+
+        array_push($instance->exacts, ...array_filter($inputs['exact'] ?? []));
+
         $instance->tags = array_filter($inputs['tags'] ?? []);
+
         foreach (($inputs['filters'] ?? []) as $filterKey => $filterVal) {
             if (empty($filterVal)) {
                 continue;
             }
             $instance->filters[$filterKey] = $filterVal === 'true' ? '' : $filterVal;
         }
+
         if (isset($inputs['types']) && count($inputs['types']) < 4) {
             $instance->filters['type'] = implode('|', $inputs['types']);
         }
+
         return $instance;
     }
 
@@ -77,15 +87,15 @@ class SearchOptions
     {
         $terms = [
             'searches' => [],
-            'exacts' => [],
-            'tags' => [],
-            'filters' => []
+            'exacts'   => [],
+            'tags'     => [],
+            'filters'  => [],
         ];
 
         $patterns = [
-            'exacts' => '/"(.*?)"/',
-            'tags' => '/\[(.*?)\]/',
-            'filters' => '/\{(.*?)\}/'
+            'exacts'  => '/"(.*?)"/',
+            'tags'    => '/\[(.*?)\]/',
+            'filters' => '/\{(.*?)\}/',
         ];
 
         // Parse special terms
@@ -99,11 +109,9 @@ class SearchOptions
         }
 
         // Parse standard terms
-        foreach (explode(' ', trim($searchString)) as $searchTerm) {
-            if ($searchTerm !== '') {
-                $terms['searches'][] = $searchTerm;
-            }
-        }
+        $parsedStandardTerms = static::parseStandardTermString($searchString);
+        array_push($terms['searches'], ...$parsedStandardTerms['terms']);
+        array_push($terms['exacts'], ...$parsedStandardTerms['exacts']);
 
         // Split filter values out
         $splitFilters = [];
@@ -116,6 +124,33 @@ class SearchOptions
         return $terms;
     }
 
+    /**
+     * Parse a standard search term string into individual search terms and
+     * extract any exact terms searches to be made.
+     *
+     * @return array{terms: array<string>, exacts: array<string>}
+     */
+    protected static function parseStandardTermString(string $termString): array
+    {
+        $terms = explode(' ', $termString);
+        $indexDelimiters = SearchIndex::$delimiters;
+        $parsed = [
+            'terms'  => [],
+            'exacts' => [],
+        ];
+
+        foreach ($terms as $searchTerm) {
+            if ($searchTerm === '') {
+                continue;
+            }
+
+            $parsedList = (strpbrk($searchTerm, $indexDelimiters) === false) ? 'terms' : 'exacts';
+            $parsed[$parsedList][] = $searchTerm;
+        }
+
+        return $parsed;
+    }
+
     /**
      * Encode this instance to a search string.
      */