diff --git a/app/Console/Commands/RegenerateReferences.php b/app/Console/Commands/RegenerateReferences.php
index 93450c5ea..805db2207 100644
--- a/app/Console/Commands/RegenerateReferences.php
+++ b/app/Console/Commands/RegenerateReferences.php
@@ -2,7 +2,7 @@
namespace BookStack\Console\Commands;
-use BookStack\References\ReferenceService;
+use BookStack\References\ReferenceStore;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
@@ -22,14 +22,14 @@ class RegenerateReferences extends Command
*/
protected $description = 'Regenerate all the cross-item model reference index';
- protected ReferenceService $references;
+ protected ReferenceStore $references;
/**
* Create a new command instance.
*
* @return void
*/
- public function __construct(ReferenceService $references)
+ public function __construct(ReferenceStore $references)
{
$this->references = $references;
parent::__construct();
diff --git a/app/Entities/Repos/PageRepo.php b/app/Entities/Repos/PageRepo.php
index 09c664edc..40d1e6e53 100644
--- a/app/Entities/Repos/PageRepo.php
+++ b/app/Entities/Repos/PageRepo.php
@@ -16,7 +16,7 @@ use BookStack\Exceptions\MoveOperationException;
use BookStack\Exceptions\NotFoundException;
use BookStack\Exceptions\PermissionsException;
use BookStack\Facades\Activity;
-use BookStack\References\ReferenceService;
+use BookStack\References\ReferenceStore;
use Exception;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Pagination\LengthAwarePaginator;
@@ -24,12 +24,12 @@ use Illuminate\Pagination\LengthAwarePaginator;
class PageRepo
{
protected BaseRepo $baseRepo;
- protected ReferenceService $references;
+ protected ReferenceStore $references;
/**
* PageRepo constructor.
*/
- public function __construct(BaseRepo $baseRepo, ReferenceService $references)
+ public function __construct(BaseRepo $baseRepo, ReferenceStore $references)
{
$this->baseRepo = $baseRepo;
$this->references = $references;
diff --git a/app/Http/Controllers/BookController.php b/app/Http/Controllers/BookController.php
index c5b6d0bf6..a041267bb 100644
--- a/app/Http/Controllers/BookController.php
+++ b/app/Http/Controllers/BookController.php
@@ -15,19 +15,22 @@ use BookStack\Entities\Tools\ShelfContext;
use BookStack\Exceptions\ImageUploadException;
use BookStack\Exceptions\NotFoundException;
use BookStack\Facades\Activity;
+use BookStack\References\ReferenceFetcher;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
use Throwable;
class BookController extends Controller
{
- protected $bookRepo;
- protected $entityContextManager;
+ protected BookRepo $bookRepo;
+ protected ShelfContext $shelfContext;
+ protected ReferenceFetcher $referenceFetcher;
- public function __construct(ShelfContext $entityContextManager, BookRepo $bookRepo)
+ public function __construct(ShelfContext $entityContextManager, BookRepo $bookRepo, ReferenceFetcher $referenceFetcher)
{
$this->bookRepo = $bookRepo;
- $this->entityContextManager = $entityContextManager;
+ $this->shelfContext = $entityContextManager;
+ $this->referenceFetcher = $referenceFetcher;
}
/**
@@ -44,7 +47,7 @@ class BookController extends Controller
$popular = $this->bookRepo->getPopular(4);
$new = $this->bookRepo->getRecentlyCreated(4);
- $this->entityContextManager->clearShelfContext();
+ $this->shelfContext->clearShelfContext();
$this->setPageTitle(trans('entities.books'));
@@ -122,7 +125,7 @@ class BookController extends Controller
View::incrementFor($book);
if ($request->has('shelf')) {
- $this->entityContextManager->setShelfContext(intval($request->get('shelf')));
+ $this->shelfContext->setShelfContext(intval($request->get('shelf')));
}
$this->setPageTitle($book->getShortName());
@@ -133,6 +136,7 @@ class BookController extends Controller
'bookChildren' => $bookChildren,
'bookParentShelves' => $bookParentShelves,
'activity' => $activities->entityActivity($book, 20, 1),
+ 'referenceCount' => $this->referenceFetcher->getPageReferenceCountToEntity($book),
]);
}
diff --git a/app/Http/Controllers/BookshelfController.php b/app/Http/Controllers/BookshelfController.php
index ccbeb6484..2143b876a 100644
--- a/app/Http/Controllers/BookshelfController.php
+++ b/app/Http/Controllers/BookshelfController.php
@@ -10,6 +10,7 @@ use BookStack\Entities\Tools\PermissionsUpdater;
use BookStack\Entities\Tools\ShelfContext;
use BookStack\Exceptions\ImageUploadException;
use BookStack\Exceptions\NotFoundException;
+use BookStack\References\ReferenceFetcher;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
@@ -18,11 +19,13 @@ class BookshelfController extends Controller
{
protected BookshelfRepo $shelfRepo;
protected ShelfContext $shelfContext;
+ protected ReferenceFetcher $referenceFetcher;
- public function __construct(BookshelfRepo $shelfRepo, ShelfContext $shelfContext)
+ public function __construct(BookshelfRepo $shelfRepo, ShelfContext $shelfContext, ReferenceFetcher $referenceFetcher)
{
$this->shelfRepo = $shelfRepo;
$this->shelfContext = $shelfContext;
+ $this->referenceFetcher = $referenceFetcher;
}
/**
@@ -124,6 +127,7 @@ class BookshelfController extends Controller
'activity' => $activities->entityActivity($shelf, 20, 1),
'order' => $order,
'sort' => $sort,
+ 'referenceCount' => $this->referenceFetcher->getPageReferenceCountToEntity($shelf),
]);
}
diff --git a/app/Http/Controllers/ChapterController.php b/app/Http/Controllers/ChapterController.php
index 60eb52380..735c760be 100644
--- a/app/Http/Controllers/ChapterController.php
+++ b/app/Http/Controllers/ChapterController.php
@@ -13,20 +13,21 @@ use BookStack\Entities\Tools\PermissionsUpdater;
use BookStack\Exceptions\MoveOperationException;
use BookStack\Exceptions\NotFoundException;
use BookStack\Exceptions\PermissionsException;
+use BookStack\References\ReferenceFetcher;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
use Throwable;
class ChapterController extends Controller
{
- protected $chapterRepo;
+ protected ChapterRepo $chapterRepo;
+ protected ReferenceFetcher $referenceFetcher;
- /**
- * ChapterController constructor.
- */
- public function __construct(ChapterRepo $chapterRepo)
+
+ public function __construct(ChapterRepo $chapterRepo, ReferenceFetcher $referenceFetcher)
{
$this->chapterRepo = $chapterRepo;
+ $this->referenceFetcher = $referenceFetcher;
}
/**
@@ -77,13 +78,14 @@ class ChapterController extends Controller
$this->setPageTitle($chapter->getShortName());
return view('chapters.show', [
- 'book' => $chapter->book,
- 'chapter' => $chapter,
- 'current' => $chapter,
- 'sidebarTree' => $sidebarTree,
- 'pages' => $pages,
- 'next' => $nextPreviousLocator->getNext(),
- 'previous' => $nextPreviousLocator->getPrevious(),
+ 'book' => $chapter->book,
+ 'chapter' => $chapter,
+ 'current' => $chapter,
+ 'sidebarTree' => $sidebarTree,
+ 'pages' => $pages,
+ 'next' => $nextPreviousLocator->getNext(),
+ 'previous' => $nextPreviousLocator->getPrevious(),
+ 'referenceCount' => $this->referenceFetcher->getPageReferenceCountToEntity($chapter),
]);
}
diff --git a/app/Http/Controllers/PageController.php b/app/Http/Controllers/PageController.php
index 268dce057..748468b21 100644
--- a/app/Http/Controllers/PageController.php
+++ b/app/Http/Controllers/PageController.php
@@ -14,6 +14,7 @@ use BookStack\Entities\Tools\PageEditorData;
use BookStack\Entities\Tools\PermissionsUpdater;
use BookStack\Exceptions\NotFoundException;
use BookStack\Exceptions\PermissionsException;
+use BookStack\References\ReferenceFetcher;
use Exception;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Http\Request;
@@ -23,13 +24,15 @@ use Throwable;
class PageController extends Controller
{
protected PageRepo $pageRepo;
+ protected ReferenceFetcher $referenceFetcher;
/**
* PageController constructor.
*/
- public function __construct(PageRepo $pageRepo)
+ public function __construct(PageRepo $pageRepo, ReferenceFetcher $referenceFetcher)
{
$this->pageRepo = $pageRepo;
+ $this->referenceFetcher = $referenceFetcher;
}
/**
@@ -160,6 +163,7 @@ class PageController extends Controller
'pageNav' => $pageNav,
'next' => $nextPreviousLocator->getNext(),
'previous' => $nextPreviousLocator->getPrevious(),
+ 'referenceCount' => $this->referenceFetcher->getPageReferenceCountToEntity($page),
]);
}
diff --git a/app/Http/Controllers/ReferenceController.php b/app/Http/Controllers/ReferenceController.php
index 3af4feb06..07b143223 100644
--- a/app/Http/Controllers/ReferenceController.php
+++ b/app/Http/Controllers/ReferenceController.php
@@ -2,23 +2,19 @@
namespace BookStack\Http\Controllers;
-use BookStack\Auth\Permissions\PermissionApplicator;
use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\Bookshelf;
use BookStack\Entities\Models\Chapter;
-use BookStack\Entities\Models\Entity;
use BookStack\Entities\Models\Page;
-use Illuminate\Database\Eloquent\Collection;
-use Illuminate\Database\Eloquent\Relations\Relation;
+use BookStack\References\ReferenceFetcher;
class ReferenceController extends Controller
{
+ protected ReferenceFetcher $referenceFetcher;
- protected PermissionApplicator $permissions;
-
- public function __construct(PermissionApplicator $permissions)
+ public function __construct(ReferenceFetcher $referenceFetcher)
{
- $this->permissions = $permissions;
+ $this->referenceFetcher = $referenceFetcher;
}
/**
@@ -28,7 +24,7 @@ class ReferenceController extends Controller
{
/** @var Page $page */
$page = Page::visible()->whereSlugs($bookSlug, $pageSlug)->firstOrFail();
- $references = $this->getEntityReferences($page);
+ $references = $this->referenceFetcher->getPageReferencesToEntity($page);
return view('pages.references', [
'page' => $page,
@@ -43,7 +39,7 @@ class ReferenceController extends Controller
{
/** @var Chapter $chapter */
$chapter = Chapter::visible()->whereSlugs($bookSlug, $chapterSlug)->firstOrFail();
- $references = $this->getEntityReferences($chapter);
+ $references = $this->referenceFetcher->getPageReferencesToEntity($chapter);
return view('chapters.references', [
'chapter' => $chapter,
@@ -57,7 +53,7 @@ class ReferenceController extends Controller
public function book(string $slug)
{
$book = Book::visible()->where('slug', '=', $slug)->firstOrFail();
- $references = $this->getEntityReferences($book);
+ $references = $this->referenceFetcher->getPageReferencesToEntity($book);
return view('books.references', [
'book' => $book,
@@ -71,35 +67,11 @@ class ReferenceController extends Controller
public function shelf(string $slug)
{
$shelf = Bookshelf::visible()->where('slug', '=', $slug)->firstOrFail();
- $references = $this->getEntityReferences($shelf);
+ $references = $this->referenceFetcher->getPageReferencesToEntity($shelf);
return view('shelves.references', [
'shelf' => $shelf,
'references' => $references,
]);
}
-
- /**
- * Query the references for the given entities.
- * Loads the commonly required relations while taking permissions into account.
- */
- protected function getEntityReferences(Entity $entity): Collection
- {
- $baseQuery = $entity->referencesTo()
- ->where('from_type', '=', (new Page())->getMorphClass())
- ->with([
- 'from' => fn(Relation $query) => $query->select(Page::$listAttributes),
- 'from.book' => fn(Relation $query) => $query->scopes('visible'),
- 'from.chapter' => fn(Relation $query) => $query->scopes('visible')
- ]);
-
- $references = $this->permissions->restrictEntityRelationQuery(
- $baseQuery,
- 'references',
- 'from_id',
- 'from_type'
- )->get();
-
- return $references;
- }
}
diff --git a/app/References/ReferenceFetcher.php b/app/References/ReferenceFetcher.php
new file mode 100644
index 000000000..fef2744d7
--- /dev/null
+++ b/app/References/ReferenceFetcher.php
@@ -0,0 +1,62 @@
+permissions = $permissions;
+ }
+
+ /**
+ * Query and return the page references pointing to the given entity.
+ * Loads the commonly required relations while taking permissions into account.
+ */
+ public function getPageReferencesToEntity(Entity $entity): Collection
+ {
+ $baseQuery = $entity->referencesTo()
+ ->where('from_type', '=', (new Page())->getMorphClass())
+ ->with([
+ 'from' => fn(Relation $query) => $query->select(Page::$listAttributes),
+ 'from.book' => fn(Relation $query) => $query->scopes('visible'),
+ 'from.chapter' => fn(Relation $query) => $query->scopes('visible')
+ ]);
+
+ $references = $this->permissions->restrictEntityRelationQuery(
+ $baseQuery,
+ 'references',
+ 'from_id',
+ 'from_type'
+ )->get();
+
+ return $references;
+ }
+
+ /**
+ * Returns the count of page references pointing to the given entity.
+ * Takes permissions into account.
+ */
+ public function getPageReferenceCountToEntity(Entity $entity): int
+ {
+ $baseQuery = $entity->referencesTo()
+ ->where('from_type', '=', (new Page())->getMorphClass());
+
+ $count = $this->permissions->restrictEntityRelationQuery(
+ $baseQuery,
+ 'references',
+ 'from_id',
+ 'from_type'
+ )->count();
+
+ return $count;
+ }
+}
\ No newline at end of file
diff --git a/app/References/ReferenceService.php b/app/References/ReferenceStore.php
similarity index 98%
rename from app/References/ReferenceService.php
rename to app/References/ReferenceStore.php
index fd7f74ae1..f6e3c04a3 100644
--- a/app/References/ReferenceService.php
+++ b/app/References/ReferenceStore.php
@@ -5,7 +5,7 @@ namespace BookStack\References;
use BookStack\Entities\Models\Page;
use Illuminate\Database\Eloquent\Collection;
-class ReferenceService
+class ReferenceStore
{
/**
diff --git a/resources/lang/en/entities.php b/resources/lang/en/entities.php
index a92b465b8..527665f88 100644
--- a/resources/lang/en/entities.php
+++ b/resources/lang/en/entities.php
@@ -23,6 +23,7 @@ return [
'meta_updated' => 'Updated :timeLength',
'meta_updated_name' => 'Updated :timeLength by :user',
'meta_owned_name' => 'Owned by :user',
+ 'meta_reference_page_count' => 'Referenced on 1 page|Referenced on :count pages',
'entity_select' => 'Entity Select',
'entity_select_lack_permission' => 'You don\'t have the required permissions to select this item',
'images' => 'Images',
diff --git a/resources/views/entities/meta.blade.php b/resources/views/entities/meta.blade.php
index 83ff23762..ac91eeed3 100644
--- a/resources/views/entities/meta.blade.php
+++ b/resources/views/entities/meta.blade.php
@@ -59,4 +59,13 @@
{{ trans('entities.meta_updated', ['timeLength' => $entity->updated_at->diffForHumans()]) }}
@endif
+
+ @if($referenceCount ?? 0)
+
+ @icon('reference')
+
+ {!! trans_choice('entities.meta_reference_page_count', $referenceCount, ['count' => $referenceCount]) !!}
+
+
+ @endif
\ No newline at end of file
diff --git a/tests/References/ReferencesTest.php b/tests/References/ReferencesTest.php
index 20829b6b4..9ae226bb7 100644
--- a/tests/References/ReferencesTest.php
+++ b/tests/References/ReferencesTest.php
@@ -54,6 +54,28 @@ class ReferencesTest extends TestCase
$this->assertDatabaseMissing('references', ['to_id' => $pageA->id, 'to_type' => $pageA->getMorphClass()]);
}
+ public function test_references_to_count_visible_on_entity_show_view()
+ {
+ $entities = $this->getEachEntityType();
+ /** @var Page $otherPage */
+ $otherPage = Page::query()->where('id', '!=', $entities['page']->id)->first();
+
+ $this->asEditor();
+ foreach ($entities as $entity) {
+ $this->createReference($entities['page'], $entity);
+ }
+
+ foreach ($entities as $entity) {
+ $resp = $this->get($entity->getUrl());
+ $resp->assertSee('Referenced on 1 page');
+ $resp->assertDontSee('Referenced on 1 pages');
+ }
+
+ $this->createReference($otherPage, $entities['page']);
+ $resp = $this->get($entities['page']->getUrl());
+ $resp->assertSee('Referenced on 2 pages');
+ }
+
public function test_references_to_visible_on_references_page()
{
$entities = $this->getEachEntityType();