<?php
namespace App\Subscriber\User;
use App\Dictionary\ConversationMessageSource;
use App\Dictionary\ConversationMessageType;
use App\Dictionary\FriendshipStatus;
use App\Entity\Member;
use App\Event\RedisEventManager;
use App\Event\User\FriendshipConfirmedEvent;
use App\Event\User\FriendshipRemovedEvent;
use App\Event\User\FriendshipRequestedEvent;
use App\Event\User\FriendshipRequestPreconditionCheckEvent;
use App\Exception\User\FriendshipRequestFailedException;
use App\Repository\FriendshipRepository;
use App\Service\Media\MemberMediaService;
use App\Service\Messenger\MessengerService;
use App\Service\User\FriendshipService;
use App\Subscriber\AbstractRedisEventManagerSubscriber;
use Doctrine\ORM\OptimisticLockException;
use Doctrine\ORM\ORMException;
use Frivol\Common\Service\Notification\FriendshipRequestNotification;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Routing\RouterInterface;
class FriendshipSubscriber extends AbstractRedisEventManagerSubscriber implements EventSubscriberInterface
{
public function __construct(
private readonly MemberMediaService $memberMediaService,
private readonly FriendshipService $service,
private readonly MessengerService $messenger,
private readonly FriendshipRepository $friendshipRepository,
RedisEventManager $redisEventManager,
RouterInterface $router
) {
parent::__construct($redisEventManager, $router);
}
public static function getSubscribedEvents(): array
{
return [
FriendshipRemovedEvent::class => [
['onFriendshipRemovedRemoveOpposite', 0],
],
FriendshipConfirmedEvent::class => [
['onFriendshipConfirmedConfirmOpposite', 0],
['onFriendshipConfirmedSendConversationMessage', 0],
],
FriendshipRequestedEvent::class => [
['onFriendshipRequestedSendNotification', 0],
['onFriendshipRequestedSendConversationMessage', 0],
],
FriendshipRequestPreconditionCheckEvent::class => [
['onFriendshipRequestPreconditionCheck', 0],
]
];
}
public function onFriendshipRequestPreconditionCheck(FriendshipRequestPreconditionCheckEvent $event): void
{
$sender = $event->getSender();
$recipient = $event->getReceiver();
if ($this->friendshipRepository->canSendFriendshipRequest($sender, $recipient)) {
return;
}
$error = new FriendshipRequestFailedException("Freundschaftsanfragen sind nur bei Stammkunden möglich");
$event->setStopReason($error);
throw $error;
}
public function onFriendshipRequestedSendNotification(FriendshipRequestedEvent $event): void
{
$issuer = $event->getFriendship()->getOwnerMember();
$target = $event->getFriendship()->getTargetMember();
$notification = new FriendshipRequestNotification();
$notification->setData([
'image' => $this->getMediaUrl($issuer),
'username' => $issuer->getUsername(),
'sex' => $issuer->getSex(),
]);
$this->getRedisEventManager()->publishToMemberWithFrom($issuer, $target, $notification);
}
public function getMediaUrl(Member $member): ?string
{
if (!$member->getMainPhoto()) {
return null;
}
return $this->memberMediaService->getUrlForMemberMedia($member->getMainPhoto(), false, '100x100');
}
/**
* @throws ORMException
* @throws OptimisticLockException
*/
public function onFriendshipRemovedRemoveOpposite(FriendshipRemovedEvent $event): void
{
$entity = $event->getFriendship();
$opposite = $this->service->getOppositeFriendship($entity);
if ($opposite) {
// dont trigger event through removeFriendship() for this one
$this->service->removeEntity($opposite);
}
}
/**
* @throws ORMException
* @throws OptimisticLockException
*/
public function onFriendshipConfirmedConfirmOpposite(FriendshipConfirmedEvent $event): void
{
$entity = $event->getFriendship();
$opposite = $this->service->getOppositeFriendship($entity);
if ($opposite && FriendshipStatus::CONFIRMED !== $opposite->getStatus()) {
// dont trigger event through confirmFriendship() for this one
$opposite->setStatus(FriendshipStatus::CONFIRMED);
$this->service->storeEntity($opposite);
}
}
/**
* @throws ORMException
* @throws OptimisticLockException
*/
public function onFriendshipConfirmedSendConversationMessage(FriendshipConfirmedEvent $event): void
{
$sender = $event->getFriendship()->getOwnerMember();
$recipient = $event->getFriendship()->getTargetMember();
$type = ConversationMessageType::FRIENDSHIP_CONFIRMED;
$text = 'Ich habe Deine Freundschaftsanfrage akzeptiert!';
$source = ConversationMessageSource::SYSTEM;
$this->messenger->sendDirectMessage($sender, $recipient, $text, $type, $source);
}
/**
* @throws ORMException
* @throws OptimisticLockException
*/
public function onFriendshipRequestedSendConversationMessage(FriendshipRequestedEvent $event): void
{
$sender = $event->getFriendship()->getOwnerMember();
$recipient = $event->getFriendship()->getTargetMember();
$type = ConversationMessageType::FRIENDSHIP_REQUEST;
$source = ConversationMessageSource::SYSTEM;
$text = 'Ich habe Dir eine Freundschaftsanfrage geschickt!';
$this->messenger->sendDirectMessage($sender, $recipient, $text, $type, $source);
}
}