Queries: Extracted chapter repo queries to class

Updated query classes to align to interface for common aligned
operations.
Extracted repeated string-identifier-based finding from page/chapter
repos to shared higher-level entity queries.
This commit is contained in:
Dan Brown 2024-02-05 15:59:20 +00:00
parent 3886aedf54
commit 8e78b4c43e
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9
12 changed files with 160 additions and 102 deletions

View File

@ -5,6 +5,8 @@ namespace BookStack\Entities\Controllers;
use BookStack\Activity\Models\View; use BookStack\Activity\Models\View;
use BookStack\Activity\Tools\UserEntityWatchOptions; use BookStack\Activity\Tools\UserEntityWatchOptions;
use BookStack\Entities\Models\Book; use BookStack\Entities\Models\Book;
use BookStack\Entities\Queries\ChapterQueries;
use BookStack\Entities\Queries\EntityQueries;
use BookStack\Entities\Repos\ChapterRepo; use BookStack\Entities\Repos\ChapterRepo;
use BookStack\Entities\Tools\BookContents; use BookStack\Entities\Tools\BookContents;
use BookStack\Entities\Tools\Cloner; use BookStack\Entities\Tools\Cloner;
@ -24,7 +26,9 @@ class ChapterController extends Controller
{ {
public function __construct( public function __construct(
protected ChapterRepo $chapterRepo, protected ChapterRepo $chapterRepo,
protected ReferenceFetcher $referenceFetcher protected ChapterQueries $queries,
protected EntityQueries $entityQueries,
protected ReferenceFetcher $referenceFetcher,
) { ) {
} }
@ -33,12 +37,15 @@ class ChapterController extends Controller
*/ */
public function create(string $bookSlug) public function create(string $bookSlug)
{ {
$book = Book::visible()->where('slug', '=', $bookSlug)->firstOrFail(); $book = $this->entityQueries->books->findVisibleBySlug($bookSlug);
$this->checkOwnablePermission('chapter-create', $book); $this->checkOwnablePermission('chapter-create', $book);
$this->setPageTitle(trans('entities.chapters_create')); $this->setPageTitle(trans('entities.chapters_create'));
return view('chapters.create', ['book' => $book, 'current' => $book]); return view('chapters.create', [
'book' => $book,
'current' => $book,
]);
} }
/** /**
@ -55,7 +62,7 @@ class ChapterController extends Controller
'default_template_id' => ['nullable', 'integer'], 'default_template_id' => ['nullable', 'integer'],
]); ]);
$book = Book::visible()->where('slug', '=', $bookSlug)->firstOrFail(); $book = $this->entityQueries->books->findVisibleBySlug($bookSlug);
$this->checkOwnablePermission('chapter-create', $book); $this->checkOwnablePermission('chapter-create', $book);
$chapter = $this->chapterRepo->create($validated, $book); $chapter = $this->chapterRepo->create($validated, $book);
@ -68,7 +75,7 @@ class ChapterController extends Controller
*/ */
public function show(string $bookSlug, string $chapterSlug) public function show(string $bookSlug, string $chapterSlug)
{ {
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); $chapter = $this->queries->findVisibleBySlugs($bookSlug, $chapterSlug);
$this->checkOwnablePermission('chapter-view', $chapter); $this->checkOwnablePermission('chapter-view', $chapter);
$sidebarTree = (new BookContents($chapter->book))->getTree(); $sidebarTree = (new BookContents($chapter->book))->getTree();
@ -96,7 +103,7 @@ class ChapterController extends Controller
*/ */
public function edit(string $bookSlug, string $chapterSlug) public function edit(string $bookSlug, string $chapterSlug)
{ {
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); $chapter = $this->queries->findVisibleBySlugs($bookSlug, $chapterSlug);
$this->checkOwnablePermission('chapter-update', $chapter); $this->checkOwnablePermission('chapter-update', $chapter);
$this->setPageTitle(trans('entities.chapters_edit_named', ['chapterName' => $chapter->getShortName()])); $this->setPageTitle(trans('entities.chapters_edit_named', ['chapterName' => $chapter->getShortName()]));
@ -118,7 +125,7 @@ class ChapterController extends Controller
'default_template_id' => ['nullable', 'integer'], 'default_template_id' => ['nullable', 'integer'],
]); ]);
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); $chapter = $this->queries->findVisibleBySlugs($bookSlug, $chapterSlug);
$this->checkOwnablePermission('chapter-update', $chapter); $this->checkOwnablePermission('chapter-update', $chapter);
$this->chapterRepo->update($chapter, $validated); $this->chapterRepo->update($chapter, $validated);
@ -133,7 +140,7 @@ class ChapterController extends Controller
*/ */
public function showDelete(string $bookSlug, string $chapterSlug) public function showDelete(string $bookSlug, string $chapterSlug)
{ {
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); $chapter = $this->queries->findVisibleBySlugs($bookSlug, $chapterSlug);
$this->checkOwnablePermission('chapter-delete', $chapter); $this->checkOwnablePermission('chapter-delete', $chapter);
$this->setPageTitle(trans('entities.chapters_delete_named', ['chapterName' => $chapter->getShortName()])); $this->setPageTitle(trans('entities.chapters_delete_named', ['chapterName' => $chapter->getShortName()]));
@ -149,7 +156,7 @@ class ChapterController extends Controller
*/ */
public function destroy(string $bookSlug, string $chapterSlug) public function destroy(string $bookSlug, string $chapterSlug)
{ {
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); $chapter = $this->queries->findVisibleBySlugs($bookSlug, $chapterSlug);
$this->checkOwnablePermission('chapter-delete', $chapter); $this->checkOwnablePermission('chapter-delete', $chapter);
$this->chapterRepo->destroy($chapter); $this->chapterRepo->destroy($chapter);
@ -164,7 +171,7 @@ class ChapterController extends Controller
*/ */
public function showMove(string $bookSlug, string $chapterSlug) public function showMove(string $bookSlug, string $chapterSlug)
{ {
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); $chapter = $this->queries->findVisibleBySlugs($bookSlug, $chapterSlug);
$this->setPageTitle(trans('entities.chapters_move_named', ['chapterName' => $chapter->getShortName()])); $this->setPageTitle(trans('entities.chapters_move_named', ['chapterName' => $chapter->getShortName()]));
$this->checkOwnablePermission('chapter-update', $chapter); $this->checkOwnablePermission('chapter-update', $chapter);
$this->checkOwnablePermission('chapter-delete', $chapter); $this->checkOwnablePermission('chapter-delete', $chapter);
@ -182,7 +189,7 @@ class ChapterController extends Controller
*/ */
public function move(Request $request, string $bookSlug, string $chapterSlug) public function move(Request $request, string $bookSlug, string $chapterSlug)
{ {
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); $chapter = $this->queries->findVisibleBySlugs($bookSlug, $chapterSlug);
$this->checkOwnablePermission('chapter-update', $chapter); $this->checkOwnablePermission('chapter-update', $chapter);
$this->checkOwnablePermission('chapter-delete', $chapter); $this->checkOwnablePermission('chapter-delete', $chapter);
@ -211,7 +218,7 @@ class ChapterController extends Controller
*/ */
public function showCopy(string $bookSlug, string $chapterSlug) public function showCopy(string $bookSlug, string $chapterSlug)
{ {
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); $chapter = $this->queries->findVisibleBySlugs($bookSlug, $chapterSlug);
$this->checkOwnablePermission('chapter-view', $chapter); $this->checkOwnablePermission('chapter-view', $chapter);
session()->flashInput(['name' => $chapter->name]); session()->flashInput(['name' => $chapter->name]);
@ -230,13 +237,13 @@ class ChapterController extends Controller
*/ */
public function copy(Request $request, Cloner $cloner, string $bookSlug, string $chapterSlug) public function copy(Request $request, Cloner $cloner, string $bookSlug, string $chapterSlug)
{ {
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); $chapter = $this->queries->findVisibleBySlugs($bookSlug, $chapterSlug);
$this->checkOwnablePermission('chapter-view', $chapter); $this->checkOwnablePermission('chapter-view', $chapter);
$entitySelection = $request->get('entity_selection') ?: null; $entitySelection = $request->get('entity_selection') ?: null;
$newParentBook = $entitySelection ? $this->chapterRepo->findParentByIdentifier($entitySelection) : $chapter->getParent(); $newParentBook = $entitySelection ? $this->entityQueries->findVisibleByStringIdentifier($entitySelection) : $chapter->getParent();
if (is_null($newParentBook)) { if (!$newParentBook instanceof Book) {
$this->showErrorNotification(trans('errors.selected_book_not_found')); $this->showErrorNotification(trans('errors.selected_book_not_found'));
return redirect($chapter->getUrl('/copy')); return redirect($chapter->getUrl('/copy'));
@ -256,7 +263,7 @@ class ChapterController extends Controller
*/ */
public function convertToBook(HierarchyTransformer $transformer, string $bookSlug, string $chapterSlug) public function convertToBook(HierarchyTransformer $transformer, string $bookSlug, string $chapterSlug)
{ {
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); $chapter = $this->queries->findVisibleBySlugs($bookSlug, $chapterSlug);
$this->checkOwnablePermission('chapter-update', $chapter); $this->checkOwnablePermission('chapter-update', $chapter);
$this->checkOwnablePermission('chapter-delete', $chapter); $this->checkOwnablePermission('chapter-delete', $chapter);
$this->checkPermission('book-create-all'); $this->checkPermission('book-create-all');

View File

@ -2,7 +2,7 @@
namespace BookStack\Entities\Controllers; namespace BookStack\Entities\Controllers;
use BookStack\Entities\Repos\ChapterRepo; use BookStack\Entities\Queries\ChapterQueries;
use BookStack\Entities\Tools\ExportFormatter; use BookStack\Entities\Tools\ExportFormatter;
use BookStack\Exceptions\NotFoundException; use BookStack\Exceptions\NotFoundException;
use BookStack\Http\Controller; use BookStack\Http\Controller;
@ -10,16 +10,10 @@ use Throwable;
class ChapterExportController extends Controller class ChapterExportController extends Controller
{ {
protected $chapterRepo; public function __construct(
protected $exportFormatter; protected ChapterQueries $queries,
protected ExportFormatter $exportFormatter,
/** ) {
* ChapterExportController constructor.
*/
public function __construct(ChapterRepo $chapterRepo, ExportFormatter $exportFormatter)
{
$this->chapterRepo = $chapterRepo;
$this->exportFormatter = $exportFormatter;
$this->middleware('can:content-export'); $this->middleware('can:content-export');
} }
@ -31,7 +25,7 @@ class ChapterExportController extends Controller
*/ */
public function pdf(string $bookSlug, string $chapterSlug) public function pdf(string $bookSlug, string $chapterSlug)
{ {
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); $chapter = $this->queries->findVisibleBySlugs($bookSlug, $chapterSlug);
$pdfContent = $this->exportFormatter->chapterToPdf($chapter); $pdfContent = $this->exportFormatter->chapterToPdf($chapter);
return $this->download()->directly($pdfContent, $chapterSlug . '.pdf'); return $this->download()->directly($pdfContent, $chapterSlug . '.pdf');
@ -45,7 +39,7 @@ class ChapterExportController extends Controller
*/ */
public function html(string $bookSlug, string $chapterSlug) public function html(string $bookSlug, string $chapterSlug)
{ {
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); $chapter = $this->queries->findVisibleBySlugs($bookSlug, $chapterSlug);
$containedHtml = $this->exportFormatter->chapterToContainedHtml($chapter); $containedHtml = $this->exportFormatter->chapterToContainedHtml($chapter);
return $this->download()->directly($containedHtml, $chapterSlug . '.html'); return $this->download()->directly($containedHtml, $chapterSlug . '.html');
@ -58,7 +52,7 @@ class ChapterExportController extends Controller
*/ */
public function plainText(string $bookSlug, string $chapterSlug) public function plainText(string $bookSlug, string $chapterSlug)
{ {
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); $chapter = $this->queries->findVisibleBySlugs($bookSlug, $chapterSlug);
$chapterText = $this->exportFormatter->chapterToPlainText($chapter); $chapterText = $this->exportFormatter->chapterToPlainText($chapter);
return $this->download()->directly($chapterText, $chapterSlug . '.txt'); return $this->download()->directly($chapterText, $chapterSlug . '.txt');
@ -71,7 +65,7 @@ class ChapterExportController extends Controller
*/ */
public function markdown(string $bookSlug, string $chapterSlug) public function markdown(string $bookSlug, string $chapterSlug)
{ {
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); $chapter = $this->queries->findVisibleBySlugs($bookSlug, $chapterSlug);
$chapterText = $this->exportFormatter->chapterToMarkdown($chapter); $chapterText = $this->exportFormatter->chapterToMarkdown($chapter);
return $this->download()->directly($chapterText, $chapterSlug . '.md'); return $this->download()->directly($chapterText, $chapterSlug . '.md');

View File

@ -8,6 +8,8 @@ use BookStack\Activity\Tools\UserEntityWatchOptions;
use BookStack\Entities\Models\Book; use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\Chapter; use BookStack\Entities\Models\Chapter;
use BookStack\Entities\Models\Page; use BookStack\Entities\Models\Page;
use BookStack\Entities\Queries\EntityQueries;
use BookStack\Entities\Queries\PageQueries;
use BookStack\Entities\Repos\PageRepo; use BookStack\Entities\Repos\PageRepo;
use BookStack\Entities\Tools\BookContents; use BookStack\Entities\Tools\BookContents;
use BookStack\Entities\Tools\Cloner; use BookStack\Entities\Tools\Cloner;
@ -29,6 +31,8 @@ class PageController extends Controller
{ {
public function __construct( public function __construct(
protected PageRepo $pageRepo, protected PageRepo $pageRepo,
protected PageQueries $pageQueries,
protected EntityQueries $entityQueries,
protected ReferenceFetcher $referenceFetcher protected ReferenceFetcher $referenceFetcher
) { ) {
} }
@ -435,9 +439,9 @@ class PageController extends Controller
$this->checkOwnablePermission('page-view', $page); $this->checkOwnablePermission('page-view', $page);
$entitySelection = $request->get('entity_selection') ?: null; $entitySelection = $request->get('entity_selection') ?: null;
$newParent = $entitySelection ? $this->pageRepo->findParentByIdentifier($entitySelection) : $page->getParent(); $newParent = $entitySelection ? $this->entityQueries->findVisibleByStringIdentifier($entitySelection) : $page->getParent();
if (is_null($newParent)) { if (!$newParent instanceof Book && !$newParent instanceof Chapter) {
$this->showErrorNotification(trans('errors.selected_book_chapter_not_found')); $this->showErrorNotification(trans('errors.selected_book_chapter_not_found'));
return redirect($page->getUrl('/copy')); return redirect($page->getUrl('/copy'));

View File

@ -11,7 +11,6 @@ use Illuminate\Support\Collection;
* Class Chapter. * Class Chapter.
* *
* @property Collection<Page> $pages * @property Collection<Page> $pages
* @property string $description
* @property ?int $default_template_id * @property ?int $default_template_id
* @property ?Page $defaultTemplate * @property ?Page $defaultTemplate
*/ */

View File

@ -6,13 +6,18 @@ use BookStack\Entities\Models\Book;
use BookStack\Exceptions\NotFoundException; use BookStack\Exceptions\NotFoundException;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
class BookQueries class BookQueries implements ProvidesEntityQueries
{ {
public function start(): Builder public function start(): Builder
{ {
return Book::query(); return Book::query();
} }
public function findVisibleById(int $id): ?Book
{
return $this->start()->scopes('visible')->find($id);
}
public function findVisibleBySlug(string $slug): Book public function findVisibleBySlug(string $slug): Book
{ {
/** @var ?Book $book */ /** @var ?Book $book */

View File

@ -6,13 +6,18 @@ use BookStack\Entities\Models\Bookshelf;
use BookStack\Exceptions\NotFoundException; use BookStack\Exceptions\NotFoundException;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
class BookshelfQueries class BookshelfQueries implements ProvidesEntityQueries
{ {
public function start(): Builder public function start(): Builder
{ {
return Bookshelf::query(); return Bookshelf::query();
} }
public function findVisibleById(int $id): ?Bookshelf
{
return $this->start()->scopes('visible')->find($id);
}
public function findVisibleBySlug(string $slug): Bookshelf public function findVisibleBySlug(string $slug): Bookshelf
{ {
/** @var ?Bookshelf $shelf */ /** @var ?Bookshelf $shelf */

View File

@ -0,0 +1,53 @@
<?php
namespace BookStack\Entities\Queries;
use BookStack\Entities\Models\Chapter;
use BookStack\Exceptions\NotFoundException;
use Illuminate\Database\Eloquent\Builder;
class ChapterQueries implements ProvidesEntityQueries
{
protected static array $listAttributes = [
'id', 'slug', 'name', 'description', 'priority',
'created_at', 'updated_at',
'created_by', 'updated_by', 'owned_by',
];
public function start(): Builder
{
return Chapter::query();
}
public function findVisibleById(int $id): ?Chapter
{
return $this->start()->scopes('visible')->find($id);
}
public function findVisibleBySlugs(string $bookSlug, string $chapterSlug): Chapter
{
/** @var ?Chapter $chapter */
$chapter = $this->start()->with('book')
->whereHas('book', function (Builder $query) use ($bookSlug) {
$query->where('slug', '=', $bookSlug);
})
->where('slug', '=', $chapterSlug)
->first();
if ($chapter === null) {
throw new NotFoundException(trans('errors.chapter_not_found'));
}
return $chapter;
}
public function visibleForList(): Builder
{
return $this->start()
->select(array_merge(static::$listAttributes, ['book_slug' => function ($builder) {
$builder->select('slug')
->from('books')
->whereColumn('books.id', '=', 'chapters.book_id');
}]));
}
}

View File

@ -2,12 +2,42 @@
namespace BookStack\Entities\Queries; namespace BookStack\Entities\Queries;
use BookStack\Entities\Models\Entity;
class EntityQueries class EntityQueries
{ {
public function __construct( public function __construct(
public BookshelfQueries $shelves, public BookshelfQueries $shelves,
public BookQueries $books, public BookQueries $books,
public ChapterQueries $chapters,
public PageQueries $pages, public PageQueries $pages,
) { ) {
} }
/**
* Find an entity via an identifier string in the format:
* {type}:{id}
* Example: (book:5).
*/
public function findVisibleByStringIdentifier(string $identifier): ?Entity
{
$explodedId = explode(':', $identifier);
$entityType = $explodedId[0];
$entityId = intval($explodedId[1]);
/** @var ?ProvidesEntityQueries $queries */
$queries = match ($entityType) {
'page' => $this->pages,
'chapter' => $this->chapters,
'book' => $this->books,
'bookshelf' => $this->shelves,
default => null,
};
if (is_null($queries)) {
return null;
}
return $queries->findVisibleById($entityId);
}
} }

View File

@ -5,13 +5,18 @@ namespace BookStack\Entities\Queries;
use BookStack\Entities\Models\Page; use BookStack\Entities\Models\Page;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
class PageQueries class PageQueries implements ProvidesEntityQueries
{ {
public function start(): Builder public function start(): Builder
{ {
return Page::query(); return Page::query();
} }
public function findVisibleById(int $id): ?Page
{
return $this->start()->scopes('visible')->find($id);
}
public function visibleForList(): Builder public function visibleForList(): Builder
{ {
return $this->start() return $this->start()

View File

@ -0,0 +1,12 @@
<?php
namespace BookStack\Entities\Queries;
use BookStack\Entities\Models\Entity;
use Illuminate\Database\Eloquent\Builder;
interface ProvidesEntityQueries
{
public function start(): Builder;
public function findVisibleById(int $id): ?Entity;
}

View File

@ -4,12 +4,11 @@ namespace BookStack\Entities\Repos;
use BookStack\Activity\ActivityType; use BookStack\Activity\ActivityType;
use BookStack\Entities\Models\Book; use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\Page;
use BookStack\Entities\Models\Chapter; use BookStack\Entities\Models\Chapter;
use BookStack\Entities\Queries\EntityQueries;
use BookStack\Entities\Tools\BookContents; use BookStack\Entities\Tools\BookContents;
use BookStack\Entities\Tools\TrashCan; use BookStack\Entities\Tools\TrashCan;
use BookStack\Exceptions\MoveOperationException; use BookStack\Exceptions\MoveOperationException;
use BookStack\Exceptions\NotFoundException;
use BookStack\Exceptions\PermissionsException; use BookStack\Exceptions\PermissionsException;
use BookStack\Facades\Activity; use BookStack\Facades\Activity;
use Exception; use Exception;
@ -17,26 +16,11 @@ use Exception;
class ChapterRepo class ChapterRepo
{ {
public function __construct( public function __construct(
protected BaseRepo $baseRepo protected BaseRepo $baseRepo,
protected EntityQueries $entityQueries,
) { ) {
} }
/**
* Get a chapter via the slug.
*
* @throws NotFoundException
*/
public function getBySlug(string $bookSlug, string $chapterSlug): Chapter
{
$chapter = Chapter::visible()->whereSlugs($bookSlug, $chapterSlug)->first();
if ($chapter === null) {
throw new NotFoundException(trans('errors.chapter_not_found'));
}
return $chapter;
}
/** /**
* Create a new chapter in the system. * Create a new chapter in the system.
*/ */
@ -91,8 +75,8 @@ class ChapterRepo
*/ */
public function move(Chapter $chapter, string $parentIdentifier): Book public function move(Chapter $chapter, string $parentIdentifier): Book
{ {
$parent = $this->findParentByIdentifier($parentIdentifier); $parent = $this->entityQueries->findVisibleByStringIdentifier($parentIdentifier);
if (is_null($parent)) { if (!$parent instanceof Book) {
throw new MoveOperationException('Book to move chapter into not found'); throw new MoveOperationException('Book to move chapter into not found');
} }
@ -106,24 +90,4 @@ class ChapterRepo
return $parent; return $parent;
} }
/**
* Find a page parent entity via an identifier string in the format:
* {type}:{id}
* Example: (book:5).
*
* @throws MoveOperationException
*/
public function findParentByIdentifier(string $identifier): ?Book
{
$stringExploded = explode(':', $identifier);
$entityType = $stringExploded[0];
$entityId = intval($stringExploded[1]);
if ($entityType !== 'book') {
throw new MoveOperationException('Chapters can only be in books');
}
return Book::visible()->where('id', '=', $entityId)->first();
}
} }

View File

@ -8,6 +8,7 @@ use BookStack\Entities\Models\Chapter;
use BookStack\Entities\Models\Entity; use BookStack\Entities\Models\Entity;
use BookStack\Entities\Models\Page; use BookStack\Entities\Models\Page;
use BookStack\Entities\Models\PageRevision; use BookStack\Entities\Models\PageRevision;
use BookStack\Entities\Queries\EntityQueries;
use BookStack\Entities\Tools\BookContents; use BookStack\Entities\Tools\BookContents;
use BookStack\Entities\Tools\PageContent; use BookStack\Entities\Tools\PageContent;
use BookStack\Entities\Tools\PageEditorData; use BookStack\Entities\Tools\PageEditorData;
@ -26,6 +27,7 @@ class PageRepo
public function __construct( public function __construct(
protected BaseRepo $baseRepo, protected BaseRepo $baseRepo,
protected RevisionRepo $revisionRepo, protected RevisionRepo $revisionRepo,
protected EntityQueries $entityQueries,
protected ReferenceStore $referenceStore, protected ReferenceStore $referenceStore,
protected ReferenceUpdater $referenceUpdater protected ReferenceUpdater $referenceUpdater
) { ) {
@ -324,8 +326,8 @@ class PageRepo
*/ */
public function move(Page $page, string $parentIdentifier): Entity public function move(Page $page, string $parentIdentifier): Entity
{ {
$parent = $this->findParentByIdentifier($parentIdentifier); $parent = $this->entityQueries->findVisibleByStringIdentifier($parentIdentifier);
if (is_null($parent)) { if (!$parent instanceof Chapter && !$parent instanceof Book) {
throw new MoveOperationException('Book or chapter to move page into not found'); throw new MoveOperationException('Book or chapter to move page into not found');
} }
@ -343,28 +345,6 @@ class PageRepo
return $parent; return $parent;
} }
/**
* Find a page parent entity via an identifier string in the format:
* {type}:{id}
* Example: (book:5).
*
* @throws MoveOperationException
*/
public function findParentByIdentifier(string $identifier): ?Entity
{
$stringExploded = explode(':', $identifier);
$entityType = $stringExploded[0];
$entityId = intval($stringExploded[1]);
if ($entityType !== 'book' && $entityType !== 'chapter') {
throw new MoveOperationException('Pages can only be in books or chapters');
}
$parentClass = $entityType === 'book' ? Book::class : Chapter::class;
return $parentClass::visible()->where('id', '=', $entityId)->first();
}
/** /**
* Get a new priority for a page. * Get a new priority for a page.
*/ */