]> BookStack Code Mirror - bookstack/commitdiff
Developed basic search queries.
authorDan Brown <redacted>
Sun, 26 Mar 2017 18:24:57 +0000 (19:24 +0100)
committerDan Brown <redacted>
Sun, 26 Mar 2017 18:24:57 +0000 (19:24 +0100)
Updated search & permission regen commands with ability to specify
database.

app/Console/Commands/RegeneratePermissions.php
app/Console/Commands/RegenerateSearch.php
app/Services/PermissionService.php
app/Services/SearchService.php
database/seeds/DummyContentSeeder.php

index 966ee4a820841429148a19c3724003492909742b..1dc25f9aa6e996f4a8db898b513dfe08207f83a3 100644 (file)
@@ -12,7 +12,7 @@ class RegeneratePermissions extends Command
      *
      * @var string
      */
-    protected $signature = 'bookstack:regenerate-permissions';
+    protected $signature = 'bookstack:regenerate-permissions {--database= : The database connection to use.}';
 
     /**
      * The console command description.
@@ -46,7 +46,14 @@ class RegeneratePermissions extends Command
      */
     public function handle()
     {
+        $connection = \DB::getDefaultConnection();
+        if ($this->option('database') !== null) {
+            \DB::setDefaultConnection($this->option('database'));
+        }
+
         $this->permissionService->buildJointPermissions();
+
+        \DB::setDefaultConnection($connection);
         $this->comment('Permissions regenerated');
     }
 }
index ccc2a20e59896b7ed0166fa565a7830dfd1c106c..35ecd46c0817ddac6e201f161dec73068e9085d6 100644 (file)
@@ -12,7 +12,7 @@ class RegenerateSearch extends Command
      *
      * @var string
      */
-    protected $signature = 'bookstack:regenerate-search';
+    protected $signature = 'bookstack:regenerate-search {--database= : The database connection to use.}';
 
     /**
      * The console command description.
@@ -41,6 +41,13 @@ class RegenerateSearch extends Command
      */
     public function handle()
     {
+        $connection = \DB::getDefaultConnection();
+        if ($this->option('database') !== null) {
+            \DB::setDefaultConnection($this->option('database'));
+        }
+
         $this->searchService->indexAllEntities();
+        \DB::setDefaultConnection($connection);
+        $this->comment('Search index regenerated');
     }
 }
index 616c81443e8a96bce10cc203d866ae458536475c..1e75308a07e3734ac6771cf2b78a5c5babe8f3d7 100644 (file)
@@ -513,7 +513,7 @@ class PermissionService
      * @param string $entityType
      * @param Builder|Entity $query
      * @param string $action
-     * @return mixed
+     * @return Builder
      */
     public function enforceEntityRestrictions($entityType, $query, $action = 'view')
     {
index be1303ca04ac59347cca106df2f5a05a630ba389..ae8dd008a86ef81b220b580c59288750414494dd 100644 (file)
@@ -16,6 +16,8 @@ class SearchService
     protected $chapter;
     protected $page;
     protected $db;
+    protected $permissionService;
+    protected $entities;
 
     /**
      * SearchService constructor.
@@ -24,22 +26,41 @@ class SearchService
      * @param Chapter $chapter
      * @param Page $page
      * @param Connection $db
+     * @param PermissionService $permissionService
      */
-    public function __construct(SearchTerm $searchTerm, Book $book, Chapter $chapter, Page $page, Connection $db)
+    public function __construct(SearchTerm $searchTerm, Book $book, Chapter $chapter, Page $page, Connection $db, PermissionService $permissionService)
     {
         $this->searchTerm = $searchTerm;
         $this->book = $book;
         $this->chapter = $chapter;
         $this->page = $page;
         $this->db = $db;
+        $this->entities = [
+            'page' => $this->page,
+            'chapter' => $this->chapter,
+            'book' => $this->book
+        ];
+        $this->permissionService = $permissionService;
     }
 
-    public function searchEntities($searchString, $entityType = 'all')
+    public function searchEntities($searchString, $entityType = 'all', $page = 0, $count = 20)
     {
         // TODO - Add Tag Searches
         // TODO - Add advanced custom column searches
         // TODO - Add exact match searches ("")
+        // TODO - Check drafts don't show up in results
+        // TODO - Move search all page to just /search?term=cat
 
+       if ($entityType !== 'all') return $this->searchEntityTable($searchString, $entityType, $page, $count);
+
+       $bookSearch = $this->searchEntityTable($searchString, 'book', $page, $count);
+       $chapterSearch = $this->searchEntityTable($searchString, 'chapter', $page, $count);
+       $pageSearch = $this->searchEntityTable($searchString, 'page', $page, $count);
+       return collect($bookSearch)->merge($chapterSearch)->merge($pageSearch)->sortByDesc('score');
+    }
+
+    public function searchEntityTable($searchString, $entityType = 'page', $page = 0, $count = 20)
+    {
         $termArray = explode(' ', $searchString);
 
         $subQuery = $this->db->table('search_terms')->select('entity_id', 'entity_type', \DB::raw('SUM(score) as score'));
@@ -49,13 +70,24 @@ class SearchService
             }
         });
 
+        $entity = $this->getEntity($entityType);
         $subQuery = $subQuery->groupBy('entity_type', 'entity_id');
-        $pageSelect = $this->db->table('pages as e')->join(\DB::raw('(' . $subQuery->toSql() . ') as s'), function(JoinClause $join) {
-            $join->on('e.id', '=', 's.entity_id');
-        })->selectRaw('e.*, s.score')->orderBy('score', 'desc');
-        $pageSelect->mergeBindings($subQuery);
-        dd($pageSelect->toSql());
-        // TODO - Continue from here
+        $entitySelect = $entity->newQuery()->join(\DB::raw('(' . $subQuery->toSql() . ') as s'), function(JoinClause $join) {
+            $join->on('id', '=', 'entity_id');
+        })->selectRaw($entity->getTable().'.*, s.score')->orderBy('score', 'desc')->skip($page * $count)->take($count);
+        $entitySelect->mergeBindings($subQuery);
+        $query = $this->permissionService->enforceEntityRestrictions($entityType, $entitySelect, 'view');
+        return $query->get();
+    }
+
+    /**
+     * Get an entity instance via type.
+     * @param $type
+     * @return Entity
+     */
+    protected function getEntity($type)
+    {
+        return $this->entities[strtolower($type)];
     }
 
     /**
@@ -86,7 +118,11 @@ class SearchService
                 $terms[] = $term;
             }
         }
-        $this->searchTerm->insert($terms);
+
+        $chunkedTerms = array_chunk($terms, 500);
+        foreach ($chunkedTerms as $termChunk) {
+            $this->searchTerm->insert($termChunk);
+        }
     }
 
     /**
@@ -97,17 +133,17 @@ class SearchService
         $this->searchTerm->truncate();
 
         // Chunk through all books
-        $this->book->chunk(500, function ($books) {
+        $this->book->chunk(1000, function ($books) {
             $this->indexEntities($books);
         });
 
         // Chunk through all chapters
-        $this->chapter->chunk(500, function ($chapters) {
+        $this->chapter->chunk(1000, function ($chapters) {
             $this->indexEntities($chapters);
         });
 
         // Chunk through all pages
-        $this->page->chunk(500, function ($pages) {
+        $this->page->chunk(1000, function ($pages) {
             $this->indexEntities($pages);
         });
     }
index efcda422018cd29fb146829ed5a8d5843dce1490..6f6b3ddc57e7b826a1417af290c84274df895ec5 100644 (file)
@@ -16,7 +16,7 @@ class DummyContentSeeder extends Seeder
         $user->attachRole($role);
 
 
-        $books = factory(\BookStack\Book::class, 20)->create(['created_by' => $user->id, 'updated_by' => $user->id])
+        factory(\BookStack\Book::class, 20)->create(['created_by' => $user->id, 'updated_by' => $user->id])
             ->each(function($book) use ($user) {
                 $chapters = factory(\BookStack\Chapter::class, 5)->create(['created_by' => $user->id, 'updated_by' => $user->id])
                     ->each(function($chapter) use ($user, $book){
@@ -28,7 +28,7 @@ class DummyContentSeeder extends Seeder
                 $book->pages()->saveMany($pages);
             });
 
-        $restrictionService = app(\BookStack\Services\PermissionService::class);
-        $restrictionService->buildJointPermissions();
+        app(\BookStack\Services\PermissionService::class)->buildJointPermissions();
+        app(\BookStack\Services\SearchService::class)->indexAllEntities();
     }
 }