diff --git a/app/Activity/Controllers/FavouriteController.php b/app/Activity/Controllers/FavouriteController.php index b3aff1cef..3125a25ad 100644 --- a/app/Activity/Controllers/FavouriteController.php +++ b/app/Activity/Controllers/FavouriteController.php @@ -2,7 +2,7 @@ namespace BookStack\Activity\Controllers; -use BookStack\Entities\Queries\TopFavourites; +use BookStack\Entities\Queries\QueryTopFavourites; use BookStack\Entities\Tools\MixedEntityRequestHelper; use BookStack\Http\Controller; use Illuminate\Http\Request; @@ -21,7 +21,7 @@ class FavouriteController extends Controller { $viewCount = 20; $page = intval($request->get('page', 1)); - $favourites = (new TopFavourites())->run($viewCount + 1, (($page - 1) * $viewCount)); + $favourites = (new QueryTopFavourites())->run($viewCount + 1, (($page - 1) * $viewCount)); $hasMoreLink = ($favourites->count() > $viewCount) ? url('/favourites?page=' . ($page + 1)) : null; diff --git a/app/App/HomeController.php b/app/App/HomeController.php index 56f3d81a8..116f5c8a4 100644 --- a/app/App/HomeController.php +++ b/app/App/HomeController.php @@ -5,8 +5,8 @@ namespace BookStack\App; use BookStack\Activity\ActivityQueries; use BookStack\Entities\Models\Page; use BookStack\Entities\Queries\EntityQueries; -use BookStack\Entities\Queries\RecentlyViewed; -use BookStack\Entities\Queries\TopFavourites; +use BookStack\Entities\Queries\QueryRecentlyViewed; +use BookStack\Entities\Queries\QueryTopFavourites; use BookStack\Entities\Tools\PageContent; use BookStack\Http\Controller; use BookStack\Uploads\FaviconHandler; @@ -23,8 +23,12 @@ class HomeController extends Controller /** * Display the homepage. */ - public function index(Request $request, ActivityQueries $activities) - { + public function index( + Request $request, + ActivityQueries $activities, + QueryRecentlyViewed $recentlyViewed, + QueryTopFavourites $topFavourites, + ) { $activity = $activities->latest(10); $draftPages = []; @@ -38,9 +42,9 @@ class HomeController extends Controller $recentFactor = count($draftPages) > 0 ? 0.5 : 1; $recents = $this->isSignedIn() ? - (new RecentlyViewed())->run(12 * $recentFactor, 1) + $recentlyViewed->run(12 * $recentFactor, 1) : $this->queries->books->visibleForList()->orderBy('created_at', 'desc')->take(12 * $recentFactor)->get(); - $favourites = (new TopFavourites())->run(6); + $favourites = $topFavourites->run(6); $recentlyUpdatedPages = $this->queries->pages->visibleForList() ->where('draft', false) ->orderBy('updated_at', 'desc') diff --git a/app/Entities/Queries/EntityQuery.php b/app/Entities/Queries/EntityQuery.php deleted file mode 100644 index bd7a98b5e..000000000 --- a/app/Entities/Queries/EntityQuery.php +++ /dev/null @@ -1,25 +0,0 @@ -make(MixedEntityListLoader::class); - } - - protected function permissionService(): PermissionApplicator - { - return app()->make(PermissionApplicator::class); - } - - protected function entityProvider(): EntityProvider - { - return app()->make(EntityProvider::class); - } -} diff --git a/app/Entities/Queries/PageQueries.php b/app/Entities/Queries/PageQueries.php index ec27ba4aa..8fb02075a 100644 --- a/app/Entities/Queries/PageQueries.php +++ b/app/Entities/Queries/PageQueries.php @@ -50,7 +50,7 @@ class PageQueries implements ProvidesEntityQueries ->first(); if (is_null($page)) { - throw new NotFoundException(trans('errors.chapter_not_found')); + throw new NotFoundException(trans('errors.page_not_found')); } return $page; diff --git a/app/Entities/Queries/Popular.php b/app/Entities/Queries/QueryPopular.php similarity index 80% rename from app/Entities/Queries/Popular.php rename to app/Entities/Queries/QueryPopular.php index a934f346b..b2ca565eb 100644 --- a/app/Entities/Queries/Popular.php +++ b/app/Entities/Queries/QueryPopular.php @@ -3,24 +3,32 @@ namespace BookStack\Entities\Queries; use BookStack\Activity\Models\View; +use BookStack\Entities\EntityProvider; use BookStack\Entities\Models\BookChild; use BookStack\Entities\Models\Entity; +use BookStack\Permissions\PermissionApplicator; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; -class Popular extends EntityQuery +class QueryPopular { + public function __construct( + protected PermissionApplicator $permissions, + protected EntityProvider $entityProvider, + ) { + } + public function run(int $count, int $page, array $filterModels = null) { - $query = $this->permissionService() + $query = $this->permissions ->restrictEntityRelationQuery(View::query(), 'views', 'viewable_id', 'viewable_type') ->select('*', 'viewable_id', 'viewable_type', DB::raw('SUM(views) as view_count')) ->groupBy('viewable_id', 'viewable_type') ->orderBy('view_count', 'desc'); if ($filterModels) { - $query->whereIn('viewable_type', $this->entityProvider()->getMorphClasses($filterModels)); + $query->whereIn('viewable_type', $this->entityProvider->getMorphClasses($filterModels)); } $entities = $query->with('viewable') @@ -35,7 +43,7 @@ class Popular extends EntityQuery return $entities; } - protected function loadBooksForChildren(Collection $entities) + protected function loadBooksForChildren(Collection $entities): void { $bookChildren = $entities->filter(fn(Entity $entity) => $entity instanceof BookChild); $eloquent = (new \Illuminate\Database\Eloquent\Collection($bookChildren)); diff --git a/app/Entities/Queries/RecentlyViewed.php b/app/Entities/Queries/QueryRecentlyViewed.php similarity index 61% rename from app/Entities/Queries/RecentlyViewed.php rename to app/Entities/Queries/QueryRecentlyViewed.php index fed15ca5a..f28b8f865 100644 --- a/app/Entities/Queries/RecentlyViewed.php +++ b/app/Entities/Queries/QueryRecentlyViewed.php @@ -3,10 +3,18 @@ namespace BookStack\Entities\Queries; use BookStack\Activity\Models\View; +use BookStack\Entities\Tools\MixedEntityListLoader; +use BookStack\Permissions\PermissionApplicator; use Illuminate\Support\Collection; -class RecentlyViewed extends EntityQuery +class QueryRecentlyViewed { + public function __construct( + protected PermissionApplicator $permissions, + protected MixedEntityListLoader $listLoader, + ) { + } + public function run(int $count, int $page): Collection { $user = user(); @@ -14,7 +22,7 @@ class RecentlyViewed extends EntityQuery return collect(); } - $query = $this->permissionService()->restrictEntityRelationQuery( + $query = $this->permissions->restrictEntityRelationQuery( View::query(), 'views', 'viewable_id', @@ -28,7 +36,7 @@ class RecentlyViewed extends EntityQuery ->take($count) ->get(); - $this->mixedEntityListLoader()->loadIntoRelations($views->all(), 'viewable', false); + $this->listLoader->loadIntoRelations($views->all(), 'viewable', false); return $views->pluck('viewable')->filter(); } diff --git a/app/Entities/Queries/TopFavourites.php b/app/Entities/Queries/QueryTopFavourites.php similarity index 71% rename from app/Entities/Queries/TopFavourites.php rename to app/Entities/Queries/QueryTopFavourites.php index 47d4b77f7..6340e35ef 100644 --- a/app/Entities/Queries/TopFavourites.php +++ b/app/Entities/Queries/QueryTopFavourites.php @@ -3,10 +3,18 @@ namespace BookStack\Entities\Queries; use BookStack\Activity\Models\Favourite; +use BookStack\Entities\Tools\MixedEntityListLoader; +use BookStack\Permissions\PermissionApplicator; use Illuminate\Database\Query\JoinClause; -class TopFavourites extends EntityQuery +class QueryTopFavourites { + public function __construct( + protected PermissionApplicator $permissions, + protected MixedEntityListLoader $listLoader, + ) { + } + public function run(int $count, int $skip = 0) { $user = user(); @@ -14,7 +22,7 @@ class TopFavourites extends EntityQuery return collect(); } - $query = $this->permissionService() + $query = $this->permissions ->restrictEntityRelationQuery(Favourite::query(), 'favourites', 'favouritable_id', 'favouritable_type') ->select('favourites.*') ->leftJoin('views', function (JoinClause $join) { @@ -30,7 +38,7 @@ class TopFavourites extends EntityQuery ->take($count) ->get(); - $this->mixedEntityListLoader()->loadIntoRelations($favourites->all(), 'favouritable', false); + $this->listLoader->loadIntoRelations($favourites->all(), 'favouritable', false); return $favourites->pluck('favouritable')->filter(); } diff --git a/app/Entities/Tools/MixedEntityListLoader.php b/app/Entities/Tools/MixedEntityListLoader.php index a0df791db..f9a940b98 100644 --- a/app/Entities/Tools/MixedEntityListLoader.php +++ b/app/Entities/Tools/MixedEntityListLoader.php @@ -3,20 +3,13 @@ namespace BookStack\Entities\Tools; use BookStack\App\Model; -use BookStack\Entities\EntityProvider; +use BookStack\Entities\Queries\EntityQueries; use Illuminate\Database\Eloquent\Relations\Relation; class MixedEntityListLoader { - protected array $listAttributes = [ - 'page' => ['id', 'name', 'slug', 'book_id', 'chapter_id', 'text', 'draft'], - 'chapter' => ['id', 'name', 'slug', 'book_id', 'description'], - 'book' => ['id', 'name', 'slug', 'description'], - 'bookshelf' => ['id', 'name', 'slug', 'description'], - ]; - public function __construct( - protected EntityProvider $entityProvider + protected EntityQueries $queries, ) { } @@ -61,14 +54,7 @@ class MixedEntityListLoader $modelMap = []; foreach ($idsByType as $type => $ids) { - if (!isset($this->listAttributes[$type])) { - continue; - } - - $instance = $this->entityProvider->get($type); - $models = $instance->newQuery() - ->select(array_merge($this->listAttributes[$type], $this->getSubSelectsForQuery($type))) - ->scopes('visible') + $models = $this->queries->visibleForList($type) ->whereIn('id', $ids) ->with($eagerLoadParents ? $this->getRelationsToEagerLoad($type) : []) ->get(); @@ -100,19 +86,4 @@ class MixedEntityListLoader return $toLoad; } - - protected function getSubSelectsForQuery(string $type): array - { - $subSelects = []; - - if ($type === 'chapter' || $type === 'page') { - $subSelects['book_slug'] = function ($builder) { - $builder->select('slug') - ->from('books') - ->whereColumn('books.id', '=', 'book_id'); - }; - } - - return $subSelects; - } } diff --git a/app/Search/SearchController.php b/app/Search/SearchController.php index b94ec1ec7..2fce6a3d5 100644 --- a/app/Search/SearchController.php +++ b/app/Search/SearchController.php @@ -3,7 +3,7 @@ namespace BookStack\Search; use BookStack\Entities\Queries\PageQueries; -use BookStack\Entities\Queries\Popular; +use BookStack\Entities\Queries\QueryPopular; use BookStack\Entities\Tools\SiblingFetcher; use BookStack\Http\Controller; use Illuminate\Http\Request; @@ -67,7 +67,7 @@ class SearchController extends Controller * Search for a list of entities and return a partial HTML response of matching entities. * Returns the most popular entities if no search is provided. */ - public function searchForSelector(Request $request) + public function searchForSelector(Request $request, QueryPopular $queryPopular) { $entityTypes = $request->filled('types') ? explode(',', $request->get('types')) : ['page', 'chapter', 'book']; $searchTerm = $request->get('term', false); @@ -78,7 +78,7 @@ class SearchController extends Controller $searchTerm .= ' {type:' . implode('|', $entityTypes) . '}'; $entities = $this->searchRunner->searchEntities(SearchOptions::fromString($searchTerm), 'all', 1, 20)['results']; } else { - $entities = (new Popular())->run(20, 0, $entityTypes); + $entities = $queryPopular->run(20, 0, $entityTypes); } return view('search.parts.entity-selector-list', ['entities' => $entities, 'permission' => $permission]); diff --git a/resources/views/errors/404.blade.php b/resources/views/errors/404.blade.php index 27d66b30b..dc24a558d 100644 --- a/resources/views/errors/404.blade.php +++ b/resources/views/errors/404.blade.php @@ -1,5 +1,5 @@ @extends('layouts.simple') - +@inject('popular', \BookStack\Entities\Queries\QueryPopular::class) @section('content')
@@ -28,7 +28,7 @@

{{ trans('entities.pages_popular') }}

- @include('entities.list', ['entities' => (new \BookStack\Entities\Queries\Popular)->run(10, 0, ['page']), 'style' => 'compact']) + @include('entities.list', ['entities' => $popular->run(10, 0, ['page']), 'style' => 'compact'])
@@ -36,7 +36,7 @@

{{ trans('entities.books_popular') }}

- @include('entities.list', ['entities' => (new \BookStack\Entities\Queries\Popular)->run(10, 0, ['book']), 'style' => 'compact']) + @include('entities.list', ['entities' => $popular->run(10, 0, ['book']), 'style' => 'compact'])
@@ -44,7 +44,7 @@

{{ trans('entities.chapters_popular') }}

- @include('entities.list', ['entities' => (new \BookStack\Entities\Queries\Popular)->run(10, 0, ['chapter']), 'style' => 'compact']) + @include('entities.list', ['entities' => $popular->run(10, 0, ['chapter']), 'style' => 'compact'])