]> BookStack Code Mirror - bookstack/commitdiff
Refactored search runner a little to be neater
authorDan Brown <redacted>
Mon, 8 Nov 2021 11:04:27 +0000 (11:04 +0000)
committerDan Brown <redacted>
Mon, 8 Nov 2021 11:04:27 +0000 (11:04 +0000)
app/Entities/Tools/SearchRunner.php
database/seeders/LargeContentSeeder.php

index 223494d46e5c759a7bbd5b2d6207db31bbbcecb5..dc54649be8ffb56156636a111bd201f06ba83503 100644 (file)
@@ -6,11 +6,12 @@ use BookStack\Auth\Permissions\PermissionService;
 use BookStack\Auth\User;
 use BookStack\Entities\EntityProvider;
 use BookStack\Entities\Models\Entity;
-use Illuminate\Database\Connection;
 use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
+use Illuminate\Database\Eloquent\Collection as EloquentCollection;
 use Illuminate\Database\Query\Builder;
 use Illuminate\Database\Query\JoinClause;
 use Illuminate\Support\Collection;
+use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Str;
 
 class SearchRunner
@@ -20,11 +21,6 @@ class SearchRunner
      */
     protected $entityProvider;
 
-    /**
-     * @var Connection
-     */
-    protected $db;
-
     /**
      * @var PermissionService
      */
@@ -37,10 +33,9 @@ class SearchRunner
      */
     protected $queryOperators = ['<=', '>=', '=', '<', '>', 'like', '!='];
 
-    public function __construct(EntityProvider $entityProvider, Connection $db, PermissionService $permissionService)
+    public function __construct(EntityProvider $entityProvider, PermissionService $permissionService)
     {
         $this->entityProvider = $entityProvider;
-        $this->db = $db;
         $this->permissionService = $permissionService;
     }
 
@@ -69,16 +64,16 @@ class SearchRunner
                 continue;
             }
 
-            $search = $this->searchEntityTable($searchOpts, $entityType, $page, $count, $action);
-            /** @var int $entityTotal */
-            $entityTotal = $this->searchEntityTable($searchOpts, $entityType, $page, $count, $action, true);
+            $searchQuery = $this->buildQuery($searchOpts, $entityType, $action);
+            $entityTotal = $searchQuery->count();
+            $searchResults = $this->getPageOfDataFromQuery($searchQuery, $page, $count);
 
             if ($entityTotal > ($page * $count)) {
                 $hasMore = true;
             }
 
             $total += $entityTotal;
-            $results = $results->merge($search);
+            $results = $results->merge($searchResults);
         }
 
         return [
@@ -103,7 +98,7 @@ class SearchRunner
             if (!in_array($entityType, $entityTypes)) {
                 continue;
             }
-            $search = $this->buildEntitySearchQuery($opts, $entityType)->where('book_id', '=', $bookId)->take(20)->get();
+            $search = $this->buildQuery($opts, $entityType)->where('book_id', '=', $bookId)->take(20)->get();
             $results = $results->merge($search);
         }
 
@@ -116,49 +111,41 @@ class SearchRunner
     public function searchChapter(int $chapterId, string $searchString): Collection
     {
         $opts = SearchOptions::fromString($searchString);
-        $pages = $this->buildEntitySearchQuery($opts, 'page')->where('chapter_id', '=', $chapterId)->take(20)->get();
+        $pages = $this->buildQuery($opts, 'page')->where('chapter_id', '=', $chapterId)->take(20)->get();
 
         return $pages->sortByDesc('score');
     }
 
     /**
-     * Search across a particular entity type.
-     * Setting getCount = true will return the total
-     * matching instead of the items themselves.
-     *
-     * @return \Illuminate\Database\Eloquent\Collection|int|static[]
+     * Get a page of result data from the given query based on the provided page parameters.
      */
-    protected function searchEntityTable(SearchOptions $searchOpts, string $entityType = 'page', int $page = 1, int $count = 20, string $action = 'view', bool $getCount = false)
+    protected function getPageOfDataFromQuery(EloquentBuilder $query, int $page = 1, int $count = 20): EloquentCollection
     {
-        $query = $this->buildEntitySearchQuery($searchOpts, $entityType, $action);
-        if ($getCount) {
-            return $query->count();
-        }
-
-        $query = $query->skip(($page - 1) * $count)->take($count);
-
-        return $query->get();
+        return $query->clone()
+            ->skip(($page - 1) * $count)
+            ->take($count)
+            ->get();
     }
 
     /**
      * Create a search query for an entity.
      */
-    protected function buildEntitySearchQuery(SearchOptions $searchOpts, string $entityType = 'page', string $action = 'view'): EloquentBuilder
+    protected function buildQuery(SearchOptions $searchOpts, string $entityType = 'page', string $action = 'view'): EloquentBuilder
     {
         $entity = $this->entityProvider->get($entityType);
         $entitySelect = $entity->newQuery();
 
         // Handle normal search terms
         if (count($searchOpts->searches) > 0) {
-            $rawScoreSum = $this->db->raw('SUM(score) as score');
-            $subQuery = $this->db->table('search_terms')->select('entity_id', 'entity_type', $rawScoreSum);
+            $rawScoreSum = DB::raw('SUM(score) as score');
+            $subQuery = DB::table('search_terms')->select('entity_id', 'entity_type', $rawScoreSum);
             $subQuery->where('entity_type', '=', $entity->getMorphClass());
             $subQuery->where(function (Builder $query) use ($searchOpts) {
                 foreach ($searchOpts->searches as $inputTerm) {
                     $query->orWhere('term', 'like', $inputTerm . '%');
                 }
             })->groupBy('entity_type', 'entity_id');
-            $entitySelect->join($this->db->raw('(' . $subQuery->toSql() . ') as s'), function (JoinClause $join) {
+            $entitySelect->join(DB::raw('(' . $subQuery->toSql() . ') as s'), function (JoinClause $join) {
                 $join->on('id', '=', 'entity_id');
             })->addSelect($entity->getTable() . '.*')
                 ->selectRaw('s.score')
@@ -238,44 +225,36 @@ class SearchRunner
     /**
      * Custom entity search filters.
      */
-    protected function filterUpdatedAfter(EloquentBuilder $query, Entity $model, $input)
+    protected function filterUpdatedAfter(EloquentBuilder $query, Entity $model, $input): void
     {
         try {
             $date = date_create($input);
-        } catch (\Exception $e) {
-            return;
-        }
-        $query->where('updated_at', '>=', $date);
+            $query->where('updated_at', '>=', $date);
+        } catch (\Exception $e) {}
     }
 
-    protected function filterUpdatedBefore(EloquentBuilder $query, Entity $model, $input)
+    protected function filterUpdatedBefore(EloquentBuilder $query, Entity $model, $input): void
     {
         try {
             $date = date_create($input);
-        } catch (\Exception $e) {
-            return;
-        }
-        $query->where('updated_at', '<', $date);
+            $query->where('updated_at', '<', $date);
+        } catch (\Exception $e) {}
     }
 
-    protected function filterCreatedAfter(EloquentBuilder $query, Entity $model, $input)
+    protected function filterCreatedAfter(EloquentBuilder $query, Entity $model, $input): void
     {
         try {
             $date = date_create($input);
-        } catch (\Exception $e) {
-            return;
-        }
-        $query->where('created_at', '>=', $date);
+            $query->where('created_at', '>=', $date);
+        } catch (\Exception $e) {}
     }
 
     protected function filterCreatedBefore(EloquentBuilder $query, Entity $model, $input)
     {
         try {
             $date = date_create($input);
-        } catch (\Exception $e) {
-            return;
-        }
-        $query->where('created_at', '<', $date);
+            $query->where('created_at', '<', $date);
+        } catch (\Exception $e) {}
     }
 
     protected function filterCreatedBy(EloquentBuilder $query, Entity $model, $input)
@@ -352,9 +331,9 @@ class SearchRunner
      */
     protected function sortByLastCommented(EloquentBuilder $query, Entity $model)
     {
-        $commentsTable = $this->db->getTablePrefix() . 'comments';
+        $commentsTable = DB::getTablePrefix() . 'comments';
         $morphClass = str_replace('\\', '\\\\', $model->getMorphClass());
-        $commentQuery = $this->db->raw('(SELECT c1.entity_id, c1.entity_type, c1.created_at as last_commented FROM ' . $commentsTable . ' c1 LEFT JOIN ' . $commentsTable . ' c2 ON (c1.entity_id = c2.entity_id AND c1.entity_type = c2.entity_type AND c1.created_at < c2.created_at) WHERE c1.entity_type = \'' . $morphClass . '\' AND c2.created_at IS NULL) as comments');
+        $commentQuery = DB::raw('(SELECT c1.entity_id, c1.entity_type, c1.created_at as last_commented FROM ' . $commentsTable . ' c1 LEFT JOIN ' . $commentsTable . ' c2 ON (c1.entity_id = c2.entity_id AND c1.entity_type = c2.entity_type AND c1.created_at < c2.created_at) WHERE c1.entity_type = \'' . $morphClass . '\' AND c2.created_at IS NULL) as comments');
 
         $query->join($commentQuery, $model->getTable() . '.id', '=', 'comments.entity_id')->orderBy('last_commented', 'desc');
     }
index 2fbf4a5c9822c9234ebffb42f43975d944ff4ff4..e8b6d74f6a4e9f8de2cc70d6ea6ee6b3f5c663be 100644 (file)
@@ -5,6 +5,7 @@ namespace Database\Seeders;
 use BookStack\Auth\Permissions\PermissionService;
 use BookStack\Auth\Role;
 use BookStack\Auth\User;
+use BookStack\Entities\Models\Book;
 use BookStack\Entities\Models\Chapter;
 use BookStack\Entities\Models\Page;
 use BookStack\Entities\Tools\SearchIndex;
@@ -25,12 +26,15 @@ class LargeContentSeeder extends Seeder
         $editorRole = Role::getRole('editor');
         $editorUser->attachRole($editorRole);
 
-        $largeBook = \BookStack\Entities\Models\Book::factory()->create(['name' => 'Large book' . Str::random(10), 'created_by' => $editorUser->id, 'updated_by' => $editorUser->id]);
+        /** @var Book $largeBook */
+        $largeBook = Book::factory()->create(['name' => 'Large book' . Str::random(10), 'created_by' => $editorUser->id, 'updated_by' => $editorUser->id]);
         $pages = Page::factory()->count(200)->make(['created_by' => $editorUser->id, 'updated_by' => $editorUser->id]);
         $chapters = Chapter::factory()->count(50)->make(['created_by' => $editorUser->id, 'updated_by' => $editorUser->id]);
+
         $largeBook->pages()->saveMany($pages);
         $largeBook->chapters()->saveMany($chapters);
-        app(PermissionService::class)->buildJointPermissions();
-        app(SearchIndex::class)->indexAllEntities();
+
+        app()->make(PermissionService::class)->buildJointPermissions();
+        app()->make(SearchIndex::class)->indexAllEntities();
     }
 }