From 546cfb0dcc801c4fa6560ca0e6d18b4f1edd830f Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Wed, 7 Feb 2024 21:58:27 +0000 Subject: [PATCH] Queries: Extracted static page,chapter,shelf queries to classes --- .../Controllers/CommentController.php | 6 ++++-- .../Commands/CopyShelfPermissionsCommand.php | 7 ++++--- app/Entities/Controllers/BookController.php | 6 ++++-- .../Controllers/BookshelfApiController.php | 12 ++++++----- .../ChapterExportApiController.php | 21 ++++++++----------- app/Entities/Controllers/PageController.php | 4 +++- .../Controllers/PageExportApiController.php | 18 ++++++++-------- app/Entities/Queries/BookshelfQueries.php | 11 ++++++++++ app/Entities/Repos/BaseRepo.php | 5 +++-- app/Entities/Tools/PageContent.php | 6 +++++- app/Entities/Tools/ShelfContext.php | 15 ++++++++----- app/Search/SearchController.php | 9 ++++---- .../Controllers/AttachmentApiController.php | 8 ++++--- .../Controllers/ImageGalleryApiController.php | 6 ++++-- app/Uploads/ImageRepo.php | 19 +++++++++-------- 15 files changed, 93 insertions(+), 60 deletions(-) diff --git a/app/Activity/Controllers/CommentController.php b/app/Activity/Controllers/CommentController.php index 340524cd0..0e8db9eaf 100644 --- a/app/Activity/Controllers/CommentController.php +++ b/app/Activity/Controllers/CommentController.php @@ -4,6 +4,7 @@ namespace BookStack\Activity\Controllers; use BookStack\Activity\CommentRepo; use BookStack\Entities\Models\Page; +use BookStack\Entities\Queries\PageQueries; use BookStack\Http\Controller; use Illuminate\Http\Request; use Illuminate\Validation\ValidationException; @@ -11,7 +12,8 @@ use Illuminate\Validation\ValidationException; class CommentController extends Controller { public function __construct( - protected CommentRepo $commentRepo + protected CommentRepo $commentRepo, + protected PageQueries $pageQueries, ) { } @@ -27,7 +29,7 @@ class CommentController extends Controller 'parent_id' => ['nullable', 'integer'], ]); - $page = Page::visible()->find($pageId); + $page = $this->pageQueries->findVisibleById($pageId); if ($page === null) { return response('Not found', 404); } diff --git a/app/Console/Commands/CopyShelfPermissionsCommand.php b/app/Console/Commands/CopyShelfPermissionsCommand.php index fc11484bd..8463ccd03 100644 --- a/app/Console/Commands/CopyShelfPermissionsCommand.php +++ b/app/Console/Commands/CopyShelfPermissionsCommand.php @@ -3,6 +3,7 @@ namespace BookStack\Console\Commands; use BookStack\Entities\Models\Bookshelf; +use BookStack\Entities\Queries\BookshelfQueries; use BookStack\Entities\Tools\PermissionsUpdater; use Illuminate\Console\Command; @@ -28,7 +29,7 @@ class CopyShelfPermissionsCommand extends Command /** * Execute the console command. */ - public function handle(PermissionsUpdater $permissionsUpdater): int + public function handle(PermissionsUpdater $permissionsUpdater, BookshelfQueries $queries): int { $shelfSlug = $this->option('slug'); $cascadeAll = $this->option('all'); @@ -51,11 +52,11 @@ class CopyShelfPermissionsCommand extends Command return 0; } - $shelves = Bookshelf::query()->get(['id']); + $shelves = $queries->start()->get(['id']); } if ($shelfSlug) { - $shelves = Bookshelf::query()->where('slug', '=', $shelfSlug)->get(['id']); + $shelves = $queries->start()->where('slug', '=', $shelfSlug)->get(['id']); if ($shelves->count() === 0) { $this->info('No shelves found with the given slug.'); } diff --git a/app/Entities/Controllers/BookController.php b/app/Entities/Controllers/BookController.php index 0e9346dbd..a0b98636f 100644 --- a/app/Entities/Controllers/BookController.php +++ b/app/Entities/Controllers/BookController.php @@ -8,6 +8,7 @@ use BookStack\Activity\Models\View; use BookStack\Activity\Tools\UserEntityWatchOptions; use BookStack\Entities\Models\Bookshelf; use BookStack\Entities\Queries\BookQueries; +use BookStack\Entities\Queries\BookshelfQueries; use BookStack\Entities\Repos\BookRepo; use BookStack\Entities\Tools\BookContents; use BookStack\Entities\Tools\Cloner; @@ -29,6 +30,7 @@ class BookController extends Controller protected ShelfContext $shelfContext, protected BookRepo $bookRepo, protected BookQueries $queries, + protected BookshelfQueries $shelfQueries, protected ReferenceFetcher $referenceFetcher, ) { } @@ -75,7 +77,7 @@ class BookController extends Controller $bookshelf = null; if ($shelfSlug !== null) { - $bookshelf = Bookshelf::visible()->where('slug', '=', $shelfSlug)->firstOrFail(); + $bookshelf = $this->shelfQueries->findVisibleBySlugOrFail($shelfSlug); $this->checkOwnablePermission('bookshelf-update', $bookshelf); } @@ -105,7 +107,7 @@ class BookController extends Controller $bookshelf = null; if ($shelfSlug !== null) { - $bookshelf = Bookshelf::visible()->where('slug', '=', $shelfSlug)->firstOrFail(); + $bookshelf = $this->shelfQueries->findVisibleBySlugOrFail($shelfSlug); $this->checkOwnablePermission('bookshelf-update', $bookshelf); } diff --git a/app/Entities/Controllers/BookshelfApiController.php b/app/Entities/Controllers/BookshelfApiController.php index a12dc90ac..9170226a5 100644 --- a/app/Entities/Controllers/BookshelfApiController.php +++ b/app/Entities/Controllers/BookshelfApiController.php @@ -3,6 +3,7 @@ namespace BookStack\Entities\Controllers; use BookStack\Entities\Models\Bookshelf; +use BookStack\Entities\Queries\BookshelfQueries; use BookStack\Entities\Repos\BookshelfRepo; use BookStack\Http\ApiController; use Exception; @@ -13,7 +14,8 @@ use Illuminate\Validation\ValidationException; class BookshelfApiController extends ApiController { public function __construct( - protected BookshelfRepo $bookshelfRepo + protected BookshelfRepo $bookshelfRepo, + protected BookshelfQueries $queries, ) { } @@ -22,7 +24,7 @@ class BookshelfApiController extends ApiController */ public function list() { - $shelves = Bookshelf::visible(); + $shelves = $this->queries->visibleForList(); return $this->apiListingResponse($shelves, [ 'id', 'name', 'slug', 'description', 'created_at', 'updated_at', 'created_by', 'updated_by', 'owned_by', @@ -54,7 +56,7 @@ class BookshelfApiController extends ApiController */ public function read(string $id) { - $shelf = Bookshelf::visible()->findOrFail($id); + $shelf = $this->queries->findVisibleByIdOrFail(intval($id)); $shelf = $this->forJsonDisplay($shelf); $shelf->load([ 'createdBy', 'updatedBy', 'ownedBy', @@ -78,7 +80,7 @@ class BookshelfApiController extends ApiController */ public function update(Request $request, string $id) { - $shelf = Bookshelf::visible()->findOrFail($id); + $shelf = $this->queries->findVisibleByIdOrFail(intval($id)); $this->checkOwnablePermission('bookshelf-update', $shelf); $requestData = $this->validate($request, $this->rules()['update']); @@ -97,7 +99,7 @@ class BookshelfApiController extends ApiController */ public function delete(string $id) { - $shelf = Bookshelf::visible()->findOrFail($id); + $shelf = $this->queries->findVisibleByIdOrFail(intval($id)); $this->checkOwnablePermission('bookshelf-delete', $shelf); $this->bookshelfRepo->destroy($shelf); diff --git a/app/Entities/Controllers/ChapterExportApiController.php b/app/Entities/Controllers/ChapterExportApiController.php index d1523e665..08aa959b3 100644 --- a/app/Entities/Controllers/ChapterExportApiController.php +++ b/app/Entities/Controllers/ChapterExportApiController.php @@ -3,20 +3,17 @@ namespace BookStack\Entities\Controllers; use BookStack\Entities\Models\Chapter; +use BookStack\Entities\Queries\ChapterQueries; use BookStack\Entities\Tools\ExportFormatter; use BookStack\Http\ApiController; use Throwable; class ChapterExportApiController extends ApiController { - protected $exportFormatter; - - /** - * ChapterExportController constructor. - */ - public function __construct(ExportFormatter $exportFormatter) - { - $this->exportFormatter = $exportFormatter; + public function __construct( + protected ExportFormatter $exportFormatter, + protected ChapterQueries $queries, + ) { $this->middleware('can:content-export'); } @@ -27,7 +24,7 @@ class ChapterExportApiController extends ApiController */ public function exportPdf(int $id) { - $chapter = Chapter::visible()->findOrFail($id); + $chapter = $this->queries->findVisibleByIdOrFail($id); $pdfContent = $this->exportFormatter->chapterToPdf($chapter); return $this->download()->directly($pdfContent, $chapter->slug . '.pdf'); @@ -40,7 +37,7 @@ class ChapterExportApiController extends ApiController */ public function exportHtml(int $id) { - $chapter = Chapter::visible()->findOrFail($id); + $chapter = $this->queries->findVisibleByIdOrFail($id); $htmlContent = $this->exportFormatter->chapterToContainedHtml($chapter); return $this->download()->directly($htmlContent, $chapter->slug . '.html'); @@ -51,7 +48,7 @@ class ChapterExportApiController extends ApiController */ public function exportPlainText(int $id) { - $chapter = Chapter::visible()->findOrFail($id); + $chapter = $this->queries->findVisibleByIdOrFail($id); $textContent = $this->exportFormatter->chapterToPlainText($chapter); return $this->download()->directly($textContent, $chapter->slug . '.txt'); @@ -62,7 +59,7 @@ class ChapterExportApiController extends ApiController */ public function exportMarkdown(int $id) { - $chapter = Chapter::visible()->findOrFail($id); + $chapter = $this->queries->findVisibleByIdOrFail($id); $markdown = $this->exportFormatter->chapterToMarkdown($chapter); return $this->download()->directly($markdown, $chapter->slug . '.md'); diff --git a/app/Entities/Controllers/PageController.php b/app/Entities/Controllers/PageController.php index 471df8184..44ba999e8 100644 --- a/app/Entities/Controllers/PageController.php +++ b/app/Entities/Controllers/PageController.php @@ -359,7 +359,9 @@ class PageController extends Controller $query->scopes('visible'); }; - $pages = Page::visible()->with(['updatedBy', 'book' => $visibleBelongsScope, 'chapter' => $visibleBelongsScope]) + $pages = $this->queries->visibleForList() + ->addSelect('updated_by') + ->with(['updatedBy', 'book' => $visibleBelongsScope, 'chapter' => $visibleBelongsScope]) ->orderBy('updated_at', 'desc') ->paginate(20) ->setPath(url('/pages/recently-updated')); diff --git a/app/Entities/Controllers/PageExportApiController.php b/app/Entities/Controllers/PageExportApiController.php index d936a0de2..8737f2f3e 100644 --- a/app/Entities/Controllers/PageExportApiController.php +++ b/app/Entities/Controllers/PageExportApiController.php @@ -3,17 +3,17 @@ namespace BookStack\Entities\Controllers; use BookStack\Entities\Models\Page; +use BookStack\Entities\Queries\PageQueries; use BookStack\Entities\Tools\ExportFormatter; use BookStack\Http\ApiController; use Throwable; class PageExportApiController extends ApiController { - protected $exportFormatter; - - public function __construct(ExportFormatter $exportFormatter) - { - $this->exportFormatter = $exportFormatter; + public function __construct( + protected ExportFormatter $exportFormatter, + protected PageQueries $queries, + ) { $this->middleware('can:content-export'); } @@ -24,7 +24,7 @@ class PageExportApiController extends ApiController */ public function exportPdf(int $id) { - $page = Page::visible()->findOrFail($id); + $page = $this->queries->findVisibleByIdOrFail($id); $pdfContent = $this->exportFormatter->pageToPdf($page); return $this->download()->directly($pdfContent, $page->slug . '.pdf'); @@ -37,7 +37,7 @@ class PageExportApiController extends ApiController */ public function exportHtml(int $id) { - $page = Page::visible()->findOrFail($id); + $page = $this->queries->findVisibleByIdOrFail($id); $htmlContent = $this->exportFormatter->pageToContainedHtml($page); return $this->download()->directly($htmlContent, $page->slug . '.html'); @@ -48,7 +48,7 @@ class PageExportApiController extends ApiController */ public function exportPlainText(int $id) { - $page = Page::visible()->findOrFail($id); + $page = $this->queries->findVisibleByIdOrFail($id); $textContent = $this->exportFormatter->pageToPlainText($page); return $this->download()->directly($textContent, $page->slug . '.txt'); @@ -59,7 +59,7 @@ class PageExportApiController extends ApiController */ public function exportMarkdown(int $id) { - $page = Page::visible()->findOrFail($id); + $page = $this->queries->findVisibleByIdOrFail($id); $markdown = $this->exportFormatter->pageToMarkdown($page); return $this->download()->directly($markdown, $page->slug . '.md'); diff --git a/app/Entities/Queries/BookshelfQueries.php b/app/Entities/Queries/BookshelfQueries.php index d61607e7a..f2fe50531 100644 --- a/app/Entities/Queries/BookshelfQueries.php +++ b/app/Entities/Queries/BookshelfQueries.php @@ -18,6 +18,17 @@ class BookshelfQueries implements ProvidesEntityQueries return $this->start()->scopes('visible')->find($id); } + public function findVisibleByIdOrFail(int $id): Bookshelf + { + $shelf = $this->findVisibleById($id); + + if (is_null($shelf)) { + throw new NotFoundException(trans('errors.bookshelf_not_found')); + } + + return $shelf; + } + public function findVisibleBySlugOrFail(string $slug): Bookshelf { /** @var ?Bookshelf $shelf */ diff --git a/app/Entities/Repos/BaseRepo.php b/app/Entities/Repos/BaseRepo.php index 17208ae03..6674f559a 100644 --- a/app/Entities/Repos/BaseRepo.php +++ b/app/Entities/Repos/BaseRepo.php @@ -9,6 +9,7 @@ use BookStack\Entities\Models\Entity; use BookStack\Entities\Models\HasCoverImage; use BookStack\Entities\Models\HasHtmlDescription; use BookStack\Entities\Models\Page; +use BookStack\Entities\Queries\PageQueries; use BookStack\Exceptions\ImageUploadException; use BookStack\References\ReferenceStore; use BookStack\References\ReferenceUpdater; @@ -23,6 +24,7 @@ class BaseRepo protected ImageRepo $imageRepo, protected ReferenceUpdater $referenceUpdater, protected ReferenceStore $referenceStore, + protected PageQueries $pageQueries, ) { } @@ -125,8 +127,7 @@ class BaseRepo return; } - $templateExists = Page::query()->visible() - ->where('template', '=', true) + $templateExists = $this->pageQueries->visibleTemplates() ->where('id', '=', $templateId) ->exists(); diff --git a/app/Entities/Tools/PageContent.php b/app/Entities/Tools/PageContent.php index 6a89ff626..88987f054 100644 --- a/app/Entities/Tools/PageContent.php +++ b/app/Entities/Tools/PageContent.php @@ -3,6 +3,7 @@ namespace BookStack\Entities\Tools; use BookStack\Entities\Models\Page; +use BookStack\Entities\Queries\PageQueries; use BookStack\Entities\Tools\Markdown\MarkdownToHtml; use BookStack\Exceptions\ImageUploadException; use BookStack\Facades\Theme; @@ -21,9 +22,12 @@ use Illuminate\Support\Str; class PageContent { + protected PageQueries $pageQueries; + public function __construct( protected Page $page ) { + $this->pageQueries = app()->make(PageQueries::class); } /** @@ -331,7 +335,7 @@ class PageContent return PageIncludeContent::fromHtmlAndTag('', $tag); } - $matchedPage = Page::visible()->find($tag->getPageId()); + $matchedPage = $this->pageQueries->findVisibleById($tag->getPageId()); $content = PageIncludeContent::fromHtmlAndTag($matchedPage->html ?? '', $tag); if (Theme::hasListeners(ThemeEvents::PAGE_INCLUDE_PARSE)) { diff --git a/app/Entities/Tools/ShelfContext.php b/app/Entities/Tools/ShelfContext.php index 50c7047d9..5ed334878 100644 --- a/app/Entities/Tools/ShelfContext.php +++ b/app/Entities/Tools/ShelfContext.php @@ -4,10 +4,16 @@ namespace BookStack\Entities\Tools; use BookStack\Entities\Models\Book; use BookStack\Entities\Models\Bookshelf; +use BookStack\Entities\Queries\BookshelfQueries; class ShelfContext { - protected $KEY_SHELF_CONTEXT_ID = 'context_bookshelf_id'; + protected string $KEY_SHELF_CONTEXT_ID = 'context_bookshelf_id'; + + public function __construct( + protected BookshelfQueries $shelfQueries, + ) { + } /** * Get the current bookshelf context for the given book. @@ -20,8 +26,7 @@ class ShelfContext return null; } - /** @var Bookshelf $shelf */ - $shelf = Bookshelf::visible()->find($contextBookshelfId); + $shelf = $this->shelfQueries->findVisibleById($contextBookshelfId); $shelfContainsBook = $shelf && $shelf->contains($book); return $shelfContainsBook ? $shelf : null; @@ -30,7 +35,7 @@ class ShelfContext /** * Store the current contextual shelf ID. */ - public function setShelfContext(int $shelfId) + public function setShelfContext(int $shelfId): void { session()->put($this->KEY_SHELF_CONTEXT_ID, $shelfId); } @@ -38,7 +43,7 @@ class ShelfContext /** * Clear the session stored shelf context id. */ - public function clearShelfContext() + public function clearShelfContext(): void { session()->forget($this->KEY_SHELF_CONTEXT_ID); } diff --git a/app/Search/SearchController.php b/app/Search/SearchController.php index bc3f2ddb4..08f0826dd 100644 --- a/app/Search/SearchController.php +++ b/app/Search/SearchController.php @@ -3,6 +3,7 @@ namespace BookStack\Search; use BookStack\Entities\Models\Page; +use BookStack\Entities\Queries\PageQueries; use BookStack\Entities\Queries\Popular; use BookStack\Entities\Tools\SiblingFetcher; use BookStack\Http\Controller; @@ -11,7 +12,8 @@ use Illuminate\Http\Request; class SearchController extends Controller { public function __construct( - protected SearchRunner $searchRunner + protected SearchRunner $searchRunner, + protected PageQueries $pageQueries, ) { } @@ -95,12 +97,11 @@ class SearchController extends Controller $searchOptions->setFilter('is_template'); $entities = $this->searchRunner->searchEntities($searchOptions, 'page', 1, 20)['results']; } else { - $entities = Page::visible() - ->where('template', '=', true) + $entities = $this->pageQueries->visibleTemplates() ->where('draft', '=', false) ->orderBy('updated_at', 'desc') ->take(20) - ->get(Page::$listAttributes); + ->get(); } return view('search.parts.entity-selector-list', [ diff --git a/app/Uploads/Controllers/AttachmentApiController.php b/app/Uploads/Controllers/AttachmentApiController.php index 2e6d16205..2832fa8e1 100644 --- a/app/Uploads/Controllers/AttachmentApiController.php +++ b/app/Uploads/Controllers/AttachmentApiController.php @@ -3,6 +3,7 @@ namespace BookStack\Uploads\Controllers; use BookStack\Entities\Models\Page; +use BookStack\Entities\Queries\PageQueries; use BookStack\Exceptions\FileUploadException; use BookStack\Http\ApiController; use BookStack\Uploads\Attachment; @@ -15,7 +16,8 @@ use Illuminate\Validation\ValidationException; class AttachmentApiController extends ApiController { public function __construct( - protected AttachmentService $attachmentService + protected AttachmentService $attachmentService, + protected PageQueries $pageQueries, ) { } @@ -48,7 +50,7 @@ class AttachmentApiController extends ApiController $requestData = $this->validate($request, $this->rules()['create']); $pageId = $request->get('uploaded_to'); - $page = Page::visible()->findOrFail($pageId); + $page = $this->pageQueries->findVisibleByIdOrFail($pageId); $this->checkOwnablePermission('page-update', $page); if ($request->hasFile('file')) { @@ -132,7 +134,7 @@ class AttachmentApiController extends ApiController $page = $attachment->page; if ($requestData['uploaded_to'] ?? false) { $pageId = $request->get('uploaded_to'); - $page = Page::visible()->findOrFail($pageId); + $page = $this->pageQueries->findVisibleByIdOrFail($pageId); $attachment->uploaded_to = $requestData['uploaded_to']; } diff --git a/app/Uploads/Controllers/ImageGalleryApiController.php b/app/Uploads/Controllers/ImageGalleryApiController.php index ec96e4593..cec47feb0 100644 --- a/app/Uploads/Controllers/ImageGalleryApiController.php +++ b/app/Uploads/Controllers/ImageGalleryApiController.php @@ -3,6 +3,7 @@ namespace BookStack\Uploads\Controllers; use BookStack\Entities\Models\Page; +use BookStack\Entities\Queries\PageQueries; use BookStack\Http\ApiController; use BookStack\Uploads\Image; use BookStack\Uploads\ImageRepo; @@ -18,6 +19,7 @@ class ImageGalleryApiController extends ApiController public function __construct( protected ImageRepo $imageRepo, protected ImageResizer $imageResizer, + protected PageQueries $pageQueries, ) { } @@ -66,9 +68,9 @@ class ImageGalleryApiController extends ApiController { $this->checkPermission('image-create-all'); $data = $this->validate($request, $this->rules()['create']); - Page::visible()->findOrFail($data['uploaded_to']); + $page = $this->pageQueries->findVisibleByIdOrFail($data['uploaded_to']); - $image = $this->imageRepo->saveNew($data['image'], $data['type'], $data['uploaded_to']); + $image = $this->imageRepo->saveNew($data['image'], $data['type'], $page->id); if (isset($data['name'])) { $image->refresh(); diff --git a/app/Uploads/ImageRepo.php b/app/Uploads/ImageRepo.php index 0e312d883..160a02fa1 100644 --- a/app/Uploads/ImageRepo.php +++ b/app/Uploads/ImageRepo.php @@ -3,6 +3,7 @@ namespace BookStack\Uploads; use BookStack\Entities\Models\Page; +use BookStack\Entities\Queries\PageQueries; use BookStack\Exceptions\ImageUploadException; use BookStack\Permissions\PermissionApplicator; use Exception; @@ -15,6 +16,7 @@ class ImageRepo protected ImageService $imageService, protected PermissionApplicator $permissions, protected ImageResizer $imageResizer, + protected PageQueries $pageQueries, ) { } @@ -77,14 +79,13 @@ class ImageRepo */ public function getEntityFiltered( string $type, - string $filterType = null, - int $page = 0, - int $pageSize = 24, - int $uploadedTo = null, - string $search = null + ?string $filterType, + int $page, + int $pageSize, + int $uploadedTo, + ?string $search ): array { - /** @var Page $contextPage */ - $contextPage = Page::visible()->findOrFail($uploadedTo); + $contextPage = $this->pageQueries->findVisibleByIdOrFail($uploadedTo); $parentFilter = null; if ($filterType === 'book' || $filterType === 'page') { @@ -225,9 +226,9 @@ class ImageRepo */ public function getPagesUsingImage(Image $image): array { - $pages = Page::visible() + $pages = $this->pageQueries->visibleForList() ->where('html', 'like', '%' . $image->url . '%') - ->get(['id', 'name', 'slug', 'book_id']); + ->get(); foreach ($pages as $page) { $page->setAttribute('url', $page->getUrl());