comment_id < 1 ? -1 : $this->comment_id; } public function getLikes(): int { return $this->likes; } public function getDislikes(): int { return $this->dislikes; } public function getTotal(): int { return $this->total; } } class CommentsVote { // Database fields private $comment_id = -1; private $user_id = -1; private $comment_vote = 0; private $comment = null; private $user = null; public const LIKE = 1; public const NONE = 0; public const DISLIKE = -1; public const TABLE = 'comments_votes'; private const QUERY_SELECT = 'SELECT %1$s FROM `' . DB::PREFIX . self::TABLE . '` AS '. self::TABLE; private const SELECT = '%1$s.`comment_id`, %1$s.`user_id`, %1$s.`comment_vote`'; private const QUERY_COUNT = 'SELECT %3$d AS `comment_id`' . ', (SELECT COUNT(`comment_id`) FROM `%1$s%2$s` WHERE %6$s) AS `total`' . ', (SELECT COUNT(`comment_id`) FROM `%1$s%2$s` WHERE %6$s AND `comment_vote` = %4$d) AS `likes`' . ', (SELECT COUNT(`comment_id`) FROM `%1$s%2$s` WHERE %6$s AND `comment_vote` = %5$d) AS `dislikes`'; public function getPostId(): int { return $this->comment_id < 1 ? -1 : $this->comment_id; } public function getPost(): CommentsPost { if($this->comment === null) $this->comment = CommentsPost::byId($this->comment_id); return $this->comment; } public function getUserId(): int { return $this->user_id < 1 ? -1 : $this->user_id; } public function getUser(): User { if($this->user === null) $this->user = User::byId($this->user_id); return $this->user; } public function getVote(): int { return $this->comment_vote; } public static function create(CommentsPost $post, User $user, int $vote, bool $return = false): ?self { $createVote = DB::prepare(' REPLACE INTO `msz_comments_votes` (`comment_id`, `user_id`, `comment_vote`) VALUES (:post, :user, :vote) ') ->bind('post', $post->getId()) ->bind('user', $user->getId()) ->bind('vote', $vote); if(!$createVote->execute()) throw new CommentsVoteCreateFailedException; if(!$return) return null; return self::byExact($post, $user); } public static function delete(CommentsPost $post, User $user): void { DB::prepare('DELETE FROM `msz_comments_votes` WHERE `comment_id` = :post AND `user_id` = :user') ->bind('post', $post->getId()) ->bind('user', $user->getId()) ->execute(); } private static function countQueryBase(int $id, string $condition = '1'): string { return sprintf(self::QUERY_COUNT, DB::PREFIX, self::TABLE, $id, self::LIKE, self::DISLIKE, $condition); } public static function countByPost(CommentsPost $post): CommentsVoteCount { $count = DB::prepare(self::countQueryBase($post->getId(), sprintf('`comment_id` = %d', $post->getId()))) ->fetchObject(CommentsVoteCount::class); if(!$count) throw new CommentsVoteCountFailedException; return $count; } private static function fake(CommentsPost $post, User $user, int $vote): CommentsVote { $fake = new CommentsVote; $fake->comment_id = $post->getId(); $fake->comment = $post; $fake->user_id = $user->getId(); $fake->user = $user; $fake->comment_vote = $vote; return $fake; } private static function byQueryBase(): string { return sprintf(self::QUERY_SELECT, sprintf(self::SELECT, self::TABLE)); } public static function byExact(CommentsPost $post, User $user): self { $vote = DB::prepare(self::byQueryBase() . ' WHERE `comment_id` = :post_id AND `user_id` = :user_id') ->bind('post_id', $post->getId()) ->bind('user_id', $user->getId()) ->fetchObject(self::class); if(!$vote) return self::fake($post, $user, self::NONE); return $vote; } public static function byPost(CommentsPost $post, ?User $user = null, ?Pagination $pagination = null): array { $votesQuery = self::byQueryBase() . ' WHERE `comment_id` = :post' . ($user === null ? '' : ' AND `user_id` = :user'); if($pagination !== null) $votesQuery .= ' LIMIT :range OFFSET :offset'; $getVotes = DB::prepare($votesQuery) ->bind('post', $post->getId()); if($user !== null) $getVotes->bind('user', $user->getId()); if($pagination !== null) $getVotes->bind('range', $pagination->getRange()) ->bind('offset', $pagination->getOffset()); return $getVotes->fetchObjects(self::class); } public static function byUser(User $user, ?Pagination $pagination = null): array { $votesQuery = self::byQueryBase() . ' WHERE `user_id` = :user'; if($pagination !== null) $votesQuery .= ' LIMIT :range OFFSET :offset'; $getVotes = DB::prepare($votesQuery) ->bind('user', $user->getId()); if($pagination !== null) $getVotes->bind('range', $pagination->getRange()) ->bind('offset', $pagination->getOffset()); return $getVotes->fetchObjects(self::class); } public static function byCategory(CommentsCategory $category, ?User $user = null, bool $rootOnly = true, ?Pagination $pagination = null): array { $votesQuery = self::byQueryBase() . ' WHERE `comment_id` IN' . ' (SELECT `comment_id` FROM `' . DB::PREFIX . CommentsPost::TABLE . '` WHERE `category_id` = :category' . (!$rootOnly ? '' : ' AND `comment_reply_to` IS NULL') . ')' . ($user === null ? '' : ' AND `user_id` = :user'); if($pagination !== null) $votesQuery .= ' LIMIT :range OFFSET :offset'; $getVotes = DB::prepare($votesQuery) ->bind('category', $category->getId()); if($user !== null) $getVotes->bind('user', $user->getId()); if($pagination !== null) $getVotes->bind('range', $pagination->getRange()) ->bind('offset', $pagination->getOffset()); return $getVotes->fetchObjects(self::class); } public static function byParent(CommentsPost $parent, ?User $user = null, ?Pagination $pagination = null): array { $votesQuery = self::byQueryBase() . ' WHERE `comment_id` IN' . ' (SELECT `comment_id` FROM `' . DB::PREFIX . CommentsPost::TABLE . '` WHERE `comment_reply_to` = :parent)' . ($user === null ? '' : ' AND `user_id` = :user'); if($pagination !== null) $votesQuery .= ' LIMIT :range OFFSET :offset'; $getVotes = DB::prepare($votesQuery) ->bind('parent', $parent->getId()); if($user !== null) $getVotes->bind('user', $user->getId()); if($pagination !== null) $getVotes->bind('range', $pagination->getRange()) ->bind('offset', $pagination->getOffset()); return $getVotes->fetchObjects(self::class); } public static function all(?Pagination $pagination = null): array { $votesQuery = self::byQueryBase(); if($pagination !== null) $votesQuery .= ' LIMIT :range OFFSET :offset'; $getVotes = DB::prepare($votesQuery); if($pagination !== null) $getVotes->bind('range', $pagination->getRange()) ->bind('offset', $pagination->getOffset()); return $getVotes->fetchObjects(self::class); } }