From af0b4fa851d8acda52d6176d6e9b2aef2448b499 Mon Sep 17 00:00:00 2001
From: Dan Brown <ssddanbrown@googlemail.com>
Date: Sat, 10 Jun 2023 15:08:07 +0100
Subject: [PATCH] Search: Updated popular items query, load parent book for
 chapters/pages

Primarily intended to show parent book for chapters when moving/copying
pages, since the default parent selector interfaces, which used the
entity-selector search endpoint, would run this popular query when no
term was present as a default backup.

For #4264
---
 app/Entities/Queries/Popular.php  | 19 ++++++++++++++++++-
 app/Search/SearchController.php   |  8 +++-----
 tests/Entity/EntitySearchTest.php | 12 ++++++++++++
 3 files changed, 33 insertions(+), 6 deletions(-)

diff --git a/app/Entities/Queries/Popular.php b/app/Entities/Queries/Popular.php
index 9b7049ae3..a934f346b 100644
--- a/app/Entities/Queries/Popular.php
+++ b/app/Entities/Queries/Popular.php
@@ -3,6 +3,10 @@
 namespace BookStack\Entities\Queries;
 
 use BookStack\Activity\Models\View;
+use BookStack\Entities\Models\BookChild;
+use BookStack\Entities\Models\Entity;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+use Illuminate\Support\Collection;
 use Illuminate\Support\Facades\DB;
 
 class Popular extends EntityQuery
@@ -19,11 +23,24 @@ class Popular extends EntityQuery
             $query->whereIn('viewable_type', $this->entityProvider()->getMorphClasses($filterModels));
         }
 
-        return $query->with('viewable')
+        $entities = $query->with('viewable')
             ->skip($count * ($page - 1))
             ->take($count)
             ->get()
             ->pluck('viewable')
             ->filter();
+
+        $this->loadBooksForChildren($entities);
+
+        return $entities;
+    }
+
+    protected function loadBooksForChildren(Collection $entities)
+    {
+        $bookChildren = $entities->filter(fn(Entity $entity) => $entity instanceof BookChild);
+        $eloquent = (new \Illuminate\Database\Eloquent\Collection($bookChildren));
+        $eloquent->load(['book' => function (BelongsTo $query) {
+            $query->scopes('visible');
+        }]);
     }
 }
diff --git a/app/Search/SearchController.php b/app/Search/SearchController.php
index 4b134f11e..09a67f2b5 100644
--- a/app/Search/SearchController.php
+++ b/app/Search/SearchController.php
@@ -9,11 +9,9 @@ use Illuminate\Http\Request;
 
 class SearchController extends Controller
 {
-    protected SearchRunner $searchRunner;
-
-    public function __construct(SearchRunner $searchRunner)
-    {
-        $this->searchRunner = $searchRunner;
+    public function __construct(
+        protected SearchRunner $searchRunner
+    ) {
     }
 
     /**
diff --git a/tests/Entity/EntitySearchTest.php b/tests/Entity/EntitySearchTest.php
index af06ae72a..a070ce3fa 100644
--- a/tests/Entity/EntitySearchTest.php
+++ b/tests/Entity/EntitySearchTest.php
@@ -5,6 +5,7 @@ namespace Tests\Entity;
 use BookStack\Activity\Models\Tag;
 use BookStack\Entities\Models\Book;
 use BookStack\Entities\Models\Bookshelf;
+use BookStack\Entities\Models\Chapter;
 use Tests\TestCase;
 
 class EntitySearchTest extends TestCase
@@ -225,6 +226,17 @@ class EntitySearchTest extends TestCase
         $chapterSearch->assertSee($chapter->book->getShortName(42));
     }
 
+    public function test_entity_selector_shows_breadcrumbs_on_default_view()
+    {
+        $page = $this->entities->pageWithinChapter();
+        $this->asEditor()->get($page->chapter->getUrl());
+
+        $resp = $this->asEditor()->get('/search/entity-selector?types=book,chapter&permission=page-create');
+        $html = $this->withHtml($resp);
+        $html->assertElementContains('.chapter.entity-list-item', $page->chapter->name);
+        $html->assertElementContains('.chapter.entity-list-item .entity-item-snippet', $page->book->getShortName(42));
+    }
+
     public function test_entity_selector_search_reflects_items_without_permission()
     {
         $page = $this->entities->page();