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

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