From f0ce7853ce3eaa39a618c896963289b59dc2bbb0 Mon Sep 17 00:00:00 2001 From: Roardom Date: Wed, 30 Oct 2024 15:51:19 +0000 Subject: [PATCH] refactor: normalize forum aggregates Even though the queries were ultra efficient before (always less than 5ms), the total combined cpu execution time for forums is not greater than 0.3% of all total execution time. Opt for cleaner code and a normalized database instead. In a forum with 40k posts and 5k topics: Topic index: 26 ms -> 83ms. The forum category topic index: 29 ms -> 63 ms. The forum index: 20 ms -> 55 ms. The forum topic index: 19 ms -> 25 ms. User topics: 18 ms -> 21 ms. Subscriptions: 19 ms -> 20 ms. These numbers are very reasonable and normalization should be fine here. Unfortunately, Laravel doesn't have a function for hasManyThrough()->latestOfMany() so the eager load has to be done manually. --- .../Commands/AutoSoftDeleteDisabledUsers.php | 4 - app/Http/Controllers/ForumController.php | 41 +++++++--- app/Http/Controllers/HomeController.php | 3 +- app/Http/Controllers/PostController.php | 48 +----------- app/Http/Controllers/Staff/UserController.php | 4 - app/Http/Controllers/TopicController.php | 75 +------------------ app/Http/Controllers/User/TopicController.php | 3 +- .../Livewire/ForumCategoryTopicSearch.php | 10 ++- app/Http/Livewire/ForumTopicSearch.php | 10 ++- app/Http/Livewire/SubscribedForum.php | 25 ++++++- app/Http/Livewire/SubscribedTopic.php | 6 +- app/Http/Livewire/TopicSearch.php | 10 ++- app/Models/Forum.php | 36 --------- app/Models/Topic.php | 45 +++-------- config/audit.php | 7 -- database/factories/ForumFactory.php | 16 ++-- database/factories/TopicFactory.php | 30 ++++---- ...st_post_columns_from_topics_and_forums.php | 47 ++++++++++++ database/seeders/ForumsTableSeeder.php | 22 ++---- .../forum/subforum-listing.blade.php | 20 ++--- .../components/forum/topic-listing.blade.php | 14 ++-- resources/views/forum/topic/show.blade.php | 2 +- 22 files changed, 191 insertions(+), 287 deletions(-) create mode 100644 database/migrations/2024_10_30_141448_drop_last_post_columns_from_topics_and_forums.php diff --git a/app/Console/Commands/AutoSoftDeleteDisabledUsers.php b/app/Console/Commands/AutoSoftDeleteDisabledUsers.php index caceb3108a..fb9283abad 100644 --- a/app/Console/Commands/AutoSoftDeleteDisabledUsers.php +++ b/app/Console/Commands/AutoSoftDeleteDisabledUsers.php @@ -95,10 +95,6 @@ final public function handle(): void 'first_post_user_id' => User::SYSTEM_USER_ID, ]); - Topic::where('last_post_user_id', '=', $user->id)->update([ - 'last_post_user_id' => User::SYSTEM_USER_ID, - ]); - PrivateMessage::where('sender_id', '=', $user->id)->update([ 'sender_id' => User::SYSTEM_USER_ID, ]); diff --git a/app/Http/Controllers/ForumController.php b/app/Http/Controllers/ForumController.php index c646a8ec61..36e26064a8 100644 --- a/app/Http/Controllers/ForumController.php +++ b/app/Http/Controllers/ForumController.php @@ -30,18 +30,39 @@ class ForumController extends Controller /** * Show All Forums. */ - public function index(Request $request): \Illuminate\Contracts\View\Factory|\Illuminate\View\View + public function index(): \Illuminate\Contracts\View\Factory|\Illuminate\View\View { + $categories = ForumCategory::query() + ->with([ + 'forums' => fn ($query) => $query->authorized(canReadTopic: true)->orderBy('position')->withCount('topics', 'posts'), + ]) + ->orderBy('position') + ->get() + ->filter(fn ($category) => $category->forums->isNotEmpty()); + + $latestPosts = Post::query() + ->with([ + 'user' => fn ($query) => $query->withTrashed(), + 'topic', + ]) + ->joinSub( + Post::query() + ->selectRaw('MAX(posts.id) AS id, forum_id') + ->join('topics', 'posts.topic_id', '=', 'topics.id') + ->groupBy('forum_id'), + 'latest_posts', + fn ($join) => $join->on('posts.id', '=', 'latest_posts.id') + ) + ->get(); + + $categories->transform(function ($category) use ($latestPosts) { + $category->forums->transform(fn ($forum) => $forum->setRelation('latestPost', $latestPosts->firstWhere('forum_id', '=', $forum->id))); + + return $category; + }); + return view('forum.index', [ - 'categories' => ForumCategory::query() - ->with([ - 'forums' => fn ($query) => $query->authorized(canReadTopic: true)->orderBy('position'), - 'forums.latestPoster' => fn ($query) => $query->withTrashed(), - 'forums.lastRepliedTopic', - ]) - ->orderBy('position') - ->get() - ->filter(fn ($category) => $category->forums->isNotEmpty()), + 'categories' => $categories, 'num_posts' => Post::count(), 'num_forums' => Forum::count(), 'num_topics' => Topic::count(), diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php index 3f41e093f9..8d3bbd2cbd 100644 --- a/app/Http/Controllers/HomeController.php +++ b/app/Http/Controllers/HomeController.php @@ -83,7 +83,8 @@ public function index(Request $request): \Illuminate\Contracts\View\Factory|\Ill ), 'articles' => $articles, 'topics' => Topic::query() - ->with(['user', 'user.group', 'latestPoster', 'reads' => fn ($query) => $query->whereBelongsto($user)]) + ->with(['user', 'user.group', 'latestPost.user', 'reads' => fn ($query) => $query->whereBelongsto($user)]) + ->withCount('posts') ->authorized(canReadTopic: true) ->latest() ->take(5) diff --git a/app/Http/Controllers/PostController.php b/app/Http/Controllers/PostController.php index c347ebbb58..5f854a3220 100644 --- a/app/Http/Controllers/PostController.php +++ b/app/Http/Controllers/PostController.php @@ -80,22 +80,6 @@ public function store(Request $request): \Illuminate\Http\RedirectResponse 'topic_id' => $topic->id, ]); - $topic->update([ - 'last_post_id' => $post->id, - 'last_post_user_id' => $user->id, - 'num_post' => $topic->posts()->count(), - 'last_post_created_at' => $post->created_at, - ]); - - $forum->update([ - 'num_post' => $forum->posts()->count(), - 'num_topic' => $forum->topics()->count(), - 'last_post_user_id' => $user->id, - 'last_post_id' => $post->id, - 'last_topic_id' => $topic->id, - 'last_post_created_at' => $post->created_at, - ]); - // Post To Chatbox and Notify Subscribers $appUrl = config('app.url'); $postUrl = \sprintf('%s/forums/topics/%s/posts/%s', $appUrl, $topic->id, $post->id); @@ -230,38 +214,10 @@ public function destroy(Request $request, int $id): \Illuminate\Http\RedirectRes $post->delete(); - $latestPost = $topic->latestPostSlow; - $isTopicDeleted = false; - - if ($latestPost === null) { + if ($topic->latestPost()->doesntExist()) { $topic->delete(); - $isTopicDeleted = true; - } else { - $latestPoster = $latestPost->user; - $topic->update([ - 'last_post_id' => $latestPost->id, - 'last_post_user_id' => $latestPoster->id, - 'num_post' => $topic->posts()->count(), - 'last_post_created_at' => $latestPost->created_at, - ]); - } - - $forum = $topic->forum; - $lastRepliedTopic = $forum->lastRepliedTopicSlow; - $latestPost = $lastRepliedTopic->latestPostSlow; - $latestPoster = $latestPost->user; - - $forum->update([ - 'num_post' => $forum->posts()->count(), - 'num_topic' => $forum->topics()->count(), - 'last_post_id' => $latestPost->id, - 'last_post_user_id' => $latestPoster->id, - 'last_topic_id' => $lastRepliedTopic->id, - 'last_post_created_at' => $latestPost->created_at, - ]); - if ($isTopicDeleted === true) { - return to_route('forums.show', ['id' => $forum->id]) + return to_route('forums.show', ['id' => $post->topic->forum_id]) ->withSuccess(trans('forum.delete-post-success')); } diff --git a/app/Http/Controllers/Staff/UserController.php b/app/Http/Controllers/Staff/UserController.php index 61f33e36a5..74527b3680 100644 --- a/app/Http/Controllers/Staff/UserController.php +++ b/app/Http/Controllers/Staff/UserController.php @@ -139,10 +139,6 @@ protected function destroy(Request $request, User $user): \Illuminate\Http\Redir 'first_post_user_id' => User::SYSTEM_USER_ID, ]); - Topic::where('last_post_user_id', '=', $user->id)->update([ - 'last_post_user_id' => User::SYSTEM_USER_ID, - ]); - PrivateMessage::where('sender_id', '=', $user->id)->update([ 'sender_id' => User::SYSTEM_USER_ID, ]); diff --git a/app/Http/Controllers/TopicController.php b/app/Http/Controllers/TopicController.php index 2b9ee5caf2..c2ee6e5b02 100644 --- a/app/Http/Controllers/TopicController.php +++ b/app/Http/Controllers/TopicController.php @@ -83,8 +83,6 @@ public function show(Request $request, int $id): \Illuminate\Contracts\View\Fact */ public function create(Request $request, int $id): \Illuminate\Contracts\View\Factory|\Illuminate\View\View|\Illuminate\Http\RedirectResponse { - $user = $request->user(); - $forum = Forum::with('category')->authorized(canStartTopic: true)->findOrFail($id); return view('forum.forum_topic.create', [ @@ -109,33 +107,17 @@ public function store(Request $request, int $id): \Illuminate\Http\RedirectRespo 'name' => $request->title, 'state' => 'open', 'first_post_user_id' => $user->id, - 'last_post_user_id' => $user->id, 'views' => 0, 'priority' => 0, 'forum_id' => $forum->id, - 'num_post' => 1, ]); - $post = Post::create([ + Post::create([ 'content' => $request->input('content'), 'user_id' => $user->id, 'topic_id' => $topic->id, ]); - $forum->update([ - 'num_topic' => $forum->topics()->count(), - 'num_post' => $forum->posts()->count(), - 'last_topic_id' => $topic->id, - 'last_post_id' => $post->id, - 'last_post_user_id' => $user->id, - 'last_post_created_at' => $post->created_at, - ]); - - $topic->update([ - 'last_post_id' => $post->id, - 'last_post_created_at' => $post->created_at, - ]); - // Post To ShoutBox $appUrl = config('app.url'); $topicUrl = \sprintf('%s/forums/topics/%s', $appUrl, $topic->id); @@ -232,50 +214,11 @@ public function update(Request $request, int $id): \Illuminate\Http\RedirectResp $newForum = Forum::authorized(canStartTopic: true)->whereKey($request->forum_id)->sole(); - $oldForum = $topic->forum; - $topic->update([ 'name' => $request->name, 'forum_id' => $newForum->id, ]); - if ($oldForum->id === $newForum->id) { - $lastRepliedTopic = $newForum->lastRepliedTopicSlow; - - if ($lastRepliedTopic->id === $newForum->last_topic_id) { - $latestPost = $lastRepliedTopic->latestPostSlow; - - $newForum->updated_at = $latestPost->created_at; - $newForum->save(); - } - } else { - $lastRepliedTopic = $oldForum->lastRepliedTopicSlow; - $latestPost = $lastRepliedTopic->latestPostSlow; - $latestPoster = $latestPost->user; - - $oldForum->update([ - 'num_topic' => $oldForum->topics()->count(), - 'num_post' => $oldForum->posts()->count(), - 'last_topic_id' => $lastRepliedTopic->id, - 'last_post_id' => $latestPost->id, - 'last_post_user_id' => $latestPoster->id, - 'last_post_created_at' => $latestPost->created_at, - ]); - - $lastRepliedTopic = $newForum->lastRepliedTopicSlow; - $latestPost = $lastRepliedTopic->latestPostSlow; - $latestPoster = $latestPost->user; - - $newForum->update([ - 'num_topic' => $newForum->topics()->count(), - 'num_post' => $newForum->posts()->count(), - 'last_topic_id' => $lastRepliedTopic->id, - 'last_post_id' => $latestPost->id, - 'last_post_user_id' => $latestPoster->id, - 'last_post_created_at' => $latestPost->created_at, - ]); - } - return to_route('topics.show', ['id' => $topic->id]) ->withSuccess('Topic Successfully Edited'); } @@ -292,21 +235,7 @@ public function destroy(int $id): \Illuminate\Http\RedirectResponse $topic->posts()->delete(); $topic->delete(); - $forum = $topic->forum; - $lastRepliedTopic = $forum->lastRepliedTopicSlow; - $latestPost = $lastRepliedTopic->latestPostSlow; - $latestPoster = $latestPost->user; - - $topic->forum()->update([ - 'num_topic' => $forum->topics()->count(), - 'num_post' => $forum->posts()->count(), - 'last_topic_id' => $lastRepliedTopic->id, - 'last_post_id' => $latestPost->id, - 'last_post_user_id' => $latestPoster->id, - 'last_post_created_at' => $latestPost->created_at, - ]); - - return to_route('forums.show', ['id' => $forum->id]) + return to_route('forums.show', ['id' => $topic->forum_id]) ->withSuccess('This Topic Is Now Deleted!'); } diff --git a/app/Http/Controllers/User/TopicController.php b/app/Http/Controllers/User/TopicController.php index c0476cb0b9..f21a52ac75 100644 --- a/app/Http/Controllers/User/TopicController.php +++ b/app/Http/Controllers/User/TopicController.php @@ -31,10 +31,11 @@ public function index(User $user): \Illuminate\Contracts\View\Factory|\Illuminat 'topics' => $user->topics() ->with([ 'user.group', - 'latestPoster', + 'latestPost.user', 'forum:id,name', 'reads' => fn ($query) => $query->whereBelongsTo(auth()->user()), ]) + ->withCount('posts') ->authorized(canReadTopic: true) ->latest() ->paginate(25), diff --git a/app/Http/Livewire/ForumCategoryTopicSearch.php b/app/Http/Livewire/ForumCategoryTopicSearch.php index 6073b2d9c2..44c06b26a7 100644 --- a/app/Http/Livewire/ForumCategoryTopicSearch.php +++ b/app/Http/Livewire/ForumCategoryTopicSearch.php @@ -17,6 +17,7 @@ namespace App\Http\Livewire; use App\Models\ForumCategory; +use App\Models\Post; use App\Models\Topic; use Livewire\Attributes\Computed; use Livewire\Attributes\Url; @@ -72,10 +73,11 @@ final public function topics(): \Illuminate\Pagination\LengthAwarePaginator ->select('topics.*') ->with([ 'user.group', - 'latestPoster', + 'latestPost.user', 'forum', 'reads' => fn ($query) => $query->whereBelongsto(auth()->user()), ]) + ->withCount('posts') ->whereRelation('forum', 'forum_category_id', '=', $this->category->id) ->authorized(canReadTopic: true) ->when($this->search !== '', fn ($query) => $query->where('name', 'LIKE', '%'.$this->search.'%')) @@ -117,7 +119,11 @@ final public function topics(): \Illuminate\Pagination\LengthAwarePaginator ->whereDoesntHave('reads', fn ($query) => $query->whereBelongsTo(auth()->user())) ) ->orderByDesc('priority') - ->orderBy($this->sortField, $this->sortDirection) + ->when( + $this->sortField === 'last_post_created_at', + fn ($query) => $query->orderBy(Post::query()->selectRaw('MAX(id)')->whereColumn('topics.id', '=', 'posts.topic_id'), $this->sortDirection), + fn ($query) => $query->orderBy('created_at', $this->sortDirection), + ) ->paginate(25); } diff --git a/app/Http/Livewire/ForumTopicSearch.php b/app/Http/Livewire/ForumTopicSearch.php index 72435b1e22..9b32b8e9ad 100644 --- a/app/Http/Livewire/ForumTopicSearch.php +++ b/app/Http/Livewire/ForumTopicSearch.php @@ -17,6 +17,7 @@ namespace App\Http\Livewire; use App\Models\Forum; +use App\Models\Post; use App\Models\Subscription; use App\Models\Topic; use Livewire\Attributes\Computed; @@ -77,10 +78,11 @@ final public function topics(): \Illuminate\Pagination\LengthAwarePaginator ->select('topics.*') ->with([ 'user.group', - 'latestPoster', + 'latestPost.user', 'forum:id,name', 'reads' => fn ($query) => $query->whereBelongsto(auth()->user()), ]) + ->withCount('posts') ->where('topics.forum_id', '=', $this->forum->id) ->authorized(canReadTopic: true) ->when($this->search !== '', fn ($query) => $query->where('name', 'LIKE', '%'.$this->search.'%')) @@ -122,7 +124,11 @@ final public function topics(): \Illuminate\Pagination\LengthAwarePaginator ->whereDoesntHave('reads', fn ($query) => $query->whereBelongsTo(auth()->user())) ) ->orderByDesc('priority') - ->orderBy($this->sortField, $this->sortDirection) + ->when( + $this->sortField === 'last_post_created_at', + fn ($query) => $query->orderBy(Post::query()->selectRaw('MAX(id)')->whereColumn('topics.id', '=', 'posts.topic_id'), $this->sortDirection), + fn ($query) => $query->orderBy('created_at', $this->sortDirection), + ) ->paginate(25); } diff --git a/app/Http/Livewire/SubscribedForum.php b/app/Http/Livewire/SubscribedForum.php index bf620fc0c3..cdf04c030c 100644 --- a/app/Http/Livewire/SubscribedForum.php +++ b/app/Http/Livewire/SubscribedForum.php @@ -17,6 +17,7 @@ namespace App\Http\Livewire; use App\Models\Forum; +use App\Models\Post; use Livewire\Attributes\Computed; use Livewire\Component; use Livewire\WithPagination; @@ -31,12 +32,32 @@ class SubscribedForum extends Component #[Computed] final public function forums() { - return Forum::query() - ->with('latestPoster', 'lastRepliedTopic') + $forums = Forum::query() + ->withCount('topics', 'posts') ->whereRelation('subscribedUsers', 'users.id', '=', auth()->id()) ->authorized(canReadTopic: true) ->orderBy('position') ->paginate(25, ['*'], 'subscribedForumsPage'); + + $latestPosts = Post::query() + ->with([ + 'user' => fn ($query) => $query->withTrashed(), + 'topic', + ]) + ->joinSub( + Post::query() + ->selectRaw('MAX(posts.id) AS id, forum_id') + ->join('topics', 'posts.topic_id', '=', 'topics.id') + ->whereIntegerInRaw('forum_id', $forums->pluck('id')) + ->groupBy('forum_id'), + 'latest_posts', + fn ($join) => $join->on('posts.id', '=', 'latest_posts.id') + ) + ->get(); + + $forums->transform(fn ($forum) => $forum->setRelation('latestPost', $latestPosts->firstWhere('forum_id', '=', $forum->id))); + + return $forums; } final public function updatedSubscribedForumsPage(): void diff --git a/app/Http/Livewire/SubscribedTopic.php b/app/Http/Livewire/SubscribedTopic.php index 4f11037ef0..192923d84a 100644 --- a/app/Http/Livewire/SubscribedTopic.php +++ b/app/Http/Livewire/SubscribedTopic.php @@ -16,6 +16,7 @@ namespace App\Http\Livewire; +use App\Models\Post; use App\Models\Topic; use Livewire\Attributes\Computed; use Livewire\Component; @@ -35,13 +36,14 @@ final public function topics(): \Illuminate\Pagination\LengthAwarePaginator ->select('topics.*') ->with([ 'user.group', - 'latestPoster', + 'latestPost.user', 'forum', 'reads' => fn ($query) => $query->whereBelongsto(auth()->user()), ]) + ->withCount('posts') ->whereRelation('subscribedUsers', 'users.id', '=', auth()->id()) ->authorized(canReadTopic: true) - ->orderBy('last_post_created_at') + ->orderByDesc(Post::query()->selectRaw('MAX(id)')->whereColumn('topics.id', '=', 'posts.topic_id')) ->paginate(25, ['*'], 'subscribedTopicsPage'); } diff --git a/app/Http/Livewire/TopicSearch.php b/app/Http/Livewire/TopicSearch.php index 7cc0d941dc..8bd5c97524 100644 --- a/app/Http/Livewire/TopicSearch.php +++ b/app/Http/Livewire/TopicSearch.php @@ -17,6 +17,7 @@ namespace App\Http\Livewire; use App\Models\ForumCategory; +use App\Models\Post; use App\Models\Topic; use Livewire\Attributes\Computed; use Livewire\Attributes\Url; @@ -83,10 +84,11 @@ final public function topics(): \Illuminate\Pagination\LengthAwarePaginator ->select('topics.*') ->with([ 'user.group', - 'latestPoster', + 'latestPost', 'forum', 'reads' => fn ($query) => $query->whereBelongsto(auth()->user()), ]) + ->withCount('posts') ->authorized(canReadTopic: true) ->when($this->search !== '', fn ($query) => $query->where('name', 'LIKE', '%'.$this->search.'%')) ->when($this->label !== '', fn ($query) => $query->where($this->label, '=', 1)) @@ -127,7 +129,11 @@ final public function topics(): \Illuminate\Pagination\LengthAwarePaginator ->whereDoesntHave('reads', fn ($query) => $query->whereBelongsTo(auth()->user())) ) ->when($this->forumId !== '', fn ($query) => $query->where('forum_id', '=', $this->forumId)) - ->orderBy($this->sortField, $this->sortDirection) + ->when( + $this->sortField === 'last_post_created_at', + fn ($query) => $query->orderBy(Post::query()->selectRaw('MAX(id)')->whereColumn('topics.id', '=', 'posts.topic_id'), $this->sortDirection), + fn ($query) => $query->orderBy('created_at', $this->sortDirection), + ) ->paginate(25); } diff --git a/app/Models/Forum.php b/app/Models/Forum.php index c95718cde9..b1d67bbe50 100644 --- a/app/Models/Forum.php +++ b/app/Models/Forum.php @@ -25,12 +25,6 @@ * * @property int $id * @property int|null $position - * @property int|null $num_topic - * @property int|null $num_post - * @property int|null $last_topic_id - * @property int|null $last_post_id - * @property int|null $last_post_user_id - * @property \Illuminate\Support\Carbon|null $last_post_created_at * @property string|null $name * @property string|null $slug * @property string|null $description @@ -82,36 +76,6 @@ public function posts(): \Illuminate\Database\Eloquent\Relations\HasManyThrough return $this->hasManyThrough(Post::class, Topic::class); } - /** - * Latest topic. - * - * @return \Illuminate\Database\Eloquent\Relations\HasOne - */ - public function lastRepliedTopicSlow(): \Illuminate\Database\Eloquent\Relations\HasOne - { - return $this->hasOne(Topic::class)->ofMany('last_post_created_at', 'max'); - } - - /** - * Latest topic. - * - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo - */ - public function lastRepliedTopic(): \Illuminate\Database\Eloquent\Relations\BelongsTo - { - return $this->belongsTo(Topic::class, 'last_topic_id'); - } - - /** - * Latest poster. - * - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo - */ - public function latestPoster(): \Illuminate\Database\Eloquent\Relations\BelongsTo - { - return $this->belongsTo(User::class, 'last_post_user_id'); - } - /** * Has Many Subscriptions. * diff --git a/app/Models/Topic.php b/app/Models/Topic.php index 9cb35fe223..66863a2821 100644 --- a/app/Models/Topic.php +++ b/app/Models/Topic.php @@ -34,11 +34,7 @@ * @property bool $bug * @property bool $suggestion * @property bool $implemented - * @property int|null $num_post * @property int|null $first_post_user_id - * @property int|null $last_post_id - * @property int|null $last_post_user_id - * @property \Illuminate\Support\Carbon|null $last_post_created_at * @property int|null $views * @property \Illuminate\Support\Carbon|null $created_at * @property \Illuminate\Support\Carbon|null $updated_at @@ -56,20 +52,19 @@ class Topic extends Model /** * Get the attributes that should be cast. * - * @return array{last_post_created_at: 'datetime', priority: 'integer', approved: 'bool', denied: 'bool', solved: 'bool', invalid: 'bool', bug: 'bool', suggestion: 'bool', implemented: 'bool'} + * @return array{priority: 'integer', approved: 'bool', denied: 'bool', solved: 'bool', invalid: 'bool', bug: 'bool', suggestion: 'bool', implemented: 'bool'} */ protected function casts(): array { return [ - 'last_post_created_at' => 'datetime', - 'priority' => 'integer', - 'approved' => 'bool', - 'denied' => 'bool', - 'solved' => 'bool', - 'invalid' => 'bool', - 'bug' => 'bool', - 'suggestion' => 'bool', - 'implemented' => 'bool', + 'priority' => 'integer', + 'approved' => 'bool', + 'denied' => 'bool', + 'solved' => 'bool', + 'invalid' => 'bool', + 'bug' => 'bool', + 'suggestion' => 'bool', + 'implemented' => 'bool', ]; } @@ -148,31 +143,11 @@ public function subscribedUsers(): \Illuminate\Database\Eloquent\Relations\Belon * * @return \Illuminate\Database\Eloquent\Relations\HasOne */ - public function latestPostSlow(): \Illuminate\Database\Eloquent\Relations\HasOne + public function latestPost(): \Illuminate\Database\Eloquent\Relations\HasOne { return $this->hasOne(Post::class)->latestOfMany(); } - /** - * Latest post. - * - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo - */ - public function latestPost(): \Illuminate\Database\Eloquent\Relations\BelongsTo - { - return $this->belongsTo(Post::class, 'last_post_id'); - } - - /** - * Latest poster. - * - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo - */ - public function latestPoster(): \Illuminate\Database\Eloquent\Relations\BelongsTo - { - return $this->belongsTo(User::class, 'last_post_user_id'); - } - /** * Only include topics a user is authorized to. * diff --git a/config/audit.php b/config/audit.php index d7e0cbb510..a329b0cf09 100644 --- a/config/audit.php +++ b/config/audit.php @@ -26,16 +26,9 @@ 'global_discards' => [ 'created_at', 'deleted_at', - 'first_post_user_id', 'ip', 'last_action', - 'last_post_created_at', - 'last_post_id', - 'last_post_user_id', - 'last_topic_id', 'nfo', - 'num_post', - 'num_topic', 'passkey', 'password', 'read', diff --git a/database/factories/ForumFactory.php b/database/factories/ForumFactory.php index cb2e0ab18b..2b2ce756b9 100644 --- a/database/factories/ForumFactory.php +++ b/database/factories/ForumFactory.php @@ -34,17 +34,11 @@ class ForumFactory extends Factory public function definition(): array { return [ - 'position' => $this->faker->randomNumber(), - 'num_topic' => $this->faker->randomNumber(), - 'num_post' => $this->faker->randomNumber(), - 'last_topic_id' => null, - 'last_post_id' => null, - 'last_post_user_id' => null, - 'last_post_created_at' => $this->faker->dateTime, - 'name' => $this->faker->name(), - 'slug' => $this->faker->slug(), - 'description' => $this->faker->text(), - 'forum_category_id' => ForumCategory::factory(), + 'position' => $this->faker->randomNumber(), + 'name' => $this->faker->name(), + 'slug' => $this->faker->slug(), + 'description' => $this->faker->text(), + 'forum_category_id' => ForumCategory::factory(), ]; } } diff --git a/database/factories/TopicFactory.php b/database/factories/TopicFactory.php index da321be947..35130bba18 100644 --- a/database/factories/TopicFactory.php +++ b/database/factories/TopicFactory.php @@ -34,23 +34,19 @@ class TopicFactory extends Factory public function definition(): array { return [ - 'name' => $this->faker->name(), - 'state' => $this->faker->word(), - 'priority' => $this->faker->randomNumber(), - 'approved' => $this->faker->boolean(), - 'denied' => $this->faker->boolean(), - 'solved' => $this->faker->boolean(), - 'invalid' => $this->faker->boolean(), - 'bug' => $this->faker->boolean(), - 'suggestion' => $this->faker->boolean(), - 'implemented' => $this->faker->boolean(), - 'num_post' => $this->faker->randomNumber(), - 'first_post_user_id' => null, - 'last_post_id' => null, - 'last_post_user_id' => null, - 'last_post_created_at' => $this->faker->dateTime(), - 'views' => $this->faker->randomNumber(), - 'forum_id' => Forum::factory(), + 'name' => $this->faker->name(), + 'state' => $this->faker->word(), + 'priority' => $this->faker->randomNumber(), + 'approved' => $this->faker->boolean(), + 'denied' => $this->faker->boolean(), + 'solved' => $this->faker->boolean(), + 'invalid' => $this->faker->boolean(), + 'bug' => $this->faker->boolean(), + 'suggestion' => $this->faker->boolean(), + 'implemented' => $this->faker->boolean(), + 'first_post_user_id' => null, + 'views' => $this->faker->randomNumber(), + 'forum_id' => Forum::factory(), ]; } } diff --git a/database/migrations/2024_10_30_141448_drop_last_post_columns_from_topics_and_forums.php b/database/migrations/2024_10_30_141448_drop_last_post_columns_from_topics_and_forums.php new file mode 100644 index 0000000000..aa072de999 --- /dev/null +++ b/database/migrations/2024_10_30_141448_drop_last_post_columns_from_topics_and_forums.php @@ -0,0 +1,47 @@ + + * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 + */ + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +return new class () extends Migration { + /** + * Run the migrations. + */ + public function up(): void + { + Schema::table('topics', function (Blueprint $table): void { + $table->dropColumn([ + 'num_post', + 'last_post_id', + 'last_post_user_id', + 'last_post_created_at', + ]); + }); + + Schema::table('forums', function (Blueprint $table): void { + $table->dropColumn([ + 'num_post', + 'num_topic', + 'last_topic_id', + 'last_post_id', + 'last_post_user_id', + 'last_post_created_at', + ]); + }); + } +}; diff --git a/database/seeders/ForumsTableSeeder.php b/database/seeders/ForumsTableSeeder.php index 961a036471..26d5e9dcb8 100644 --- a/database/seeders/ForumsTableSeeder.php +++ b/database/seeders/ForumsTableSeeder.php @@ -39,20 +39,14 @@ public function run(): void Forum::upsert([ [ - 'id' => 1, - 'position' => 2, - 'num_topic' => null, - 'num_post' => null, - 'last_topic_id' => null, - 'last_post_id' => null, - 'last_post_user_id' => null, - 'last_post_created_at' => null, - 'name' => 'Welcome', - 'slug' => 'welcome', - 'description' => 'Introduce Yourself Here!', - 'forum_category_id' => 1, - 'created_at' => '2017-04-01 20:16:06', - 'updated_at' => '2017-12-27 18:19:07', + 'id' => 1, + 'position' => 2, + 'name' => 'Welcome', + 'slug' => 'welcome', + 'description' => 'Introduce Yourself Here!', + 'forum_category_id' => 1, + 'created_at' => '2017-04-01 20:16:06', + 'updated_at' => '2017-12-27 18:19:07', ], ], ['id'], ['updated_at' => DB::raw('updated_at')]); } diff --git a/resources/views/components/forum/subforum-listing.blade.php b/resources/views/components/forum/subforum-listing.blade.php index a6278f637e..fdaad7f402 100644 --- a/resources/views/components/forum/subforum-listing.blade.php +++ b/resources/views/components/forum/subforum-listing.blade.php @@ -21,20 +21,20 @@ class="subforum-listing__link"
{{ __('forum.topics') }}
-
{{ $subforum->num_topic ?: 0 }}
+
{{ $subforum->topics_count ?: 0 }}
{{ __('forum.posts') }}
-
{{ $subforum->num_post ?: 0 }}
+
{{ $subforum->posts_count ?: 0 }}
- @if ($subforum->lastRepliedTopic !== null) + @if ($subforum->latestPost?->topic !== null)

- {{ $subforum->lastRepliedTopic->name }} + {{ $subforum->latestPost?->topic?->name }}

@endif @@ -44,24 +44,24 @@ class="subforum-listing__latest-datetime" datetime="{{ $subforum->updated_at }}" title="{{ $subforum->updated_at }}" > - @if ($subforum->lastRepliedTopic === null) + @if ($subforum->latestPost?->topic === null) {{ $subforum->updated_at?->diffForHumans() ?? __('common.unknown') }} @else {{ $subforum->updated_at?->diffForHumans() ?? __('common.unknown') }} @endif - @if ($subforum->lastRepliedTopic !== null && $subforum->latestPoster !== null) + @if ($subforum->latestPost?->topic !== null && $subforum->latestPost?->user !== null)
- {{ $subforum->latestPoster->username }} + {{ $subforum->latestPost?->user?->username }}
@endif diff --git a/resources/views/components/forum/topic-listing.blade.php b/resources/views/components/forum/topic-listing.blade.php index 79519bb0a4..3a7be8ea39 100644 --- a/resources/views/components/forum/topic-listing.blade.php +++ b/resources/views/components/forum/topic-listing.blade.php @@ -105,7 +105,7 @@ class="topic-listing__created-link"
{{ __('forum.replies') }}
-
{{ $topic->num_post - 1 }}
+
{{ $topic->posts_count - 1 }}
{{ __('forum.views') }}
@@ -113,27 +113,27 @@ class="topic-listing__created-link"
diff --git a/resources/views/forum/topic/show.blade.php b/resources/views/forum/topic/show.blade.php index cf2e2544f2..9af5cf1315 100644 --- a/resources/views/forum/topic/show.blade.php +++ b/resources/views/forum/topic/show.blade.php @@ -81,7 +81,7 @@ class="breadcrumb__link"
{{ __('forum.replies') }}
-
{{ $topic->num_post - 1 }}
+
{{ $topic->posts_count - 1 }}
{{ __('forum.views') }}