DiscussionComposer.php 5.89 KB
<?php

namespace FootyRoom\Http\ViewComposers;

use Illuminate\View\View;
use FootyRoom\User\User;
use Illuminate\Http\Request;
use FootyRoom\Queries\Comment\CommentQuery;
use FootyRoom\Queries\Comment\TopCommentsQuery;
use FootyRoom\Queries\Comment\CommentCountQuery;
use FootyRoom\Queries\Comment\CommentQueryHandler;

class DiscussionComposer
{
    /**
     * @var \FootyRoom\Queries\Comment\CommentQueryHandler
     */
    protected $commentQueryHandler;

    /**
     * @var \Illuminate\Http\Request
     */
    protected $request;

    /**
     * Constructor.
     *
     * @param \FootyRoom\Queries\Comment\CommentQueryHandler $commentQueryHandler
     * @param \Illuminate\Http\Request $request
     */
    public function __construct(CommentQueryHandler $commentQueryHandler, Request $request)
    {
        $this->commentQueryHandler = $commentQueryHandler;
        $this->request = $request;
    }

    /**
     * Compose the view.
     *
     * @param \Illuminate\View\View $view
     * @param int $discussionId
     * @param \FootyRoom\User\User $user
     * @param string $filter
     * @param int $page
     * @param int $sinceId
     * @param bool $showTopComments Set to false to not include top comments.
     *
     * @return \Illuminate\View\View
     */
    public function compose(
        View $view,
        $discussionId,
        User $user = null,
        $filter = null,
        $page = 1,
        $sinceId = 0,
        $showTopComments = true
    ) {
        $commentsPerPage = 20;

        if ($commentId = $this->request->get('commentId')) {
            $theCommentQuery = (new CommentQuery($discussionId))
                ->order('desc')
                ->threadOf($commentId)
                ->withUserInfo(true)
                ->viewedBy($user ? $user->getRole() : 0);

            $theComment = $this->commentQueryHandler->find($theCommentQuery);
        }

        if (isset($theComment[0])) {
            $view->with('theComment', $theComment[0]);
        }

        if (isset($theComment[0])) {
            $limit = $commentsPerPage - 1;
        } else {
            $limit = $commentsPerPage;
        }

        if ($without = $this->request->get('without')) {
            $offset = $commentsPerPage * ($page - 1) - 1;
        } else {
            $offset = $commentsPerPage * ($page - 1);
            $without = isset($theComment[0]) ? $theComment[0]->id : 0;
        }

        $commentQuery = (new CommentQuery($discussionId))
            ->order('desc')
            ->limit($limit)
            ->offset($offset)
            ->sinceId($sinceId)
            ->filter($filter)
            ->without($without)
            ->withUserInfo(true)
            ->viewedBy($user ? $user->getRole() : 0);

        $comments = $this->commentQueryHandler->find($commentQuery);

        $view->with('comments', $comments);

        if ($page === 1) {
            if ($showTopComments) {
                $this->loadTopComments($view, $discussionId, $filter, $user);
            }

            $this->loadCount($view, $discussionId, $filter, $user);
        }

        if (isset($view->count) && $view->count >= $commentsPerPage) {
            $hasNext = $this->hasNext($commentQuery);
        } elseif (!isset($view->count)) {
            $hasNext = $this->hasNext($commentQuery);
        } else {
            $hasNext = false;
        }

        $this->buildJsonData($view, $discussionId, $page, $filter, $sinceId, $comments, $hasNext, $without);

        return $view;
    }

    /**
     * Builds json data for discussion.
     *
     * @param View $view
     * @param int $discussionId
     * @param int $page
     * @param string $filter
     * @param int $sinceId
     * @param mixed $comments
     * @param bool $hasNext
     * @param int $without
     */
    protected function buildJsonData($view, $discussionId, $page, $filter, $sinceId, $comments, $hasNext, $without)
    {
        $jsonData = [
            'discussionId' => $discussionId,
            'filter' => $filter,
            'cursor' => [
                'since' => $sinceId ?: (isset($comments[0]) ? $comments[0]->id : 0),
                'next' => $hasNext ? $page + 1 : null,
            ],
        ];

        if ($without) {
            $jsonData['without'] = $without;
        }

        $view->with('jsonData', json_encode($jsonData));
    }

    /**
     * Loads comments count.
     *
     * @param \Illuminate\View\View $view
     * @param int $discussionId
     * @param string $filter
     * @param \FootyRoom\User\User $user
     */
    protected function loadCount(View $view, $discussionId, $filter, User $user = null)
    {
        $countQuery = (new CommentCountQuery($discussionId))
            ->filter($filter)
            ->viewedBy($user ? $user->getRole() : 0);

        $count = $this->commentQueryHandler->count($countQuery);

        $view->with('count', $count);
    }

    /**
     * Loads top comments.
     *
     * @param \Illuminate\View\View $view
     * @param int $discussionId
     * @param string $filter
     * @param \FootyRoom\User\User $user
     */
    protected function loadTopComments(View $view, $discussionId, $filter, User $user = null)
    {
        $topCommentsQuery = (new TopCommentsQuery($discussionId))
            ->filter($filter)
            ->withUserInfo(true)
            ->viewedBy($user ? $user->getRole() : 0);

        $topComments = $this->commentQueryHandler->findTop($topCommentsQuery);

        $view->with('topComments', $topComments);
    }

    /**
     * Determines whether we have next page of comments.
     *
     * @param \FootyRoom\Queries\Comment\CommentQuery $commentQuery
     *
     * @return bool
     */
    protected function hasNext(CommentQuery $commentQuery)
    {
        $hasNextQuery = (clone $commentQuery);

        $hasNextQuery
            ->offset($commentQuery->getOffset() + $commentQuery->getLimit())
            ->withUserInfo(false)
            ->limit(1);

        return (bool) $this->commentQueryHandler->find($hasNextQuery);
    }
}