Skip to content

Commit

Permalink
Clean TopicController
Browse files Browse the repository at this point in the history
  • Loading branch information
danon committed Nov 26, 2023
1 parent 7c1395a commit 0abe7ea
Showing 1 changed file with 40 additions and 75 deletions.
115 changes: 40 additions & 75 deletions app/Http/Controllers/Forum/TopicController.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
<?php

namespace Coyote\Http\Controllers\Forum;

use Coyote\Events\TopicSaved;
use Coyote\Forum;
use Coyote\Forum\Reason;
use Coyote\Http\Factories\CacheFactory;
Expand All @@ -12,8 +10,8 @@
use Coyote\Http\Resources\TopicResource;
use Coyote\Repositories\Criteria\Forum\OnlyThoseWithAccess;
use Coyote\Repositories\Criteria\Post\WithSubscribers;
use Coyote\Repositories\Criteria\WithTrashed;
use Coyote\Repositories\Criteria\Post\WithTrashedInfo;
use Coyote\Repositories\Criteria\WithTrashed;
use Coyote\Services\Elasticsearch\Builders\Forum\MoreLikeThisBuilder;
use Coyote\Services\Flags;
use Coyote\Services\Forum\Tracker;
Expand All @@ -22,65 +20,48 @@
use Coyote\Services\Forum\TreeBuilder\ListDecorator;
use Coyote\Topic;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Illuminate\View\View;
use Spatie\SchemaOrg\Schema;

class TopicController extends BaseController
{
use CacheFactory;

/**
* @var \Illuminate\Contracts\Auth\Access\Gate
*/
private $gate;

/**
* @param Request $request
* @param $forum
* @param $topic
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Support\Collection|\Illuminate\View\View
*/
public function index(Request $request, $forum, $topic)
public function index(Request $request, Forum $forum, Topic $topic): Collection|View
{
$this->breadcrumb->push($topic->title, route('forum.topic', [$forum->slug, $topic->id, $topic->slug]));

// get the topic (and forum) mark time value from middleware
// @see \Coyote\Http\Middleware\ScrollToPost
$markTime = $request->attributes->get('mark_time');

$this->gate = $this->getGateFactory();
$gate = $this->getGateFactory();

// current page...
$page = (int) $request->get('page');
// number of posts per one page
$page = (int)$request->get('page');
$perPage = $this->postsPerPage($request);

// user with forum-update ability WILL see every post
// NOTE: criteria MUST BE pushed before calling getPage() method!
if ($this->gate->allows('delete', $forum)) {
if ($gate->allows('delete', $forum)) {
$this->post->pushCriteria(new WithTrashed());
$this->post->pushCriteria(new WithTrashedInfo());

// user is able to see real number of posts in this topic
$topic->replies = $topic->replies_real;
$topic->replies = $topic->replies_real; // user is able to see real number of posts in this topic
}

// user wants to show certain post. we need to calculate page number based on post id.
if ($request->filled('p')) {
$page = $this->post->getPage(min(2147483647, (int) $request->get('p')), $topic->id, $perPage);
$page = $this->post->getPage(min(2147483647, (int)$request->get('p')), $topic->id, $perPage);
}

// show posts of last page if page parameter is higher than pages count
$lastPage = max((int) ceil(($topic->replies + 1) / $perPage), 1);
$lastPage = max((int)ceil(($topic->replies + 1) / $perPage), 1);
if ($page > $lastPage) {
$page = $lastPage;
}

$this->post->pushCriteria(new WithSubscribers($this->userId));

// magic happens here. get posts for given topic
/* @var \Illuminate\Support\Collection $posts */
$paginate = $this->post->lengthAwarePagination($topic, $page, $perPage);

$this->pushForumCriteria(true);

// create forum list for current user (according to user's privileges)
Expand All @@ -94,19 +75,18 @@ public function index(Request $request, $forum, $topic)

$tracker = Tracker::make($topic);

$allForums = [];
$reasons = null;

if ($this->gate->allows('delete', $forum) || $this->gate->allows('move', $forum)) {
if ($gate->allows('delete', $forum) || $gate->allows('move', $forum)) {
$reasons = Reason::pluck('name', 'id')->toArray();

$this->forum->resetCriteria();
$this->pushForumCriteria(false);

// forum list only for moderators
$treeBuilder->setForums($this->forum->list());

$allForums = (new JsonDecorator($treeBuilder))->build();
} else {
$allForums = [];
$reasons = null;
}

$resource = (new PostCollection($paginate))
Expand All @@ -118,7 +98,6 @@ public function index(Request $request, $forum, $topic)
// assign array ot posts variable. this is our skeleton! do not remove
$posts = $resource->toResponse($this->request)->getData(true);

// ..then, mark topic as read
if ($markTime < $dateTime) {
$tracker->asRead($dateTime);
}
Expand All @@ -131,62 +110,48 @@ public function index(Request $request, $forum, $topic)

TopicResource::withoutWrapping();

$schema = Schema::discussionForumPosting()
->identifier($request->getUri())
->headline($topic->title)
->author(
Schema::person()
->name($topic->firstPost->user?->name)
)->interactionStatistic(
Schema::interactionCounter()
->userInteractionCount($topic->replies)
);

return $this->view('forum.topic', compact('posts', 'forum', 'paginate', 'reasons'))->with([
'mlt' => $this->moreLikeThis($topic),
'model' => $topic, // we need eloquent model in twig to show information about locked/moved topic
'topic' => (new TopicResource($tracker))->toResponse($request)->getData(true),
'poll' => $topic->poll ? (new PollResource($topic->poll))->resolve($request) : null,
'is_writeable' => $this->gate->allows('write', $forum) && $this->gate->allows('write', $topic),
'all_forums' => $allForums,
'user_forums' => $userForums,
'description' => excerpt(array_first($posts['data'])['text'], 100),
'flags' => $this->flags($forum),
'schema' => $schema,
]);
return $this
->view('forum.topic', compact('posts', 'forum', 'paginate', 'reasons'))
->with([
'mlt' => $this->moreLikeThis($topic),
'model' => $topic, // we need eloquent model in twig to show information about locked/moved topic
'topic' => (new TopicResource($tracker))->toResponse($request)->getData(true),
'poll' => $topic->poll ? (new PollResource($topic->poll))->resolve($request) : null,
'is_writeable' => $gate->allows('write', $forum) && $gate->allows('write', $topic),
'all_forums' => $allForums,
'user_forums' => $userForums,
'description' => excerpt(array_first($posts['data'])['text'], 100),
'flags' => $this->flags($forum),
'schema' => Schema::discussionForumPosting()
->identifier($request->getUri())
->headline($topic->title)
->author(Schema::person()->name($topic->firstPost->user?->name))
->interactionStatistic(Schema::interactionCounter()->userInteractionCount($topic->replies)),
]);
}

private function moreLikeThis(Topic $topic)
{
// build "more like this" block. it's important to send elasticsearch query before
// send SQL query to database because search() method exists only in Model and not Builder class.
return $this->getCacheFactory()->remember('mlt-post:' . $topic->id, now()->addDay(), function () use ($topic) {
// it's important to reset criteria for the further queries
$this->forum->resetCriteria();

$this->forum->pushCriteria(new OnlyThoseWithAccess());

$builder = new MoreLikeThisBuilder($topic, $this->forum->pluck('id'));

// search related topics
return $this->topic->search($builder);
});
return $this
->getCacheFactory()
->remember("mlt-post:$topic->id", now()->addDay(), function () use ($topic) {
$this->forum->resetCriteria();
$this->forum->pushCriteria(new OnlyThoseWithAccess());
return $this->topic->search(new MoreLikeThisBuilder($topic, $this->forum->pluck('id')));
});
}

private function flags(Forum $forum): array
{
$flags = resolve(Flags::class)->fromModels([Topic::class])->permission('delete', [$forum])->get();

return FlagResource::collection($flags)->toArray($this->request);
}

/**
* @param \Coyote\Topic $topic
*/
public function mark($topic)
public function mark(Topic $topic): void
{
$tracker = Tracker::make($topic);

$tracker->asRead($topic->last_post_created_at);
}
}

0 comments on commit 0abe7ea

Please sign in to comment.