src/Aqarmap/Bundle/ListingBundle/EventListener/ListingStatusListener.php line 155

Open in your IDE?
  1. <?php
  2. namespace Aqarmap\Bundle\ListingBundle\EventListener;
  3. use App\Message\Listing\AfterChangeStatusMessage;
  4. use Aqarmap\Bundle\CreditBundle\Constant\CreditStatus;
  5. use Aqarmap\Bundle\CreditBundle\Contract\CreditManagerInterface;
  6. use Aqarmap\Bundle\CreditBundle\Entity\Credit;
  7. use Aqarmap\Bundle\ListingBundle\Constant\ListingActivityType;
  8. use Aqarmap\Bundle\ListingBundle\Constant\ListingCategories;
  9. use Aqarmap\Bundle\ListingBundle\Constant\ListingFeatures;
  10. use Aqarmap\Bundle\ListingBundle\Constant\ListingStatus;
  11. use Aqarmap\Bundle\ListingBundle\Document\ListingActivityLog;
  12. use Aqarmap\Bundle\ListingBundle\Entity\Listing;
  13. use Aqarmap\Bundle\ListingBundle\Event\ListingEvent;
  14. use Aqarmap\Bundle\ListingBundle\Message\ListingDeleted;
  15. use Aqarmap\Bundle\ListingBundle\Service\ListingManager;
  16. use Aqarmap\Bundle\ListingBundle\Service\ListingRuleMatcher;
  17. use Aqarmap\Bundle\ListingBundle\Service\SpecialAddListingService;
  18. use Aqarmap\Bundle\MainBundle\Adapter\MailerServiceInterface;
  19. use Aqarmap\Bundle\MainBundle\Constant\ActivityType;
  20. use Aqarmap\Bundle\MainBundle\Constant\Locales;
  21. use Aqarmap\Bundle\MainBundle\Constant\ProducerQueues;
  22. use Aqarmap\Bundle\MainBundle\Contract\ProducerFactoryInterface;
  23. use Aqarmap\Bundle\MainBundle\Helpers\MailerHelper;
  24. use Aqarmap\Bundle\MainBundle\Service\ActivityLogger;
  25. use Aqarmap\Bundle\NotificationBundle\Types\ListingHasExpired;
  26. use Aqarmap\Bundle\UserBundle\Constant\UserTypes;
  27. use Doctrine\Common\Collections\ArrayCollection;
  28. use Doctrine\ODM\MongoDB\DocumentManager;
  29. use Doctrine\ORM\EntityManagerInterface;
  30. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
  31. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  32. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  33. use Symfony\Component\Messenger\MessageBusInterface;
  34. use Symfony\Component\Routing\RouterInterface;
  35. use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  36. use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
  37. use Symfony\Contracts\Translation\TranslatorInterface;
  38. use Twig\Environment;
  39. class ListingStatusListener implements EventSubscriberInterface
  40. {
  41.     /**
  42.      * @var MailerServiceInterface
  43.      */
  44.     protected $mailer;
  45.     /**
  46.      * @var ProducerFactoryInterface
  47.      */
  48.     private $pokeProducerFactory;
  49.     /**
  50.      * @var EntityManagerInterface
  51.      */
  52.     private $entityManager;
  53.     /**
  54.      * @var TokenStorageInterface
  55.      */
  56.     private $tokenStorage;
  57.     /**
  58.      * @var ListingRuleMatcher
  59.      */
  60.     private $listingRuleMatcher;
  61.     /**
  62.      * @var CreditManagerInterface
  63.      */
  64.     private $creditManager;
  65.     /**
  66.      * @var ActivityLogger
  67.      */
  68.     private $activityLogger;
  69.     /**
  70.      * @var EventDispatcherInterface
  71.      */
  72.     private $eventDispatcher;
  73.     /**
  74.      * @var TranslatorInterface
  75.      */
  76.     private $translator;
  77.     /**
  78.      * @var ListingManager
  79.      */
  80.     private $listingManager;
  81.     /**
  82.      * @var EngineInterface
  83.      */
  84.     private $engine;
  85.     /**
  86.      * @var MailerHelper
  87.      */
  88.     private $mailerHelper;
  89.     /** @var ParameterBagInterface */
  90.     private $parameterBag;
  91.     private MessageBusInterface $messageBus;
  92.     /**
  93.      * @var DocumentManager
  94.      */
  95.     private $documentManager;
  96.     /**
  97.      * Constructor.
  98.      */
  99.     public function __construct(
  100.         ProducerFactoryInterface $pokeProducerFactory,
  101.         MailerServiceInterface $mailer,
  102.         EntityManagerInterface $entityManager,
  103.         TokenStorageInterface $tokenStorage,
  104.         ListingRuleMatcher $listingRuleMatcher,
  105.         CreditManagerInterface $creditManager,
  106.         ActivityLogger $activityLogger,
  107.         EventDispatcherInterface $eventDispatcher,
  108.         TranslatorInterface $translator,
  109.         ListingManager $listingManager,
  110.         SessionInterface $session,
  111.         RouterInterface $router,
  112.         Environment $engine,
  113.         MailerHelper $mailerHelper,
  114.         ParameterBagInterface $parameterBag,
  115.         SpecialAddListingService $specialAddListingService,
  116.         MessageBusInterface $messageBus,
  117.         DocumentManager $documentManager
  118.     ) {
  119.         $this->pokeProducerFactory $pokeProducerFactory;
  120.         $this->mailer $mailer;
  121.         $this->entityManager $entityManager;
  122.         $this->tokenStorage $tokenStorage;
  123.         $this->listingRuleMatcher $listingRuleMatcher;
  124.         $this->creditManager $creditManager;
  125.         $this->activityLogger $activityLogger;
  126.         $this->eventDispatcher $eventDispatcher;
  127.         $this->translator $translator;
  128.         $this->listingManager $listingManager;
  129.         $this->engine $engine;
  130.         $this->mailerHelper $mailerHelper;
  131.         $this->parameterBag $parameterBag;
  132.         $this->specialAddListingService $specialAddListingService;
  133.         $this->messageBus $messageBus;
  134.         $this->documentManager $documentManager;
  135.     }
  136.     public function preSaveListingEvent(ListingEvent $event): void
  137.     {
  138.         $listing $event->getListing();
  139.         if (null === $listing->getStatus()) {
  140.             $this->getListingManager()->changeStatus($listingListingStatus::DRAFTfalse);
  141.         }
  142.     }
  143.     public function onSubmittedEvent(ListingEvent $event): void
  144.     {
  145.         $listing $event->getListing();
  146.         // Add or edit status
  147.         $isDraftOrLive = \in_array($listing->getStatus(), [
  148.             ListingStatus::DRAFT,
  149.             ListingStatus::LIVE,
  150.             ListingStatus::REJECTED,
  151.         ]);
  152.         // IF listing owner has admin role && listing status is
  153.         // DRAFT (add) Change listing status to LIVE
  154.         if ($listing->getUser()->hasRole('ROLE_ADMIN') && ListingStatus::DRAFT === $listing->getStatus()) {
  155.             $this->getListingManager()->changeStatus($listingListingStatus::LIVEtrue);
  156.         }
  157.         if (ListingCategories::FIRST_LISTING_FOR_FREE == $listing->getCategory()
  158.             || ($isDraftOrLive && !$listing->getUser()->hasRole('ROLE_ADMIN'))
  159.         ) {
  160.             $this->getListingManager()->changeStatus($listingListingStatus::PENDINGtrue);
  161.         }
  162.         if ($this->specialAddListingService->hasSpecialAddListingGroup($listing->getUser())
  163.             && ListingStatus::PENDING_PAYMENT === $listing->getStatus()
  164.             && $listing->getSpecialPublicationCredit()
  165.         ) {
  166.             $this->getListingManager()->changeStatus($listingListingStatus::PENDINGtrue);
  167.         }
  168.     }
  169.     public function onListingPublishEvent(ListingEvent $event): void
  170.     {
  171.         $listing $event->getListing();
  172.         $user $listing->getUser();
  173.         // unsetting pending payment and photos statuses
  174.         $listing->setPendingPaymentStatus(null);
  175.         $listing->setPendingPhotosStatus(null);
  176.         // If no publish did already or the listing is expired and being relisted give it a bump
  177.         if (!$listing->getPublishedAt() || ListingStatus::EXPIRED == $listing->getStatus()) {
  178.             $listing->setPublishedAt(new \DateTime());
  179.         }
  180.         $em $this->entityManager;
  181.         $userListingsCount $em->getRepository(Listing::class)
  182.             ->getUserListingsCountByStatus($user, [ListingStatus::LIVE]);
  183.         $token $this->tokenStorage->getToken();
  184.         // Only flag if user has more than 3 listings and he is not already flagged
  185.         if ($token
  186.             && !$user->hasRole('ROLE_IN_HOUSE')
  187.             && $userListingsCount >= 2
  188.             && UserTypes::INDIVIDUAL == $user->getUserType()
  189.         ) {
  190.             $user->setUserType(UserTypes::BROKER);
  191.             $em->persist($user);
  192.             $em->flush($user);
  193.         }
  194.         $listing->addRejections(new ArrayCollection());
  195.         $this->notifyPoke($listingListingStatus::LIVE);
  196.     }
  197.     public function onListingPublishForFreeEvent(ListingEvent $event): void
  198.     {
  199.         $listing $event->getListing();
  200.         $listingRules $this->listingRuleMatcher->match($listing);
  201.         if ($listingRules['publication_fees']) {
  202.             $creditManager $this->creditManager;
  203.             $credits $creditManager->deduction($listing->getUser(), (float) 0'Free publishing'CreditStatus::SUCCESS);
  204.             foreach ($credits as $credit) {
  205.                 if ($credit instanceof Credit) {
  206.                     $this->getListingManager()->addFeature($listingListingFeatures::PAIDnull$credit);
  207.                 }
  208.             }
  209.             // Record this acction in the activity logger
  210.             if (ListingCategories::SCRAPPED != $listing->getCategory()) {
  211.                 $this->activityLogger->record(ActivityType::LISTING_FREE_PUBLISH$listing->getId());
  212.             }
  213.         }
  214.     }
  215.     public function onPublishedForFreeEmailEvent(ListingEvent $event): void
  216.     {
  217.         $listing $event->getListing();
  218.         $originalLocale $this->getTranslator()->getLocale();
  219.         $this->getTranslator()->setLocale($this->getListingLanguage($listing));
  220.         $template '@AqarmapListingBundle/Admin/Email/listingApprovedForFree.html.twig';
  221.         $templateContext = ['listing' => $listing];
  222.         $compose $this->getComposeMessage($listing$template$templateContext'listings-free-publish');
  223.         $this->getMailer()->sendMessage($compose);
  224.         $this->getTranslator()->setLocale($originalLocale);
  225.     }
  226.     /**
  227.      * Unset DeletedAt date on undelete event.
  228.      */
  229.     public function onListingUndeleteEvent(ListingEvent $event): void
  230.     {
  231.         $listing $event->getListing();
  232.         $listing->setDeletedAt(null);
  233.     }
  234.     /**
  235.      * Refund listing credit on delete event.
  236.      */
  237.     public function onListingDeleteEvent(ListingEvent $event): void
  238.     {
  239.         $listing $event->getListing();
  240.         $listingFeatured $listing->getNotExpiredCredit();
  241.         /*
  242.         Refund Policy,
  243.         listings should have paid features that are not expired yet,
  244.         Also the listing should never been published before.
  245.         */
  246.         if (!empty($listingFeatured) && !$listing->getPublishedAt()) {
  247.             foreach ((array) $listingFeatured as $listingFees) {
  248.                 $credits[] = $listingFees->getCredit();
  249.             }
  250.             $creditManager $this->creditManager;
  251.             $em $this->getEntityManager();
  252.             foreach ($credits as $credit) {
  253.                 if ($credit->canBeCancelled()) {
  254.                     $creditManager->deposit($credit->getUser(), -$credit->getAmount(), CreditStatus::SUCCESSCreditStatus::REFUND_LABEL);
  255.                     $credit->setStatus(CreditStatus::REFUND);
  256.                     $em->persist($credit);
  257.                 }
  258.             }
  259.             $em->flush();
  260.         }
  261.         $listing->setDeletedAt(new \DateTime());
  262.         $this->notifyPoke($listingListingStatus::EXPIRED);
  263.     }
  264.     /**
  265.      * Refund listing credit on delete event.
  266.      */
  267.     public function onListingStatusDeleteEvent(ListingEvent $event): void
  268.     {
  269.         $this->messageBus->dispatch(new ListingDeleted($event->getListing()));
  270.     }
  271.     public function onApprovedSendEmailEvent(ListingEvent $event): void
  272.     {
  273.         $listing $event->getListing();
  274.         $originalLocale $this->getTranslator()->getLocale();
  275.         $this->getTranslator()->setLocale($this->getListingLanguage($listing));
  276.         $template '@AqarmapListingBundle/Admin/Email/listingApproved.html.twig';
  277.         $templateContext = ['listing' => $listing];
  278.         $compose $this->getComposeMessage($listing$template$templateContext'listings-approval');
  279.         $this->getMailer()->sendMessage($compose);
  280.         $this->getTranslator()->setLocale($originalLocale);
  281.     }
  282.     public function onListingExpiredEvent(ListingEvent $event): void
  283.     {
  284.         $listing $event->getListing();
  285.         $this->eventDispatcher
  286.             ->dispatch((new ListingHasExpired())->setSubject($listing), 'listing.has.expired');
  287.         $this->notifyPoke($listingListingStatus::EXPIRED);
  288.     }
  289.     public function onListingPhotosDeleted(ListingEvent $event): void
  290.     {
  291.         $listing $event->getListing();
  292.         $this->getListingManager()->changeStatus($listingListingStatus::PENDING_PHOTOStrue);
  293.     }
  294.     /**
  295.      * @return void
  296.      */
  297.     public function notifyPoke(Listing $listingint $status)
  298.     {
  299.         $message json_encode($listing->getReferenceId());
  300.         if (ListingStatus::LIVE === $status) {
  301.             return $this->pokeProducerFactory
  302.                 ->create(ProducerQueues::POKE_NEW_LISTING)
  303.                 ->publish($message);
  304.         }
  305.         return $this->pokeProducerFactory
  306.             ->create(ProducerQueues::POKE_EXPIRED_LISTING)
  307.             ->publish($message);
  308.     }
  309.     /**
  310.      * @return object
  311.      */
  312.     public function getEntityManager()
  313.     {
  314.         return $this->entityManager;
  315.     }
  316.     /**
  317.      * @return MailerServiceInterface
  318.      */
  319.     public function getMailer()
  320.     {
  321.         return $this->mailer;
  322.     }
  323.     /**
  324.      * @return \Symfony\Component\Translation\LoggingTranslator
  325.      */
  326.     public function getTranslator()
  327.     {
  328.         return $this->translator;
  329.     }
  330.     public function getTemplating()
  331.     {
  332.         return $this->engine;
  333.     }
  334.     public function changeListingWaitingTime(ListingEvent $event): void
  335.     {
  336.         $now = new \DateTime();
  337.         $listing $event->getListing();
  338.         $activityRepo $this->documentManager->getRepository(ListingActivityLog::class);
  339.         $lastActivityWaitingTime $activityRepo->getLastActivity($listing->getId(), ListingActivityType::PENDING_APPROVAL);
  340.         $listing->setWaitingTime($lastActivityWaitingTime $now->getTimestamp() - $lastActivityWaitingTime->getCreatedAt()->getTimestamp() : null);
  341.         $this->entityManager->persist($listing);
  342.         $this->entityManager->flush();
  343.     }
  344.     public function onListingStatusPendingEvent(ListingEvent $event): void
  345.     {
  346.         $listing $event->getListing();
  347.         if (!$listing->getPendingStatusCreatedAt() && !$event->getIsAdmin()) {
  348.             $listing->setPendingStatusCreatedAt(new \DateTime());
  349.         }
  350.     }
  351.     public function onListingStatusChangedEvent(ListingEvent $event): void
  352.     {
  353.         $listing $event->getListing();
  354.         if ($listing) {
  355.             if (in_array($listing->getStatus(), [
  356.                 ListingStatus::LIVE,
  357.                 ListingStatus::EXPIRED,
  358.                 ListingStatus::USER_DELETED,
  359.                 ListingStatus::ADMIN_DELETED,
  360.             ])) {
  361.                 $this->messageBus->dispatch(new AfterChangeStatusMessage($listing->getId()));
  362.             }
  363.         }
  364.     }
  365.     public static function getSubscribedEvents()
  366.     {
  367.         return [
  368.             'aqarmap.listing.pre_save' => ['preSaveListingEvent'],
  369.             'aqarmap.listing.publish' => [
  370.                 ['onListingPublishEvent'100], ['changeListingWaitingTime'],
  371.             ],
  372.             'aqarmap.listing.submitted' => ['onSubmittedEvent'100],
  373.             'aqarmap.listing.expired' => ['onListingExpiredEvent'],
  374.             'aqarmap.listing.undelete' => ['onListingUndeleteEvent'],
  375.             'aqarmap.listing.delete' => [['onListingStatusDeleteEvent'], ['onListingDeleteEvent']],
  376.             'aqarmap.listing.delete_by_user' => ['onListingStatusDeleteEvent'],
  377.             'aqarmap.listing.free_publish' => [
  378.                 ['onListingPublishForFreeEvent'], ['onListingPublishEvent'], ['onPublishedForFreeEmailEvent'],
  379.             ],
  380.             'aqarmap.listing.publish_without_photos' => [
  381.                 ['onListingPublishForFreeEvent'], ['onListingPublishEvent'],
  382.             ],
  383.             'aqarmap.listing.photos_deleted' => ['onListingPhotosDeleted'],
  384.             'aqarmap.listing.rejected' => ['changeListingWaitingTime'],
  385.             'aqarmap.listing.pending_approval' => ['onListingStatusPendingEvent'],
  386.             'aqarmap.listing.after_change_status' => ['onListingStatusChangedEvent'],
  387.         ];
  388.     }
  389.     /**
  390.      * @return ListingManager
  391.      */
  392.     protected function getListingManager()
  393.     {
  394.         return $this->listingManager;
  395.     }
  396.     private function getComposeMessage($listing$template$templateContext$headerCategory)
  397.     {
  398.         $composeMessage $this->mailerHelper->createMessageWithGlobalAttributes();
  399.         $composeMessage->setSubject($this->getTranslator()->trans('email.subject.listing_approved'));
  400.         $composeMessage->setTo($listing->getUser()->getEmailCanonical());
  401.         $composeMessage->setReplyTo($listing->getUser()->getEmailCanonical());
  402.         $composeMessage->setTemplate($template);
  403.         $composeMessage->setTemplateContext($templateContext);
  404.         $compose $this->getMailer()->composeMessage($composeMessage);
  405.         $compose->getHeaders()->addTextHeader('X-Mail-Category'$headerCategory);
  406.         $compose->getHeaders()->addTextHeader('X-Site-Country'$this->parameterBag->get('country'));
  407.         return $compose;
  408.     }
  409.     private function getListingLanguage($listing)
  410.     {
  411.         $language Locales::AR;
  412.         if (null !== $listing->getUser()->getLanguage()) {
  413.             $language $listing->getUser()->getLanguage();
  414.         }
  415.         return $language;
  416.     }
  417. }