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

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