]> BookStack Code Mirror - bookstack/blobdiff - app/Entities/Tools/SearchRunner.php
Reverted shift change to old migration
[bookstack] / app / Entities / Tools / SearchRunner.php
index acfe8d9565fdf1ea2884d337e31e0402270f6cb9..df566eb0b30b1769658659205e8a214e7fce61dc 100644 (file)
@@ -1,6 +1,9 @@
-<?php namespace BookStack\Entities\Tools;
+<?php
+
+namespace BookStack\Entities\Tools;
 
 use BookStack\Auth\Permissions\PermissionService;
+use BookStack\Auth\User;
 use BookStack\Entities\EntityProvider;
 use BookStack\Entities\Models\Entity;
 use Illuminate\Database\Connection;
@@ -12,7 +15,6 @@ use Illuminate\Support\Str;
 
 class SearchRunner
 {
-
     /**
      * @var EntityProvider
      */
@@ -28,14 +30,13 @@ class SearchRunner
      */
     protected $permissionService;
 
-
     /**
-     * Acceptable operators to be used in a query
+     * Acceptable operators to be used in a query.
+     *
      * @var array
      */
     protected $queryOperators = ['<=', '>=', '=', '<', '>', 'like', '!='];
 
-
     public function __construct(EntityProvider $entityProvider, Connection $db, PermissionService $permissionService)
     {
         $this->entityProvider = $entityProvider;
@@ -55,7 +56,7 @@ class SearchRunner
 
         if ($entityType !== 'all') {
             $entityTypesToSearch = $entityType;
-        } else if (isset($searchOpts->filters['type'])) {
+        } elseif (isset($searchOpts->filters['type'])) {
             $entityTypesToSearch = explode('|', $searchOpts->filters['type']);
         }
 
@@ -77,16 +78,15 @@ class SearchRunner
         }
 
         return [
-            'total' => $total,
-            'count' => count($results),
+            'total'    => $total,
+            'count'    => count($results),
             'has_more' => $hasMore,
-            'results' => $results->sortByDesc('score')->values(),
+            'results'  => $results->sortByDesc('score')->values(),
         ];
     }
 
-
     /**
-     * Search a book for entities
+     * Search a book for entities.
      */
     public function searchBook(int $bookId, string $searchString): Collection
     {
@@ -107,12 +107,13 @@ class SearchRunner
     }
 
     /**
-     * Search a chapter for entities
+     * Search a chapter for entities.
      */
     public function searchChapter(int $chapterId, string $searchString): Collection
     {
         $opts = SearchOptions::fromString($searchString);
         $pages = $this->buildEntitySearchQuery($opts, 'page')->where('chapter_id', '=', $chapterId)->take(20)->get();
+
         return $pages->sortByDesc('score');
     }
 
@@ -120,6 +121,7 @@ class SearchRunner
      * 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[]
      */
     protected function searchEntityTable(SearchOptions $searchOpts, string $entityType = 'page', int $page = 1, int $count = 20, string $action = 'view', bool $getCount = false)
@@ -129,12 +131,13 @@ class SearchRunner
             return $query->count();
         }
 
-        $query = $query->skip(($page-1) * $count)->take($count);
+        $query = $query->skip(($page - 1) * $count)->take($count);
+
         return $query->get();
     }
 
     /**
-     * Create a search query for an entity
+     * Create a search query for an entity.
      */
     protected function buildEntitySearchQuery(SearchOptions $searchOpts, string $entityType = 'page', string $action = 'view'): EloquentBuilder
     {
@@ -148,20 +151,22 @@ class SearchRunner
             $subQuery->where('entity_type', '=', $entity->getMorphClass());
             $subQuery->where(function (Builder $query) use ($searchOpts) {
                 foreach ($searchOpts->searches as $inputTerm) {
-                    $query->orWhere('term', 'like', $inputTerm .'%');
+                    $query->orWhere('term', 'like', $inputTerm . '%');
                 }
             })->groupBy('entity_type', 'entity_id');
             $entitySelect->join($this->db->raw('(' . $subQuery->toSql() . ') as s'), function (JoinClause $join) {
                 $join->on('id', '=', 'entity_id');
-            })->selectRaw($entity->getTable().'.*, s.score')->orderBy('score', 'desc');
+            })->addSelect($entity->getTable() . '.*')
+                ->selectRaw('s.score')
+                ->orderBy('score', 'desc');
             $entitySelect->mergeBindings($subQuery);
         }
 
         // Handle exact term matching
         foreach ($searchOpts->exacts as $inputTerm) {
             $entitySelect->where(function (EloquentBuilder $query) use ($inputTerm, $entity) {
-                $query->where('name', 'like', '%'.$inputTerm .'%')
-                    ->orWhere($entity->textField, 'like', '%'.$inputTerm .'%');
+                $query->where('name', 'like', '%' . $inputTerm . '%')
+                    ->orWhere($entity->textField, 'like', '%' . $inputTerm . '%');
             });
         }
 
@@ -178,7 +183,7 @@ class SearchRunner
             }
         }
 
-        return $this->permissionService->enforceEntityRestrictions($entityType, $entitySelect, $action);
+        return $this->permissionService->enforceEntityRestrictions($entity, $entitySelect, $action);
     }
 
     /**
@@ -190,7 +195,8 @@ class SearchRunner
         foreach ($this->queryOperators as $operator) {
             $escapedOperators[] = preg_quote($operator);
         }
-        return join('|', $escapedOperators);
+
+        return implode('|', $escapedOperators);
     }
 
     /**
@@ -198,7 +204,7 @@ class SearchRunner
      */
     protected function applyTagSearch(EloquentBuilder $query, string $tagTerm): EloquentBuilder
     {
-        preg_match("/^(.*?)((".$this->getRegexEscapedOperators().")(.*?))?$/", $tagTerm, $tagSplit);
+        preg_match('/^(.*?)((' . $this->getRegexEscapedOperators() . ')(.*?))?$/', $tagTerm, $tagSplit);
         $query->whereHas('tags', function (EloquentBuilder $query) use ($tagSplit) {
             $tagName = $tagSplit[1];
             $tagOperator = count($tagSplit) > 2 ? $tagSplit[3] : '';
@@ -221,13 +227,13 @@ class SearchRunner
                 $query->where('name', '=', $tagName);
             }
         });
+
         return $query;
     }
 
     /**
-     * Custom entity search filters
+     * Custom entity search filters.
      */
-
     protected function filterUpdatedAfter(EloquentBuilder $query, Entity $model, $input)
     {
         try {
@@ -270,29 +276,34 @@ class SearchRunner
 
     protected function filterCreatedBy(EloquentBuilder $query, Entity $model, $input)
     {
-        if (!is_numeric($input) && $input !== 'me') {
-            return;
-        }
-        if ($input === 'me') {
-            $input = user()->id;
+        $userSlug = $input === 'me' ? user()->slug : trim($input);
+        $user = User::query()->where('slug', '=', $userSlug)->first(['id']);
+        if ($user) {
+            $query->where('created_by', '=', $user->id);
         }
-        $query->where('created_by', '=', $input);
     }
 
     protected function filterUpdatedBy(EloquentBuilder $query, Entity $model, $input)
     {
-        if (!is_numeric($input) && $input !== 'me') {
-            return;
+        $userSlug = $input === 'me' ? user()->slug : trim($input);
+        $user = User::query()->where('slug', '=', $userSlug)->first(['id']);
+        if ($user) {
+            $query->where('updated_by', '=', $user->id);
         }
-        if ($input === 'me') {
-            $input = user()->id;
+    }
+
+    protected function filterOwnedBy(EloquentBuilder $query, Entity $model, $input)
+    {
+        $userSlug = $input === 'me' ? user()->slug : trim($input);
+        $user = User::query()->where('slug', '=', $userSlug)->first(['id']);
+        if ($user) {
+            $query->where('owned_by', '=', $user->id);
         }
-        $query->where('updated_by', '=', $input);
     }
 
     protected function filterInName(EloquentBuilder $query, Entity $model, $input)
     {
-        $query->where('name', 'like', '%' .$input. '%');
+        $query->where('name', 'like', '%' . $input . '%');
     }
 
     protected function filterInTitle(EloquentBuilder $query, Entity $model, $input)
@@ -302,7 +313,7 @@ class SearchRunner
 
     protected function filterInBody(EloquentBuilder $query, Entity $model, $input)
     {
-        $query->where($model->textField, 'like', '%' .$input. '%');
+        $query->where($model->textField, 'like', '%' . $input . '%');
     }
 
     protected function filterIsRestricted(EloquentBuilder $query, Entity $model, $input)
@@ -332,16 +343,14 @@ class SearchRunner
         }
     }
 
-
     /**
-     * Sorting filter options
+     * Sorting filter options.
      */
-
     protected function sortByLastCommented(EloquentBuilder $query, Entity $model)
     {
         $commentsTable = $this->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 = $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');
 
         $query->join($commentQuery, $model->getTable() . '.id', '=', 'comments.entity_id')->orderBy('last_commented', 'desc');
     }