<?php
namespace App\Subscriber\Content;
use App\Entity\ContentRanking;
use App\Event\Content\CommentCreatedEvent;
use App\Event\Content\CommentUpdatedEvent;
use App\Service\Content\CommentService;
use App\Service\Content\RankingService;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class ContentRankingSubscriber implements EventSubscriberInterface
{
protected RankingService $service;
protected CommentService $commentService;
/**
* CommentSubscriber constructor.
*/
public function __construct(RankingService $service, CommentService $commentService)
{
$this->service = $service;
$this->commentService = $commentService;
}
public static function getSubscribedEvents(): array
{
return [
CommentCreatedEvent::class => [
['onCommentCreatedUpdateContentRankingVotes', 0],
],
CommentUpdatedEvent::class => [
['onCommentUpdatedUpdateContentRankingVotes', 0],
],
];
}
/**
* @throws \Doctrine\ORM\ORMException
* @throws \Doctrine\ORM\OptimisticLockException
*/
public function onCommentCreatedUpdateContentRankingVotes(CommentCreatedEvent $event)
{
$this->calculateAndStoreRanking($event);
}
/**
* @param CommentCreatedEvent $event
*
* @throws \Doctrine\ORM\ORMException
* @throws \Doctrine\ORM\OptimisticLockException
*/
public function onCommentUpdatedUpdateContentRankingVotes(CommentUpdatedEvent $event)
{
$this->calculateAndStoreRanking($event);
}
/**
* @throws \Doctrine\ORM\ORMException
* @throws \Doctrine\ORM\OptimisticLockException
*/
protected function calculateAndStoreRanking(CommentCreatedEvent|CommentUpdatedEvent $event)
{
$content = $event->getComment()->getContent();
if (!$ranking = $content->getRanking()) {
$ranking = $this->service->createRankingByContent($content);
}
$sums = $this->commentService->getSumsForContent($content);
$ranking->setCommentCount($sums['comment_count']);
$ranking->setVotes((int) $sums['vote_count']);
if ($ranking->getVotes() > 0) {
$ranking->setVoteAverage($sums['vote_sum'] / $ranking->getVotes());
}
$ranking->setRank($this->calculateRankInteger($ranking));
$this->service->storeRanking($ranking);
}
protected function calculateRankInteger(ContentRanking $entity): int
{
$rank = 0;
if ($entity->getVoteAverage()) {
$rank += $entity->getVoteAverage() * 100;
}
if ($entity->getVotes()) {
$rank += $entity->getVotes() * 20;
}
if ($entity->getCommentCount()) {
$rank += $entity->getCommentCount() * 20;
}
if ($entity->getSellCount()) {
$rank += $entity->getSellCount() * 10;
}
// do not consider for now (business logic)
if (false && $entity->getLikeCount()) {
$rank += $entity->getLikeCount() * 10;
}
if ($entity->getRankModifier()) {
$rank = $entity * $entity->getRankModifier();
}
return $rank;
}
}