src/Aqarmap/Bundle/ListingBundle/EventListener/ListingRuleListener.php line 218

Open in your IDE?
  1. <?php
  2. namespace Aqarmap\Bundle\ListingBundle\EventListener;
  3. use Aqarmap\Bundle\CreditBundle\Constant\CreditStatus;
  4. use Aqarmap\Bundle\CreditBundle\Contract\CreditManagerInterface;
  5. use Aqarmap\Bundle\CreditBundle\Entity\Credit;
  6. use Aqarmap\Bundle\ListingBundle\Constant\ListingCategories;
  7. use Aqarmap\Bundle\ListingBundle\Constant\ListingFeaturedStatus;
  8. use Aqarmap\Bundle\ListingBundle\Constant\ListingSource;
  9. use Aqarmap\Bundle\ListingBundle\Constant\ListingStatus;
  10. use Aqarmap\Bundle\ListingBundle\Entity\Listing;
  11. use Aqarmap\Bundle\ListingBundle\Event\ListingEvent;
  12. use Aqarmap\Bundle\ListingBundle\Event\ListingFeatureEvent;
  13. use Aqarmap\Bundle\ListingBundle\Service\Contracts\ListingFeatureServiceInterface;
  14. use Aqarmap\Bundle\ListingBundle\Service\ListingFeatureService;
  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\UserBundle\Constant\UserServicesType;
  19. use Aqarmap\Bundle\UserBundle\Services\UserServicesManager;
  20. use Doctrine\ORM\EntityManagerInterface;
  21. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  22. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  23. use Symfony\Component\HttpFoundation\RedirectResponse;
  24. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  25. use Symfony\Component\Routing\RouterInterface;
  26. use Symfony\Contracts\Translation\TranslatorInterface;
  27. class ListingRuleListener implements EventSubscriberInterface
  28. {
  29.     /**
  30.      * @var ListingRuleMatcher
  31.      */
  32.     private $listingRuleMatcher;
  33.     /**
  34.      * @var CreditManagerInterface
  35.      */
  36.     private $creditManager;
  37.     /**
  38.      * @var ListingManager
  39.      */
  40.     private $listingManager;
  41.     /**
  42.      * @var EntityManagerInterface
  43.      */
  44.     private $entityManager;
  45.     /**
  46.      * @var ListingFeatureServiceInterface
  47.      */
  48.     private $listingFeatureService;
  49.     /**
  50.      * @var SessionInterface
  51.      */
  52.     private $session;
  53.     /**
  54.      * @var TranslatorInterface
  55.      */
  56.     private $translator;
  57.     /**
  58.      * @var RouterInterface
  59.      */
  60.     private $router;
  61.     /** @var EventDispatcherInterface */
  62.     private $dispatcher;
  63.     public function __construct(
  64.         ListingRuleMatcher $listingRuleMatcher,
  65.         CreditManagerInterface $creditManager,
  66.         ListingManager $listingManager,
  67.         EntityManagerInterface $entityManager,
  68.         ListingFeatureServiceInterface $listingFeatureService,
  69.         SessionInterface $session,
  70.         TranslatorInterface $translator,
  71.         RouterInterface $router,
  72.         SpecialAddListingService $specialAddListingService,
  73.         UserServicesManager $userServicesManager,
  74.         EventDispatcherInterface $dispatcher
  75.     ) {
  76.         $this->listingRuleMatcher $listingRuleMatcher;
  77.         $this->creditManager $creditManager;
  78.         $this->listingManager $listingManager;
  79.         $this->entityManager $entityManager;
  80.         $this->listingFeatureService $listingFeatureService;
  81.         $this->session $session;
  82.         $this->translator $translator;
  83.         $this->router $router;
  84.         $this->specialAddListingService $specialAddListingService;
  85.         $this->userServicesManager $userServicesManager;
  86.         $this->dispatcher $dispatcher;
  87.     }
  88.     public function preSaveListingEvent(ListingEvent $event): void
  89.     {
  90.         $listing $event->getListing();
  91.         if (
  92.             !$listing->isDraft()
  93.             && !$listing->isLive()
  94.             && ListingCategories::FIRST_LISTING_FOR_FREE === $listing->getCategory()
  95.         ) {
  96.             $this->getListingManager()->changeStatus($listingListingStatus::PENDINGfalse);
  97.             return;
  98.         }
  99.         $publicationCredit $listing->getPublicationCredit();
  100.         /** @var ListingRuleMatcher $matcher */
  101.         $matcher $this->listingRuleMatcher;
  102.         $listingRule $matcher->match($listing);
  103.         $listingRulesRequirePhotos = ($listingRule['required_photos'] && $listing->getPhotos()->count() < $listingRule['required_photos']);
  104.         $listingHasTitle $listing->getTitle();
  105.         if ($listingRulesRequirePhotos && $listingHasTitle) {
  106.             $this->getListingManager()->changeStatus($listingListingStatus::PENDING_PHOTOS);
  107.         }
  108.         if (
  109.             !$listing->isDraft()
  110.             && !$listing->isLive()
  111.             && !$listing->isProjectOrUnit()
  112.             && ListingStatus::PENDING != $listing->getStatus()
  113.             && $listing->getPhotos()->count() >= $listingRule['required_photos']
  114.         ) {
  115.             $this->getListingManager()->changeStatus($listingListingStatus::PENDING_PAYMENTfalse);
  116.         }
  117.         // If listing is PENDING_PAYMENT, the user already paid the fees
  118.         if (ListingStatus::PENDING_PAYMENT === $listing->getStatus()) {
  119.             if ($publicationCredit) {
  120.                 $this->getListingManager()->changeStatus($listingListingStatus::PENDINGfalse);
  121.             }
  122.         }
  123.         // ----------------------------------------------------------------------
  124.         // Toggle the listing's category on location change.
  125.         // ----------------------------------------------------------------------
  126.         $isPaid ListingCategories::PAID === $listing->getCategory();
  127.         $isScrapped ListingCategories::SCRAPPED === $listing->getCategory();
  128.         $isUnlimited ListingCategories::UNLIMITED === $listing->getCategory();
  129.         if (!$isPaid && !$isScrapped && !$isUnlimited && $listingRule['publication_fees'] > 0) {
  130.             $listing->setCategory(ListingCategories::PAID);
  131.             if (ListingStatus::PENDING === $listing->getStatus() && !$publicationCredit) {
  132.                 $this->getListingManager()->changeStatus($listingListingStatus::PENDING_PAYMENTfalse);
  133.             }
  134.         }
  135.         if (
  136.             !$isPaid && !$isScrapped && !$isUnlimited && $listingHasTitle && $listingRule['publication_fees'] <= 0
  137.             && \in_array($listing->getStatus(), [ListingStatus::PENDING_PAYMENTListingStatus::DRAFT])
  138.         ) {
  139.             $this->getListingManager()->changeStatus($listingListingStatus::PENDINGfalse);
  140.         }
  141.         if ($isPaid && !$isScrapped && !$isUnlimited && $listingRule['publication_fees'] <= 0) {
  142.             $listing->setCategory(ListingCategories::NORMAL);
  143.             if (ListingStatus::PENDING_PAYMENT === $listing->getStatus()) {
  144.                 $this->getListingManager()->changeStatus($listingListingStatus::PENDING_PAYMENTfalse);
  145.             }
  146.         }
  147.         if ($this->getListingManager()->isListingUserEbawab($listing)) {
  148.             $listing->setCategory(ListingCategories::EBAWAB);
  149.         }
  150.         if ($this->getListingManager()->isListingUserManualScraped($listing)) {
  151.             $listing->setCategory(ListingCategories::SCRAPPED);
  152.         }
  153.     }
  154.     public function onSubmittedEvent(ListingEvent $event): void
  155.     {
  156.         /** @var Listing $listing */
  157.         $listing $event->getListing();
  158.         $matcher $this->listingRuleMatcher;
  159.         $listingRule $matcher->match($listing);
  160.         if (!$listingRule['flf2'] && ListingCategories::PAID === $listing->getCategory() && $this->listingManager->isEligibleForFreePublishing($listing)) {
  161.             $this->listingManager->createFirstListingForFree($listing);
  162.         }
  163.         if (
  164.             ListingSource::LITE == $listing->getSource()
  165.             || ListingSource::SCRAPPING == $listing->getSource()
  166.             || ListingCategories::FIRST_LISTING_FOR_FREE === $listing->getCategory()
  167.         ) {
  168.             return;
  169.         }
  170.         if ($listingRule['publication_fees'] > && $listing->getPhotos()->count() >= $listingRule['required_photos']) {
  171.             if ((
  172.                 $this->specialAddListingService->hasSpecialAddListingGroup($listing->getUser())
  173.                     && !$listing->getSpecialPublicationCredit()
  174.             )
  175.             || (
  176.                 !$this->specialAddListingService->hasSpecialAddListingGroup($listing->getUser())
  177.                 && !$listing->getPublicationCredit()
  178.             )
  179.             ) {
  180.                 $this->getListingManager()->changeStatus($listingListingStatus::PENDING_PAYMENTtruetrue);
  181.             }
  182.         }
  183.     }
  184.     public function onSubmittedStatusRedirectionEvent(ListingEvent $event): void
  185.     {
  186.         /** @var Listing $listing */
  187.         $listing $event->getListing();
  188.         $userId $listing->getUser();
  189.         if ($this->specialAddListingService->hasSpecialAddListingGroup($userId)) {
  190.             $userUnlimitedListings $this->userServicesManager->hasActiveService(UserServicesType::UNLIMITED_LISTINGS$userId);
  191.             if (!$userUnlimitedListings || ($userUnlimitedListings && == $userUnlimitedListings['remainingQuota'])) {
  192.                 $event->setResponse($this->redirect(
  193.                     'listing_slug',
  194.                     ['id' => $listing->getId(), 'slug' => $listing->getSlug()]
  195.                 ));
  196.                 return;
  197.             }
  198.         }
  199.         switch ($listing->getStatus()) {
  200.             case ListingStatus::PENDING_PAYMENT:
  201.                 $event->setResponse($this->redirect(
  202.                     'listing_confirm_publish_credit',
  203.                     ['id' => $listing->getId()]
  204.                 ));
  205.                 break;
  206.             case ListingStatus::PENDING_PHOTOS:
  207.                 $this->setFlashMessage('info'$this->getTranslator()->trans('add_listing_page.success_messages.add_photos_message'));
  208.                 $event->setResponse($this->redirect(
  209.                     'listing_upload',
  210.                     ['id' => $event->getListing()->getId()]
  211.                 ));
  212.                 break;
  213.         }
  214.     }
  215.     /**
  216.      * @throws \Exception
  217.      */
  218.     public function onListingPublishEvent(ListingEvent $event): void
  219.     {
  220.         $listing $event->getListing();
  221.         $listingPublishPaid $listing->getPublicationCredit();
  222.         $listingPublishFeatured $listing->getFeaturedPublicationCredit();
  223.         $listingRule $this->listingRuleMatcher->match($listing);
  224.         if (ListingCategories::FIRST_LISTING_FOR_FREE === $listing->getCategory()) {
  225.             $listing->setExpiresAt(new \DateTime('+'.$listingRule['first_free_duration'].' days'));
  226.             return;
  227.         }
  228.         if ($listingRule['duration'] && (!$listing->getExpiresAt() || new \DateTime() >= $listing->getExpiresAt())) {
  229.             $listing->setExpiresAt(new \DateTime('+'.$listingRule['duration'].' days'));
  230.         }
  231.         if ($listingPublishPaid) {
  232.             if (!$listingPublishPaid->getExpiresAt()) {
  233.                 $listingPublishPaid->setExpiresAt($listing->getExpiresAt());
  234.             }
  235.         }
  236.         if ($listingPublishFeatured) {
  237.             if (!$listingPublishFeatured->getExpiresAt() && !$listingPublishFeatured->getFeaturingStatus()) {
  238.                 $duration $this->getListingFeaturingService()->getFeaturedTypeDuration($listingRule$listingPublishFeatured->getType());
  239.                 $listingPublishFeatured->setExpiresAt(new \DateTime('+'.$duration.' days'));
  240.                 $this->dispatcher->dispatch(new ListingFeatureEvent($listingPublishFeatured), 'aqarmap.listing.feature.bumpup');
  241.             }
  242.         }
  243.     }
  244.     public function onFeaturingListingApprovalEvent(ListingEvent $event): void
  245.     {
  246.         $listing $event->getListing();
  247.         $listingPublishFeatured $listing->getFeaturedPublicationCredit();
  248.         $listingManager $this->getListingManager();
  249.         $listingFeatureService $this->getListingFeaturingService();
  250.         $listingRule $listingManager->getListingRules($listing);
  251.         if ($listingPublishFeatured && ListingStatus::LIVE == $listing->getStatus()) {
  252.             $listing->setFeatured($listingFeatureService->getListingFeaturedType($listingPublishFeatured->getType()));
  253.             $listingPublishFeatured->setFeaturingStatus(ListingFeaturedStatus::APPROVED);
  254.             $listingPublishFeatured->setApprovedAt(new \DateTime());
  255.             if (!$listingPublishFeatured->getExpiresAt()) {
  256.                 $duration $this->getListingFeaturingService()->getFeaturedTypeDuration($listingRule$listingPublishFeatured->getType());
  257.                 $listingPublishFeatured->setExpiresAt(new \DateTime('+'.$duration.' days'));
  258.             }
  259.         }
  260.         $em $this->getEntityManager();
  261.         $em->persist($listing);
  262.         $em->flush();
  263.     }
  264.     /**
  265.      * @throws \Exception
  266.      */
  267.     public function onFeaturingListingRejectEvent(ListingEvent $event): void
  268.     {
  269.         $listing $event->getListing();
  270.         $listingFeatured $listing->getLastListingFeature();
  271.         if (ListingStatus::LIVE == $listing->getStatus()) {
  272.             $listingFeatured->setFeaturingStatus(ListingFeaturedStatus::REJECTED);
  273.             $listingFeatured->setExpiresAt(new \DateTime('-2 days'));
  274.         }
  275.         $em $this->getEntityManager();
  276.         $em->persist($listingFeatured);
  277.         $featureTypeLabel $this->getTranslator()->trans($listingFeatured->getPendingFeaturedLabel());
  278.         $balance $this->creditManager->getBalance($listing->getUser());
  279.         $amount abs($listingFeatured->getCredit()->getAmount());
  280.         $credit = new Credit();
  281.         $credit
  282.             ->setUser($listing->getUser())
  283.             ->setAmount(abs($listingFeatured->getCredit()->getAmount()))
  284.             ->setDescription('Rejected to be '.$featureTypeLabel)
  285.             ->setBalance($balance $amount)
  286.             ->setStatus(CreditStatus::SUCCESS)
  287.             ->setCreatedAt(new \DateTime());
  288.         $em->persist($credit);
  289.         $em->flush();
  290.     }
  291.     public function getEntityManager()
  292.     {
  293.         return $this->entityManager;
  294.     }
  295.     /**
  296.      * @return TranslatorInterface
  297.      */
  298.     public function getTranslator()
  299.     {
  300.         return $this->translator;
  301.     }
  302.     public static function getSubscribedEvents()
  303.     {
  304.         return [
  305.             'aqarmap.listing.pre_save' => ['preSaveListingEvent'],
  306.             'aqarmap.listing.submitted' => [['onSubmittedEvent'], ['onSubmittedStatusRedirectionEvent']],
  307.             'aqarmap.listing.resubmitted' => [['onSubmittedEvent'], ['onSubmittedStatusRedirectionEvent']],
  308.             'aqarmap.listing.publish' => ['onListingPublishEvent'],
  309.             'aqarmap.listing.featuring.approved' => ['onFeaturingListingApprovalEvent'],
  310.             'aqarmap.listing.free_publish' => ['onListingPublishEvent'],
  311.             'aqarmap.listing.publish_without_photos' => ['onListingPublishEvent'],
  312.             'aqarmap.listing.featuring.rejected' => ['onFeaturingListingRejectEvent'],
  313.         ];
  314.     }
  315.     /**
  316.      * @return ListingManager
  317.      */
  318.     protected function getListingManager()
  319.     {
  320.         return $this->listingManager;
  321.     }
  322.     /**
  323.      * @return ListingFeatureService
  324.      */
  325.     protected function getListingFeaturingService()
  326.     {
  327.         return $this->listingFeatureService;
  328.     }
  329.     /**
  330.      * @param string $type
  331.      * @param string $message
  332.      */
  333.     private function setFlashMessage($type$message)
  334.     {
  335.         return $this->session->getFlashBag()->add($type$message);
  336.     }
  337.     private function redirect($route$parameters = [])
  338.     {
  339.         return new RedirectResponse(
  340.             $this->router->generate($route$parameters),
  341.             \Symfony\Component\HttpFoundation\Response::HTTP_FOUND
  342.         );
  343.     }
  344. }