FlagsReportQuery.php 5.17 KB
<?php

namespace FootyRoom\Queries\Comment;

use FootyRoom\Support\Arr;
use FootyRoom\Support\AutoMapper;
use FootyRoom\Support\MongoClient;
use FootyRoom\Queries\Post\OneForumPostQuery;
use FootyRoom\Queries\Post\ForumPostQueryHandler;
use Illuminate\Support\Str;

class FlagsReportQuery
{
    /**
     * @var \FootyRoom\Support\MongoClient
     */
    protected $mongo;

    /**
     * @var \FootyRoom\Queries\Comment\CommentQueryHandler
     */
    protected $commentQh;

    /**
     * @var \FootyRoom\Queries\Post\ForumPostQueryHandler
     */
    protected $forumPostQh;

    /**
     * Constructor.
     *
     * @param \FootyRoom\Support\MongoClient $mongo
     * @param \FootyRoom\Queries\Comment\CommentQueryHandler $commentQh
     * @param \FootyRoom\Queries\Post\ForumPostQueryHandler $forumPostQh
     */
    public function __construct(MongoClient $mongo, CommentQueryHandler $commentQh, ForumPostQueryHandler $forumPostQh)
    {
        $this->mongo = $mongo->footyroom;
        $this->commentQh = $commentQh;
        $this->forumPostQh = $forumPostQh;
    }

    /**
     * Count total number of flag reports.
     *
     * @return int
     */
    public function count()
    {
        return $this->mongo->selectCollection('comments.flags')->count();
    }

    /**
     * Find flag reports.
     *
     * @param int $userRole
     * @param int $limit
     * @param int $offset
     *
     * @return \FootyRoom\Queries\Comment\FlagsReport[]
     */
    public function find($userRole, $limit = 10, $offset = 0): array
    {
        $cursor = $this->mongo->selectCollection('comments.flags')->find(
            [],
            [
                'limit' => $limit,
                'skip' => $offset,
                'sort' => ['total' => -1],
            ]
        );

        $flagReports = [];

        foreach ($cursor as $report) {
            $flagReports[] = AutoMapper::map($report, FlagsReport::class);
        }

        if (!$flagReports) {
            return [];
        }

        $commentIds = array_pluck($flagReports, 'commentId');

        $commentQuery = (new CommentQuery())
        ->ids($commentIds)
        ->threaded(false)
        ->withUserInfo(true)
        ->viewedBy($userRole);

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

        $flagReports = Arr::joinObjects($flagReports, $comments, 'commentId', 'comment', 'id');

        foreach ($flagReports as $report) {
            // If comment is actually a forum post then we must provide that
            // post to front-end so that it can handle post deletion as well.
            if (Str::startsWith($report->comment->discussionId, 'forumPost')) {
                $mainCommentQuery = (new CommentQuery($report->comment->discussionId))
                    ->order('asc')
                    ->limit(1)
                    ->viewedBy($userRole);

                $mainComment = $this->commentQh->find($mainCommentQuery);

                if (count($mainComment) > 0 && $mainComment[0]->id == $report->comment->id) {
                    $postId = (int) filter_var($report->comment->discussionId, FILTER_SANITIZE_NUMBER_INT);
                    $postQuery = new OneForumPostQuery($postId);
                    $report->post = $this->forumPostQh->findOne($postQuery);
                }
            }
        }

        return $flagReports;
    }

    /**
     * Find comment flags report by commentId.
     *
     * @param int $commentId
     *
     * @return \FootyRoom\Queries\Comment\FlagReport|null
     */
    public function findByCommentId($commentId)
    {
        $report = $this->mongo->selectCollection('comments.flags')->findOne([
            'commentId' => $commentId,
        ]);

        if (!$report) {
            return null;
        }

        return AutoMapper::map($report, FlagsReport::class);
    }

    /**
     * Record flag to read model.
     *
     * @param int $commentId
     * @param string $flagName
     * @param string $username
     * @param $url string
     */
    public function recordFlag($commentId, $flagName, $username, $url)
    {
        $upsert = [
            '$inc' => [
                'total' => 1,
            ],
            '$addToSet' => [
                $flagName => $username,
            ],
        ];

        if ($url) {
            $upsert['$set'] = [
                'url' => $url,
            ];
        }

        $this->mongo->selectCollection('comments.flags')->updateOne(['commentId' => $commentId], $upsert, ['upsert' => true]);
    }

    /**
     * Deletes flagged comment specified by commentId.
     *
     * @param int $commentId
     */
    public function deleteByCommentId($commentId)
    {
        $this->mongo->selectCollection('comments.flags')->deleteOne([
            'commentId' => $commentId,
        ]);
    }

    /**
     * Removes a flag.
     *
     * @param int $commentId
     * @param string $username
     * @param string $flagName
     */
    public function removeFlag($commentId, $username, $flagName)
    {
        $this->mongo->selectCollection('comments.flags')->updateOne([
            'commentId' => $commentId,
        ], [
            '$inc' => [
                'total' => -1,
            ],
            '$pull' => [
                $flagName => $username,
            ],
        ]);
    }
}