src/Aqarmap/Bundle/ListingBundle/Controller/ListingController.php line 395

Open in your IDE?
  1. <?php
  2. namespace Aqarmap\Bundle\ListingBundle\Controller;
  3. use App\Exception\LogicHttpException;
  4. use Aqarmap\Bundle\CreditBundle\Constant\CreditStatus;
  5. use Aqarmap\Bundle\CreditBundle\Entity\Credit;
  6. use Aqarmap\Bundle\CreditBundle\Services\CreditManager;
  7. use Aqarmap\Bundle\FeatureToggleBundle\Service\FeatureToggleManager;
  8. use Aqarmap\Bundle\FinancialAidsBundle\Service\FinancialAidService;
  9. use Aqarmap\Bundle\ListingBundle\Constant\LeadTypes;
  10. use Aqarmap\Bundle\ListingBundle\Constant\ListingCategories;
  11. use Aqarmap\Bundle\ListingBundle\Constant\ListingFeaturedTypes;
  12. use Aqarmap\Bundle\ListingBundle\Constant\ListingFeatures;
  13. use Aqarmap\Bundle\ListingBundle\Constant\ListingSections;
  14. use Aqarmap\Bundle\ListingBundle\Constant\ListingSellerRoles;
  15. use Aqarmap\Bundle\ListingBundle\Constant\ListingSource;
  16. use Aqarmap\Bundle\ListingBundle\Constant\ListingStatus;
  17. use Aqarmap\Bundle\ListingBundle\Constant\PropertyRegistrationStatusOption;
  18. use Aqarmap\Bundle\ListingBundle\Constant\ResaleListingsConstant;
  19. use Aqarmap\Bundle\ListingBundle\Contracts\PhoneManagerInterface;
  20. use Aqarmap\Bundle\ListingBundle\Contracts\RelatedResultServiceInterface;
  21. use Aqarmap\Bundle\ListingBundle\Entity\CallRequest;
  22. use Aqarmap\Bundle\ListingBundle\Entity\File;
  23. use Aqarmap\Bundle\ListingBundle\Entity\Listing;
  24. use Aqarmap\Bundle\ListingBundle\Entity\ListingPhone;
  25. use Aqarmap\Bundle\ListingBundle\Entity\Phone;
  26. use Aqarmap\Bundle\ListingBundle\Entity\Section;
  27. use Aqarmap\Bundle\ListingBundle\Event\ListingEvent;
  28. use Aqarmap\Bundle\ListingBundle\Exception\InvalidLeadValidationHttpException;
  29. use Aqarmap\Bundle\ListingBundle\Form\AdvancedFilterType;
  30. use Aqarmap\Bundle\ListingBundle\Form\AdvancedSearchType;
  31. use Aqarmap\Bundle\ListingBundle\Form\CallRequestFormType;
  32. use Aqarmap\Bundle\ListingBundle\Form\ContactSellerFormType;
  33. use Aqarmap\Bundle\ListingBundle\Form\ContactSellerWideFormType;
  34. use Aqarmap\Bundle\ListingBundle\Form\LandingPageFormType;
  35. use Aqarmap\Bundle\ListingBundle\Form\ListingInitializeType;
  36. use Aqarmap\Bundle\ListingBundle\Form\ListingType;
  37. use Aqarmap\Bundle\ListingBundle\Form\LiteListingType;
  38. use Aqarmap\Bundle\ListingBundle\Form\Model\LandingPage;
  39. use Aqarmap\Bundle\ListingBundle\Form\MultipleSearchFormType;
  40. use Aqarmap\Bundle\ListingBundle\Form\PhotoType;
  41. use Aqarmap\Bundle\ListingBundle\Form\QuickLeadType;
  42. use Aqarmap\Bundle\ListingBundle\Repository\ListingPhotoRepository;
  43. use Aqarmap\Bundle\ListingBundle\Service\AdvancedFilterFormTypeManager;
  44. use Aqarmap\Bundle\ListingBundle\Service\AdvancedSearchFormTypeManager;
  45. use Aqarmap\Bundle\ListingBundle\Service\CallRequestManager;
  46. use Aqarmap\Bundle\ListingBundle\Service\Contracts\ListingLeadManagerInterface;
  47. use Aqarmap\Bundle\ListingBundle\Service\Contracts\LocationManagerInterface;
  48. use Aqarmap\Bundle\ListingBundle\Service\FreeListingService;
  49. use Aqarmap\Bundle\ListingBundle\Service\InteractionService;
  50. use Aqarmap\Bundle\ListingBundle\Service\ListingFeatureService;
  51. use Aqarmap\Bundle\ListingBundle\Service\ListingManager;
  52. use Aqarmap\Bundle\ListingBundle\Service\ListingRuleMatcher;
  53. use Aqarmap\Bundle\ListingBundle\Service\Mortgage\MortgageService;
  54. use Aqarmap\Bundle\ListingBundle\Service\SpecialAddListingService;
  55. use Aqarmap\Bundle\ListingBundle\Service\SpecialListingFeatureDecorator;
  56. use Aqarmap\Bundle\ListingBundle\Service\V4\CompoundDetailService;
  57. use Aqarmap\Bundle\MainBundle\Form\ConfirmFeaturedFormType;
  58. use Aqarmap\Bundle\MainBundle\Form\ConfirmFormType;
  59. use Aqarmap\Bundle\MainBundle\Service\MobileDetectionService;
  60. use Aqarmap\Bundle\MainBundle\Service\Setting;
  61. use Aqarmap\Bundle\MessageBundle\Service\Composer;
  62. use Aqarmap\Bundle\NeighborhoodBundle\Service\NeighborhoodManager;
  63. use Aqarmap\Bundle\NotificationBundle\DatabaseNotification;
  64. use Aqarmap\Bundle\NotifierBundle\Event\NotifierEvent;
  65. use Aqarmap\Bundle\OTPBundle\Contract\OtpServiceInterface;
  66. use Aqarmap\Bundle\SearchBundle\Services\CompoundFaqsService;
  67. use Aqarmap\Bundle\SearchBundle\Services\ElasticListingSearch\DefaultListingSearch;
  68. use Aqarmap\Bundle\TopSellerBundle\Model\TopSeller;
  69. use Aqarmap\Bundle\TopSellerBundle\Service\TopSellerRetrievalService;
  70. use Aqarmap\Bundle\UserBundle\Constant\UserServicesType;
  71. use Aqarmap\Bundle\UserBundle\Constant\UserTypes;
  72. use Aqarmap\Bundle\UserBundle\Entity\User;
  73. use Aqarmap\Bundle\UserBundle\Entity\UserServices;
  74. use Aqarmap\Bundle\UserBundle\Form\QuickRegistrationFormType;
  75. use Aqarmap\Bundle\UserBundle\Repository\UserPackagesRepository;
  76. use Aqarmap\Bundle\UserBundle\Services\UserActivityService;
  77. use Aqarmap\Bundle\UserBundle\Services\UserManager;
  78. use Aqarmap\Bundle\UserBundle\Services\UserPackagesService;
  79. use Aqarmap\Bundle\UserBundle\Services\UserServicesManager;
  80. use Doctrine\ORM\EntityManager;
  81. use Doctrine\ORM\EntityManagerInterface;
  82. use FOS\RestBundle\Controller\Annotations as Rest;
  83. use FOS\RestBundle\View\View;
  84. use FOS\UserBundle\Model\UserManagerInterface;
  85. use Gedmo\Translatable\TranslatableListener;
  86. use Knp\Component\Pager\PaginatorInterface;
  87. use Liip\ImagineBundle\Imagine\Cache\CacheManager;
  88. use Predis\ClientInterface as RedisClient;
  89. use Psr\Log\LoggerInterface;
  90. use Psr\Log\LogLevel;
  91. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
  92. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  93. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  94. use Symfony\Component\Form\FormInterface;
  95. use Symfony\Component\HttpFoundation\JsonResponse;
  96. use Symfony\Component\HttpFoundation\RedirectResponse;
  97. use Symfony\Component\HttpFoundation\Request;
  98. use Symfony\Component\HttpFoundation\Response;
  99. use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
  100. use Symfony\Component\Routing\Annotation\Route;
  101. use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  102. use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
  103. use Symfony\Contracts\Translation\TranslatorInterface;
  104. use Vich\UploaderBundle\Handler\DownloadHandler;
  105. use Vich\UploaderBundle\Templating\Helper\UploaderHelper;
  106. /**
  107.  * Listing controller.
  108.  */
  109. class ListingController extends AbstractController
  110. {
  111.     /**
  112.      * @var Composer
  113.      */
  114.     private $messageComposer;
  115.     /**
  116.      * @var DatabaseNotification
  117.      */
  118.     private $databaseNotification;
  119.     /**
  120.      * @var LoggerInterface
  121.      */
  122.     private $logger;
  123.     /**
  124.      * @var TranslatorInterface
  125.      */
  126.     private $translator;
  127.     /**
  128.      * @var FeatureToggleManager
  129.      */
  130.     private $featureToggleManager;
  131.     /**
  132.      * @var Setting
  133.      */
  134.     private $setting;
  135.     /**
  136.      * @var ListingManager
  137.      */
  138.     private $listingManager;
  139.     /**
  140.      * @var EventDispatcherInterface
  141.      */
  142.     private $dispatcher;
  143.     /**
  144.      * @var InteractionService
  145.      */
  146.     private $interactionService;
  147.     /**
  148.      * @var NeighborhoodManager
  149.      */
  150.     private $neighborhoodManager;
  151.     /**
  152.      * @var DefaultListingSearch
  153.      */
  154.     private $defaultListingSearch;
  155.     /**
  156.      * @var RelatedResultServiceInterface
  157.      */
  158.     private $relatedResultService;
  159.     /**
  160.      * @var TopSellerRetrievalService
  161.      */
  162.     private $topSellerRetrievalService;
  163.     /**
  164.      * @var FinancialAidService
  165.      */
  166.     private $financialAidService;
  167.     /**
  168.      * @var ListingLeadManagerInterface
  169.      */
  170.     private $listingLeadManager;
  171.     /**
  172.      * @var CompoundFaqsService
  173.      */
  174.     private $compoundFaqsService;
  175.     /**
  176.      * @var PaginatorInterface
  177.      */
  178.     private $paginator;
  179.     /**
  180.      * @var UserActivityService
  181.      */
  182.     private $userActivityService;
  183.     /**
  184.      * @var MobileDetectionService
  185.      */
  186.     private $mobileDetectionService;
  187.     /**
  188.      * @var RedisClient
  189.      */
  190.     private $redis;
  191.     /**
  192.      * @var CacheManager
  193.      */
  194.     private $imagine;
  195.     /**
  196.      * @var UploaderHelper
  197.      */
  198.     private $uploaderHelper;
  199.     /**
  200.      * @var CallRequestManager
  201.      */
  202.     private $callRequestManager;
  203.     /**
  204.      * @var AuthorizationCheckerInterface
  205.      */
  206.     private $authorizationChecker;
  207.     /**
  208.      * @var TokenStorage
  209.      */
  210.     private $tokenStorage;
  211.     /**
  212.      * @var MortgageService
  213.      */
  214.     private $mortgageService;
  215.     /**
  216.      * @var ListingRuleMatcher
  217.      */
  218.     private $listingRuleMatcher;
  219.     /**
  220.      * @var CreditManager
  221.      */
  222.     private $creditManager;
  223.     /**
  224.      * @var UserServicesManager
  225.      */
  226.     private $userServicesManager;
  227.     /**
  228.      * @var UserManagerInterface
  229.      */
  230.     private $FOSUserManager;
  231.     /**
  232.      * @var PhoneManagerInterface
  233.      */
  234.     private $phoneManager;
  235.     /**
  236.      * @var ListingFeatureService
  237.      */
  238.     private $listingFeatureService;
  239.     private UserManager $userManager;
  240.     /**
  241.      * @var AdvancedSearchFormTypeManager
  242.      */
  243.     private $advancedSearchFormTypeManager;
  244.     /**
  245.      * @var AdvancedFilterFormTypeManager
  246.      */
  247.     private $advancedFilterFormTypeManager;
  248.     /** @var CompoundDetailService */
  249.     private $compoundDetailService;
  250.     /** @var TranslatableListener */
  251.     private $translatableListener;
  252.     /** @var EntityManagerInterface */
  253.     private $entityManager;
  254.     /** @var UserPackagesRepository */
  255.     private $userPackagesRepository;
  256.     public function __construct(
  257.         Composer $messageComposer,
  258.         OtpServiceInterface $otpService,
  259.         DatabaseNotification $databaseNotification,
  260.         LoggerInterface $logger,
  261.         TranslatorInterface $translator,
  262.         FeatureToggleManager $featureToggleManager,
  263.         Setting $setting,
  264.         ListingManager $listingManager,
  265.         EventDispatcherInterface $dispatcher,
  266.         InteractionService $interactionService,
  267.         NeighborhoodManager $neighborhoodManager,
  268.         DefaultListingSearch $defaultListingSearch,
  269.         RelatedResultServiceInterface $relatedResultService,
  270.         LocationManagerInterface $locationManager,
  271.         TopSellerRetrievalService $topSellerRetrievalService,
  272.         FinancialAidService $financialAidService,
  273.         ListingLeadManagerInterface $listingLeadManager,
  274.         CompoundFaqsService $compoundFaqsService,
  275.         PaginatorInterface $paginator,
  276.         UserActivityService $userActivityService,
  277.         MobileDetectionService $mobileDetectionService,
  278.         RedisClient $redis,
  279.         CacheManager $imagine,
  280.         UploaderHelper $uploaderHelper,
  281.         CallRequestManager $callRequestManager,
  282.         AuthorizationCheckerInterface $authorizationChecker,
  283.         TokenStorageInterface $tokenStorage,
  284.         MortgageService $mortgageService,
  285.         ListingRuleMatcher $listingRuleMatcher,
  286.         CreditManager $creditManager,
  287.         UserServicesManager $userServicesManager,
  288.         UserManagerInterface $FOSUserManager,
  289.         PhoneManagerInterface $phoneManager,
  290.         FreeListingService $freeListingService,
  291.         ListingFeatureService $listingFeatureService,
  292.         UserManager $userManager,
  293.         AdvancedSearchFormTypeManager $advancedSearchFormTypeManager,
  294.         AdvancedFilterFormTypeManager $advancedFilterFormTypeManager,
  295.         SpecialAddListingService $specialAddListingService,
  296.         CompoundDetailService $compoundDetailService,
  297.         SpecialListingFeatureDecorator $specialListingFeatureDecorator,
  298.         TranslatableListener $translatableListener,
  299.         EntityManagerInterface $entityManager,
  300.         UserPackagesRepository $userPackagesRepository
  301.     ) {
  302.         $this->messageComposer $messageComposer;
  303.         $this->databaseNotification $databaseNotification;
  304.         $this->logger $logger;
  305.         $this->translator $translator;
  306.         $this->featureToggleManager $featureToggleManager;
  307.         $this->setting $setting;
  308.         $this->listingManager $listingManager;
  309.         $this->dispatcher $dispatcher;
  310.         $this->interactionService $interactionService;
  311.         $this->neighborhoodManager $neighborhoodManager;
  312.         $this->defaultListingSearch $defaultListingSearch;
  313.         $this->relatedResultService $relatedResultService;
  314.         $this->topSellerRetrievalService $topSellerRetrievalService;
  315.         $this->financialAidService $financialAidService;
  316.         $this->listingLeadManager $listingLeadManager;
  317.         $this->compoundFaqsService $compoundFaqsService;
  318.         $this->paginator $paginator;
  319.         $this->userActivityService $userActivityService;
  320.         $this->mobileDetectionService $mobileDetectionService;
  321.         $this->redis $redis;
  322.         $this->imagine $imagine;
  323.         $this->uploaderHelper $uploaderHelper;
  324.         $this->callRequestManager $callRequestManager;
  325.         $this->authorizationChecker $authorizationChecker;
  326.         $this->tokenStorage $tokenStorage;
  327.         $this->mortgageService $mortgageService;
  328.         $this->listingRuleMatcher $listingRuleMatcher;
  329.         $this->creditManager $creditManager;
  330.         $this->userServicesManager $userServicesManager;
  331.         $this->FOSUserManager $FOSUserManager;
  332.         $this->phoneManager $phoneManager;
  333.         $this->listingFeatureService $listingFeatureService;
  334.         $this->userManager $userManager;
  335.         $this->advancedSearchFormTypeManager $advancedSearchFormTypeManager;
  336.         $this->advancedFilterFormTypeManager $advancedFilterFormTypeManager;
  337.         $this->specialAddListingService $specialAddListingService;
  338.         $this->specialListingFeatureDecorator $specialListingFeatureDecorator;
  339.         $this->compoundDetailService $compoundDetailService;
  340.         $this->translatableListener $translatableListener;
  341.         $this->entityManager $entityManager;
  342.         $this->userPackagesRepository $userPackagesRepository;
  343.     }
  344.     /**
  345.      * Listing Details Action.
  346.      *
  347.      * @Route("/{id}/{notification}", defaults={"notification"=0}, requirements={"id" = "\d+"}, options={"i18n" = false, "expose" = true}, name="listing_view", methods={"GET"})
  348.      * @Route("/listing/{id}/notification/{notification}", defaults={"notification"=0}, name="listing_view_notification", methods={"GET"})
  349.      * @Route("/listing/{id}", requirements={"id" = "\d+"} , options={"expose" = true} , name="listing_details", methods={"GET"})
  350.      * @Route("/listing/{id}-{slug}", requirements={"id" = "\d+", "slug" = ".+"}, name="listing_slug", methods={"GET"})
  351.      */
  352.     public function read(Request $requestListing $listingEntityManagerInterface $em)
  353.     {
  354.         if ($request->get('notification')) {
  355.             try {
  356.                 $this->databaseNotification->markOneAsRead($request->get('notification'));
  357.             } catch (\Exception $exception) {
  358.                 $this->logger->log(LogLevel::ERROR$exception->getMessage());
  359.             }
  360.         }
  361.         // Redirect to the right URL if the URL is short-URL or the listing slug is incorrect
  362.         if (('listing_slug' != $request->get('_route')
  363.                 || $request->attributes->get('slug') != $listing->getSlug())
  364.             && !empty($listing->getSlug())
  365.         ) {
  366.             return $this->redirect($this->generateUrl('listing_slug'array_merge($request->query->all(), [
  367.                 'id' => $listing->getId(),
  368.                 'slug' => $listing->getSlug(),
  369.             ])), Response::HTTP_MOVED_PERMANENTLY);
  370.         }
  371.         $listingStatus = !\in_array($listing->getStatus(), [ListingStatus::LIVEListingStatus::PENDING]);
  372.         if ($listingStatus && !$request->query->get('noredirect') && $listing->getUser() != $this->getUser()) {
  373.             if (!$listing->getSection()->getSearchable()) {
  374.                 return $this->redirect($this->generateUrl('compound_search'), Response::HTTP_FOUND);
  375.             }
  376.             try {
  377.                 $searchableLocation $listing->getLocation()->getNearestSearchable();
  378.             } catch (\Exception $exception) {
  379.                 $this->addFlash(
  380.                     'danger',
  381.                     $this->translator->trans('listing.not_available')
  382.                 );
  383.                 return $this->redirect($this->generateUrl('homepage'), Response::HTTP_FOUND);
  384.             }
  385.             return $this->redirect($this->generateUrl('search', [
  386.                 'section_slug' => $listing->getSection()->getSlug(),
  387.                 'property_type_slug' => $listing->getPropertyType()->getSlug(),
  388.                 'location_slug' => $searchableLocation->getSlug(),
  389.             ]), Response::HTTP_MOVED_PERMANENTLY);
  390.         }
  391.         $listingRepo $em->getRepository(Listing::class);
  392.         if ($notifierId $request->query->get('notifier')) {
  393.             if (null !== $notifier $em->getRepository('AqarmapNotifierBundle:Notifier')->find($notifierId)) {
  394.                 $this->dispatcher->dispatch(new NotifierEvent($notifier), 'aqarmap.notifier.interaction');
  395.             } else {
  396.                 $this->logger->warning('Notifier with id: '.$notifierId.' was not found!');
  397.             }
  398.         }
  399.         $this->interactionService->increaseViews($listing$this->getUser());
  400.         $relatedListingCriteriaMapper $this->relatedResultService->getRelatedListingCriteriaMapper($listing);
  401.         $relatedListings $this->defaultListingSearch->search($relatedListingCriteriaMapper)['searchResults'];
  402.         $topSeller $this->createTopSeller($listing);
  403.         $topSearchableCompanies $this->topSellerRetrievalService->getTopSellerPersonalData($topSeller$request->getLocale());
  404.         $searchableLocation $listing->getLocation()->getNearestSearchable();
  405.         $isPlaceHoldered false;
  406.         $userProfilePhoto $listing->getUser()->isValidPersonalPhoto() ? $listing->getUser()->getPersonalPhoto() : null;
  407.         if ($listing->getLogo() || ($listing->getParent() && $listing->getParent()->getLogo())) {
  408.             if ($listing->getParent() && $listing->getParent()->getLogo()) {
  409.             }
  410.         } elseif (!empty($listing->getPhotosForSlider()) && $listing->getUser()->getIsValidLogo()) {
  411.             $isPlaceHoldered true;
  412.         }
  413.         $this->financialAidService->setFinancialAidInListing($listing);
  414.         $activeListingsCount $listing->getUser()->getActiveListingsCount();
  415.         $leadsCount 0;
  416.         if ($this->featureToggleManager->isEnabled('web.client.served.count')) {
  417.             $leadsCount $listing->getUser()->getClientServedCount();
  418.         }
  419.         $listing current(
  420.             $this->listingManager->setUserActivities(
  421.                 [$listing],
  422.                 [$listing->getId()]
  423.             )
  424.         );
  425.         $hasUserMadeLead false;
  426.         if ($user $this->getUser()) {
  427.             $hasUserMadeLead $this->listingLeadManager->hasUserMadeLead($listing$user);
  428.         }
  429.         $compoundFaqs = [];
  430.         $listingDetails $listing;
  431.         if ($listing->isProject()) {
  432.             $compoundFaqs $this->compoundFaqsService->generateFaqData($listing);
  433.             $resaleRegularListingsPaginated $this->paginator->paginate(
  434.                 $listingRepo->getSectionListings($listingnullListingSections::FOR_SALE),
  435.                 $request->query->get('page'ResaleListingsConstant::PAGE),
  436.                 ResaleListingsConstant::LIMIT
  437.             );
  438.             $this->compoundDetailService->getPropertyTypeChildrens($listing$request->getLocale());
  439.             $liveUnitsPaginated $listing->getPropertyTypeChildren();
  440.             $this->compoundDetailService->getPropertyTypeUnitsChildrens($listingListingSections::FOR_SALE$request->getLocale());
  441.             $resaleUnitsPaginated $listing->getPropertyTypeChildren();
  442.             $this->compoundDetailService->getPropertyTypeUnitsChildrens($listingListingSections::FOR_RENT$request->getLocale());
  443.             $rentUnitsPaginated $listing->getPropertyTypeChildren();
  444.         }
  445.         $request->cookies->get('user-agent');
  446.         $mobileDetection $this->mobileDetectionService->mobileDetection($request$return);
  447.         $return = [
  448.             'listing' => $listingDetails,
  449.             'searchableLocation' => $searchableLocation,
  450.             'contact_seller_form' => $this->contactSellerForm($listing)->createView(),
  451.             'quick_registration_form' => $this->quickRegistrationForm()->createView(),
  452.             'call_request' => $this->callRequestForm($listing)->createView(),
  453.             'related_listings' => $relatedListings,
  454.             'relatedListingsCount' => (null != $relatedListings) ? $relatedListings->getTotalItemCount() : 0,
  455.             'location_statistics' => $this->neighborhoodManager->getStatistics(
  456.                 $listing->getLocation()->getNearestNeighborhood(),
  457.                 $listing->getPropertyType()
  458.             ),
  459.             'topSearchableCompanies' => $topSearchableCompanies,
  460.             'topSearchableCompaniesCount' => \count($topSearchableCompanies),
  461.             'isPlaceHoldered' => $isPlaceHoldered,
  462.             'userProfilePhoto' => $userProfilePhoto,
  463.             'activeListingsCount' => $activeListingsCount,
  464.             'leadsCount' => $leadsCount,
  465.             'featureToggle' => $this->userActivityService->getFeatureToggles(),
  466.             'leadAnalytics' => $this->listingManager->getLeadAnalytics($listing),
  467.             'otherUnits' => $this->listingManager->getOtherUnits($listing$request->getLocale()),
  468.             'hasUserMadeLead' => $hasUserMadeLead,
  469.             'resaleRegularListings' => $resaleRegularListingsPaginated ?? null,
  470.             'resaleUnitsPaginated' => $resaleUnitsPaginated ?? null,
  471.             'liveUnitsPaginated' => $liveUnitsPaginated ?? null,
  472.             'rentUnitsPaginated' => $rentUnitsPaginated ?? null,
  473.             'compoundFaqs' => $compoundFaqs,
  474.             'isMobile' => $mobileDetection['isMobile'],
  475.         ];
  476.         if ($mobileDetection['isMobile']) {
  477.             $nearestLocations $em
  478.                 ->getRepository(\Aqarmap\Bundle\ListingBundle\Entity\Location::class)
  479.                 ->getNearestLocations([$listing->getLocation()])
  480.             ;
  481.             $return['nearestLocations'] = $nearestLocations;
  482.             foreach ($mobileDetection as $key => $val) {
  483.                 $return[$key] = $val;
  484.             }
  485.             return $this->render('@AqarmapListing/Listing/read-mob.html.twig'$return);
  486.         }
  487.         $return['discussions'] = $em
  488.             ->getRepository('AqarmapDiscussionBundle:Discussion')
  489.             ->getTrendingWithLocation($listing->getLocation()->getId(), 3)
  490.         ;
  491.         return $this->render('@AqarmapListing/Listing/read.html.twig'$return);
  492.     }
  493.     /**
  494.      * TopSeller Attributes from listing data.
  495.      *
  496.      * @param  Listing
  497.      *
  498.      * @return TopSeller
  499.      */
  500.     private function createTopSeller($listing)
  501.     {
  502.         $topSeller = new TopSeller();
  503.         $topSeller->setLocation($listing->getLocation()->getId());
  504.         $topSeller->setSection($listing->getSection()->getId());
  505.         $topSeller->setPropertyType($listing->getPropertyType()->getId());
  506.         return $topSeller;
  507.     }
  508.     /**
  509.      * Advanced Search Form.
  510.      */
  511.     protected function createAdvancedSearchForm(): FormInterface
  512.     {
  513.         return $this->advancedSearchFormTypeManager
  514.             ->setAction($this->generateUrl('listing_advanced_search'))
  515.             ->setFormType(AdvancedSearchType::class)
  516.             ->setMethodType('Post')
  517.             ->setSettings($this->setting)
  518.             ->applyOptions()
  519.             ->createForm();
  520.     }
  521.     /**
  522.      * Advanced Search Form.
  523.      */
  524.     protected function createAdvancedFilterForm(): FormInterface
  525.     {
  526.         $customFields $this->redis->get('customFields');
  527.         return $this->advancedFilterFormTypeManager
  528.             ->setAction($this->generateUrl('listing_filter_search'))
  529.             ->setFormType(AdvancedFilterType::class)
  530.             ->setMethodType('Post')
  531.             ->setSettings($this->setting)
  532.             ->setCustomFields($customFields unserialize($customFields) : [])
  533.             ->applyOptions()
  534.             ->createForm();
  535.     }
  536.     /**
  537.      * Multiple Search Form.
  538.      */
  539.     protected function createMultipleSearchForm(): FormInterface
  540.     {
  541.         return $this->advancedSearchFormTypeManager
  542.             ->setAction($this->generateUrl('listing_multiple_search'))
  543.             ->setFormType(MultipleSearchFormType::class)
  544.             ->setMethodType('Post')
  545.             ->setSettings($this->setting)
  546.             ->applyOptions()
  547.             ->createForm();
  548.     }
  549.     /**
  550.      * Latest Listings Action.
  551.      *
  552.      * @Route("/listing/latest", name="listing_latest", methods={"GET"})
  553.      */
  554.     public function latest(Request $request): Response
  555.     {
  556.         /** @var $em \Doctrine\ORM\EntityManager */
  557.         $em $this->getDoctrine()->getManager();
  558.         $pagination $this->paginator->paginate(
  559.             $em->getRepository(Listing::class)->getLatestListings(),
  560.             $request->query->get('page'1)
  561.         );
  562.         return $this->render('@AqarmapListing/Listing/latest.html.twig', [
  563.             'listings' => $pagination,
  564.         ]);
  565.     }
  566.     /**
  567.      * @Route("/listing/latest/{section}.{_format}")
  568.      *
  569.      * @return Response
  570.      */
  571.     public function CSVLatestListings(Request $requestSection $section)
  572.     {
  573.         /** @var EntityManager $em */
  574.         $em $this->getDoctrine()->getManager();
  575.         $listings $em->getRepository(Listing::class)->findBy([
  576.             'section' => $section,
  577.             'status' => ListingStatus::LIVE,
  578.         ], ['id' => 'desc'], 100);
  579.         $handle fopen('php://memory''r+');
  580.         fputcsv($handle, [
  581.             $request->query->get('id''id'),
  582.             $request->query->get('section''section'),
  583.             $request->query->get('description''description'),
  584.             $request->query->get('image''image'),
  585.             $request->query->get('link''link'),
  586.             $request->query->get('title''title'),
  587.             $request->query->get('price''price'),
  588.             $request->query->get('formatted_price''formatted_price'),
  589.             $request->query->get('price_currency''price_currency'),
  590.             $request->query->get('location''location'),
  591.             $request->query->get('address''address'),
  592.             $request->query->get('property_type''property_type'),
  593.             $request->query->get('availability''availability'),
  594.             $request->query->get('condition''condition'),
  595.         ]);
  596.         foreach ($listings as $listing) {
  597.             $thumb null;
  598.             if ($listing->getMainPhoto()) {
  599.                 $thumb $this->imagine->generateUrl(
  600.                     $this->uploaderHelper->asset($listing->getMainPhoto()->getFile(), 'file'),
  601.                     'large'
  602.                 );
  603.             }
  604.             $description preg_split('/\n/'mb_substr($listing->getDescription(), 0200), \PREG_SPLIT_DELIM_CAPTURE);
  605.             fputcsv($handle, [
  606.                 $listing->getId(),
  607.                 $section->getTitle(),
  608.                 $description[0],
  609.                 $thumb,
  610.                 $this->generateUrl('listing_view', ['id' => $listing->getId()], true),
  611.                 $listing->getTitle(),
  612.                 $listing->getPrice(),
  613.                 number_format($listing->getPrice()),
  614.                 sprintf('%s %s'number_format($listing->getPrice()), 'EGP'),
  615.                 $listing->getLocation()->getTitle(),
  616.                 $listing->getAddress(),
  617.                 $listing->getPropertyType()->getTitle(),
  618.                 'in stock',
  619.                 'new',
  620.             ]);
  621.         }
  622.         rewind($handle);
  623.         $content stream_get_contents($handle);
  624.         fclose($handle);
  625.         return new Response($contentResponse::HTTP_OK, [
  626.             'Content-Type' => 'application/force-download',
  627.             'Content-Disposition' => sprintf(
  628.                 'attachment; filename="latest-listings - %s - %s.csv"',
  629.                 $section->getTitle(),
  630.                 date('Y-m-d H-i-s')
  631.             ),
  632.         ]);
  633.     }
  634.     /**
  635.      * @deprecated
  636.      *
  637.      * @Route("/listing/{id}/one", name="landing_page", methods={"GET", "POST"})
  638.      *
  639.      * @Rest\View()
  640.      *
  641.      * @return array
  642.      */
  643.     public function landingPage(Request $requestListing $listing)
  644.     {
  645.         $form $this->createForm(LandingPageFormType::class, $landingPage = new LandingPage(), [
  646.             'action' => $this->generateUrl('landing_page', ['id' => $listing->getId()]),
  647.         ]);
  648.         $form->handleRequest($request);
  649.         if ($form->isSubmitted() && $form->isValid()) {
  650.             if (!($user $this->FOSUserManager->findUserByEmail($landingPage->getUser()->getEmail()))) {
  651.                 $user $this->userManager
  652.                     ->createUserWithoutPassword($form->get('user')->getData(), $form->get('user'), $request)
  653.                 ;
  654.             }
  655.             if (!$form->get('message')->getData()) {
  656.                 $callRequest = new CallRequest();
  657.                 $callRequest->setListing($listing);
  658.                 $callRequest->setUser($user);
  659.                 $this->callRequestManager->submitCallRequest($callRequest);
  660.             } else {
  661.                 // Compose a message
  662.                 $composer $this->messageComposer;
  663.                 $composer->setSender($user);
  664.                 $composer->compose($form->get('message')->getData(), $listing);
  665.             }
  666.         }
  667.         return [
  668.             'form' => $form->createView(),
  669.             'listing' => $listing,
  670.         ];
  671.     }
  672.     /**
  673.      * Add Listing First Step Action.
  674.      *
  675.      * @Route("/listing/initialize", name="listing_initialize", options={"expose"=true})
  676.      */
  677.     public function initialize(Request $request)
  678.     {
  679.         $user $this->getUser();
  680.         if (false === $this->authorizationChecker->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
  681.             return $this->redirect($this->generateUrl('aqarmap_add_listing'));
  682.         }
  683.         $isPhoneVerified true;
  684.         if ($user instanceof User) {
  685.             $isPhoneVerified $user->isPhoneVerified();
  686.         }
  687.         $hasRentalPackage $this->userPackagesRepository->hasRentalPackage($user);
  688.         $initializeOptions = [
  689.             'action' => $this->generateUrl('listing_initialize'),
  690.             'method' => 'POST',
  691.             'em' => $this->getDoctrine()->getManager(),
  692.             'is_admin' => $this->authorizationChecker->isGranted('ROLE_ADMIN'),
  693.             'has_rental_package' => $hasRentalPackage,
  694.             'parentUser' => $user,
  695.         ];
  696.         $form $this->createForm(ListingInitializeType::class, $listing = new Listing(), $initializeOptions);
  697.         $listingEvent = new ListingEvent($listing);
  698.         $this->dispatcher->dispatch($listingEvent'aqarmap.listing.pre_submitted');
  699.         $form->handleRequest($request);
  700.         if ($form->isSubmitted() && $form->isValid() && ($isPhoneVerified || $user->getHasActiveSubscription())) {
  701.             $listing $this->listingManager->createDraft($listing);
  702.             // Add user phone number to the listing
  703.             if ($listing->getUser()->getPhoneNumber()) {
  704.                 // link user phone with this listing
  705.                 // TODO: Suggest only the main number for now, later on we will suggest the main + last 2 numbers.
  706.                 $this->listingManager->suggestListingPhoneNumbers(
  707.                     [$listing->getUser()->getPhoneNumber()],
  708.                     $listing
  709.                 );
  710.             }
  711.             return $this->redirect($this->generateUrl('listing_edit', [
  712.                 'id' => $listing->getId(),
  713.             ]));
  714.         }
  715.         return $this->render('@AqarmapListing/Listing/initialize.html.twig', [
  716.             'form' => $form->createView(),
  717.             'isPhoneVerified' => $isPhoneVerified,
  718.         ]);
  719.     }
  720.     /**
  721.      * Add Listing V2.
  722.      *
  723.      * @Route("/listing/initialize/{step}", name="add_listing", options={"expose"=true})
  724.      * @Route("/listing/initialize/{id}/{step}", name="edit_listing", options={"expose"=true})
  725.      *
  726.      * @Security("is_granted('IS_AUTHENTICATED_REMEMBERED')")
  727.      *
  728.      * @throws \Doctrine\ORM\NonUniqueResultException
  729.      */
  730.     public function addListing(): Response
  731.     {
  732.         return $this->render('@AqarmapListing/Listing/add.html.twig', [
  733.             'title' => $this->translator->trans('listing.add_your_listing'),
  734.             'featureToggle' => [
  735.                 'accept_adding_phones' => $this->featureToggleManager->isEnabled('web.addlisting.accept_adding_phones'),
  736.                 'google_maps_location' => $this->featureToggleManager->isEnabled('web.addlisting.google_maps_location'),
  737.             ],
  738.         ]);
  739.     }
  740.     /**
  741.      * Add Listing groups.
  742.      *
  743.      * @Route("/listing/add/", name="add_listing_steps", options={"expose"=true})
  744.      * @Route("/listing/{id}/edit/steps", name="edit_listing_steps", options={"expose"=true})
  745.      *
  746.      * @Security("is_granted('IS_AUTHENTICATED_REMEMBERED')")
  747.      *
  748.      * @throws \Doctrine\ORM\NonUniqueResultException
  749.      */
  750.     public function addListingSteps(): Response
  751.     {
  752.         return $this->render('@AqarmapListing/Listing/addSteps.html.twig', [
  753.             'title' => $this->translator->trans('listing.add_your_listing'),
  754.             'featureToggle' => [
  755.                 'accept_adding_phones' => $this->featureToggleManager->isEnabled('web.addlisting.accept_adding_phones'),
  756.                 'google_maps_location' => $this->featureToggleManager->isEnabled('web.addlisting.google_maps_location'),
  757.             ],
  758.         ]);
  759.     }
  760.     /**
  761.      * Listing Post Action
  762.      * This action manage adding & editing listings.
  763.      *
  764.      * @Route("/listing/{id}/edit/", name="listing_edit", requirements={"id" = "\d+"}, options={"expose"=true})
  765.      *
  766.      * @Security(
  767.      *     "(is_granted('IS_AUTHENTICATED_REMEMBERED') and is_granted('ROLE_OWNER', listing)) or is_granted('ROLE_ADMIN')"
  768.      * )
  769.      */
  770.     public function post(Request $requestListing $listing): Response
  771.     {
  772.         $user $this->getUser();
  773.         // if user doesn't have phone or active subscription, redirect to my listings with an error flash message
  774.         if ($user instanceof User && (!$user->isPhoneVerified() && !$user->getHasActiveSubscription())) {
  775.             $this->addFlash('danger'$this->translator->trans('listing.notice.cannot_add_before_verify'));
  776.             return $this->redirect($this->generateUrl('aqarmap_listing_default_mylistings'));
  777.         }
  778.         $form $this->createForm(ListingType::class, $listing, [
  779.             'action' => $this->generateUrl('listing_edit', ['id' => $listing->getId()]),
  780.             'method' => 'POST',
  781.             'listingIsLiveFor5Days' => $this->listingManager->checkListingLiveDays($listing),
  782.             'is_admin' => $this->authorizationChecker->isGranted('ROLE_ADMIN'),
  783.             'user_country' => $this->setting->getSetting('general''country'),
  784.             'user_type' => $listing->getUser() ? $listing->getUser()->getUserType() : null,
  785.             'isMortgageOptionsEnabled' => $this->featureToggleManager->isEnabled('web.mortgage.options'),
  786.             'isListingMarketPropertyTypesEnabled' => $this->featureToggleManager->isEnabled('web.listing.market.property.types'),
  787.         ]);
  788.         $form->handleRequest($request);
  789.         if ($request->isMethod('POST')) {
  790.             if ($form->isSubmitted() && $form->isValid()) {
  791.                 $this->updateWhatsAppPhones($listing->getUser()->getId(), (array) $request->request->get('phoneIds', []), (array) $request->request->get('hasWhatsApp', []));
  792.                 $listing $this->handleListingPhones($listing$request->request->all()['listing']['phones']);
  793.                 $this->handleUserPhones($listing->getUser(), $request->request->all()['listing']['phones']);
  794.                 $this->listingManager->saveListing($listing);
  795.                 if ($this->featureToggleManager->isEnabled('web.add.listing.translations')) {
  796.                     if ('en' == $request->getLocale()) {
  797.                         $criteria = [
  798.                             'reversedLocale' => 'ar',
  799.                             'title-ar' => $request->request->get('title-ar'),
  800.                             'description-ar' => $request->request->get('description-ar'),
  801.                         ];
  802.                     } else {
  803.                         $criteria = [
  804.                             'reversedLocale' => 'en',
  805.                             'title-en' => $request->request->get('title-en'),
  806.                             'description-en' => $request->request->get('description-en'),
  807.                         ];
  808.                     }
  809.                     $this->listingManager->updateListingTranslationsFields($listing$criteria);
  810.                 } else {
  811.                     $this->listingManager->updateListingTranslations($listing);
  812.                 }
  813.                 if ($this->featureToggleManager->isEnabled('web.mortgage.options')) {
  814.                     $propertyRegistrationStatus $form->has('propertyRegistrationStatus') ? $form->get('propertyRegistrationStatus')->getData() : null;
  815.                     if (\in_array($propertyRegistrationStatusPropertyRegistrationStatusOption::getValidMorgageOptions())) {
  816.                         $this->mortgageService->addEligibleMortgageTypes($listing);
  817.                     } else {
  818.                         $this->listingManager->setELigibleMortgageToNull($listing);
  819.                     }
  820.                     $listing $this->mortgageService->addMortgageApproval($listing$form);
  821.                 }
  822.                 $listingEvent = new ListingEvent($listing);
  823.                 $this->dispatcher->dispatch($listingEvent'aqarmap.listing.submitted');
  824.                 if (ListingSource::SCRAPPING == $listing->getSource()
  825.                     || ListingSource::LITE == $listing->getSource()
  826.                 ) {
  827.                     return $this->redirect($this->generateUrl('listing_view', ['id' => $listing->getId()]));
  828.                 }
  829.                 return $this
  830.                     ->redirect(
  831.                         $this->generateUrl(
  832.                             'listing_upload',
  833.                             ['id' => $listing->getId(), '_locale' => $request->get('_locale')]
  834.                         )
  835.                     )
  836.                 ;
  837.             }
  838.             $this->addFlash('danger'$this->translator->trans('static.problem_error_message'));
  839.         }
  840.         $translatedLocale 'en' == $request->getLocale() ? 'ar' 'en';
  841.         return $this->render('@AqarmapListing/Listing/post.html.twig', [
  842.             'form' => $form->createView(),
  843.             'listing' => $listing,
  844.             'title_translation' => $this->listingTitleTranslations($listing$translatedLocale),
  845.             'description_translation' => $this->listingDescriptionTranslations($listing$translatedLocale),
  846.             'brokerChoices' => UserTypes::getBrokerChoices(),
  847.         ]);
  848.     }
  849.     /**
  850.      * @return array|mixed
  851.      */
  852.     private function listingTitleTranslations(Listing $listingstring $locale)
  853.     {
  854.         $this->translatableListener->setTranslatableLocale($locale);
  855.         $listing->setTranslatableLocale($locale);
  856.         $this->entityManager->refresh($listing);
  857.         return $listing->getTitle() ?? $this->listingManager->listingTitleTranslations($listing$locale);
  858.     }
  859.     private function listingDescriptionTranslations(Listing $listingstring $locale)
  860.     {
  861.         $this->translatableListener->setTranslatableLocale($locale);
  862.         $listing->setTranslatableLocale($locale);
  863.         $this->entityManager->refresh($listing);
  864.         return $listing->getDescription() ?? $this->listingManager->listingTitleTranslations($listing$locale);
  865.     }
  866.     private function handleListingPhones(Listing $listing, array $phones): Listing
  867.     {
  868.         $listing->clearPhones();
  869.         foreach ($phones as $phone) {
  870.             $phoneNumber $phone['number'];
  871.             $countryCode $phone['countryCode'];
  872.             $phone = new Phone($countryCode.$phoneNumber$countryCode);
  873.             $listing->addPhone(new ListingPhone($phoneNumber$listing$countryCode$phone));
  874.         }
  875.         return $listing;
  876.     }
  877.     private function handleUserPhones(User $user, array $phones): void
  878.     {
  879.         foreach ($phones as $phone) {
  880.             $originalPhoneNumber $phone['number'];
  881.             $countryCode $phone['countryCode'];
  882.             $phoneNumber $this->phoneManager->trimZero($originalPhoneNumber$countryCode);
  883.             $this->phoneManager->addNewUserPhone($phoneNumber$countryCode$usertruefalsenull$originalPhoneNumber);
  884.         }
  885.     }
  886.     /**
  887.      * Listing Post Action
  888.      * This action manage adding & editing listings.
  889.      *
  890.      * @Route("/listing/{id}/preview/", name="listing_preview", requirements={"id" = "\d+"}, options={"expose"=true})
  891.      *
  892.      * @Security(
  893.      *     "(is_granted('IS_AUTHENTICATED_REMEMBERED') and is_granted('ROLE_OWNER', listing)) or is_granted('ROLE_ADMIN')"
  894.      * )
  895.      *
  896.      * @return array|RedirectResponse
  897.      */
  898.     public function preview(Listing $listing): Response
  899.     {
  900.         return $this->render('@AqarmapListing/Listing/preview.html.twig', [
  901.             'listing' => $listing,
  902.         ]);
  903.     }
  904.     /**
  905.      * Listing Post Action
  906.      * This action manage adding & editing listings.
  907.      *
  908.      * @Route("/listing/lite", name="listing_lite_add",  options={"expose"=true})
  909.      */
  910.     public function postLite(Request $request)
  911.     {
  912.         /** @var $em \Doctrine\ORM\EntityManager */
  913.         $em $this->getDoctrine()->getManager();
  914.         $form $this->createForm(
  915.             LiteListingType::class,
  916.             null,
  917.             ['em' => $em,
  918.                 'action' => $this->generateUrl('listing_lite_add'),
  919.                 'method' => 'post', ]
  920.         );
  921.         if ($request->isMethod('POST')) {
  922.             $form->handleRequest($request);
  923.             if ($form->isSubmitted() && $form->isValid()) {
  924.                 $listing $form->getData();
  925.                 $listing->setSellerRole(ListingSellerRoles::OWNER);
  926.                 $this->listingManager->saveListing($listing);
  927.                 // add listing phone to new phones table ;
  928.                 $this->phoneManager->addListingPhonesList($listing->getPhones(), ''$listing);
  929.                 $this->listingManager->addLiteListingTitleAndDescriptionTranslation($listing);
  930.                 $listingEvent = new ListingEvent($listing);
  931.                 $this->dispatcher->dispatch($listingEvent'aqarmap.listing.submitted');
  932.                 $this->addFlash(
  933.                     'success',
  934.                     $this->translator->trans('add_listing_page.success_messages.padding_review')
  935.                 );
  936.                 if ($this->featureToggleManager->isEnabled('web.delayed.review.eid.info.message')) {
  937.                     $this->addFlash(
  938.                         'info',
  939.                         $this->translator->trans('add_listing_page.info_messages.eid_delayed_review')
  940.                     );
  941.                 }
  942.                 return $this->redirect($this->generateUrl('homepage'));
  943.             }
  944.             $this->addFlash('danger'$this->translator->trans('static.problem_error_message'));
  945.         }
  946.         return $this->render('@AqarmapListing/Listing/postLite.html.twig', [
  947.             'form' => $form->createView(),
  948.         ]);
  949.     }
  950.     /**
  951.      * Add Listing First Step Action.
  952.      *
  953.      * @Route("/listing/{id}/edit/photos", name="listing_upload", requirements={"id" = "\d+"}, options={"expose"=true})
  954.      *
  955.      * @Security("is_granted('ROLE_ADMIN') or is_granted('ROLE_OWNER', listing)")
  956.      */
  957.     public function upload(Request $requestListing $listing)
  958.     {
  959.         $form $this->createForm(PhotoType::class, null, [
  960.             'method' => 'POST',
  961.         ]);
  962.         $form->handleRequest($request);
  963.         $listingRules $this->listingRuleMatcher->match($listing);
  964.         if ($form->isSubmitted() && $form->isValid() && $request->isMethod('POST')) {
  965.             $listingPhotos = [];
  966.             try {
  967.                 $listingPhotos $this->listingManager->addListingPhotos($listing$form->get('file')->getData());
  968.                 $listingEvent = new ListingEvent($listing);
  969.                 $this->dispatcher->dispatch($listingEvent'aqarmap.listing.submitted');
  970.                 $this->listingManager->saveListing($listing);
  971.                 // If not Ajax request
  972.                 if (!$request->isXmlHttpRequest()) {
  973.                     $this->logger->error('Not AJAX');
  974.                     return $this->redirect($request->headers->get('referer') ?: $this->generateUrl('homepage'));
  975.                 }
  976.             } catch (\Exception $exception) {
  977.                 $this->logger->error($exception->getMessage());
  978.             }
  979.             return View::create(['files' => $listingPhotos], Response::HTTP_OK);
  980.         }
  981.         return $this->render('@AqarmapListing/Listing/upload.html.twig', [
  982.             'requiredPhotosCount' => $listingRules['required_photos'] ?? 0,
  983.             'listing' => $listing,
  984.             'form' => $form->createView(),
  985.         ]);
  986.     }
  987.     /**
  988.      * Should be called after photos are uploaded.
  989.      *
  990.      * @Route("/listing/{id}/finish", requirements={"id" = "\d+"}, name="listing_finish")
  991.      *
  992.      * @return RedirectResponse|Response
  993.      */
  994.     public function finish(Listing $listingUserPackagesService $userPackagesService)
  995.     {
  996.         $listingEvent = new ListingEvent($listing);
  997.         if (!$userPackagesService->canListInLocation($listing)) {
  998.             $this->addFlash('danger'$this->translator->trans('credit.can_not_list_in_location'));
  999.             return $this->redirect($this->generateUrl('listing_upload', [
  1000.                 'id' => $listing->getId(),
  1001.             ]), Response::HTTP_FOUND);
  1002.         }
  1003.         $this->dispatcher->dispatch($listingEvent'aqarmap.listing.submitted');
  1004.         $response $listingEvent->getResponse();
  1005.         if (null === $response) {
  1006.             if (ListingStatus::PENDING === $listing->getStatus()) {
  1007.                 $this->addFlash(
  1008.                     'success',
  1009.                     $this->translator->trans('add_listing_page.success_messages.padding_review')
  1010.                 );
  1011.                 if ($this->featureToggleManager->isEnabled('web.delayed.review.eid.info.message')) {
  1012.                     $this->addFlash(
  1013.                         'info',
  1014.                         $this->translator->trans('add_listing_page.info_messages.eid_delayed_review')
  1015.                     );
  1016.                 }
  1017.             }
  1018.             $response = new RedirectResponse(
  1019.                 $this->generateUrl(
  1020.                     'listing_slug',
  1021.                     ['id' => $listing->getId(), 'slug' => $listing->getSlug()]
  1022.                 )
  1023.             );
  1024.         }
  1025.         return $response;
  1026.     }
  1027.     /**
  1028.      * SWAT special add listing feature page.
  1029.      *
  1030.      * @Route("/listing/{id}/feature", requirements={"id" = "\d+"}, name="special_add_listing_feature")
  1031.      *
  1032.      * @Security("is_granted('ROLE_OWNER', listing)")
  1033.      */
  1034.     public function specialAddListingFeature(Listing $listing): RedirectResponse
  1035.     {
  1036.         return $this->redirectToRoute('listing_finish', ['id' => $listing->getId()]);
  1037.     }
  1038.     /**
  1039.      * @Route("/listing/{id}/make_it_featured",
  1040.      * requirements={"id" = "\d+"}, name="listing_confirm_featured_credit", methods={"GET"})
  1041.      *
  1042.      * @Security("is_granted('ROLE_OWNER', listing)")
  1043.      *
  1044.      * @return RedirectResponse|Response
  1045.      */
  1046.     public function confirmFeaturedPublishing(Listing $listing)
  1047.     {
  1048.         if (!\in_array($listing->getStatus(), [ListingStatus::PENDINGListingStatus::LIVE])) {
  1049.             $this->addFlash(
  1050.                 'danger',
  1051.                 $this->translator->trans('listing.featured_failure_statement.not_live_or_pending')
  1052.             );
  1053.             return $this->redirect($this->generateUrl('aqarmap_listing_default_mylistings'));
  1054.         }
  1055.         if (UserTypes::INDIVIDUAL == $listing->getUser()->getUserType()) {
  1056.             $listingRules $this->listingFeatureService->getFeaturedListingRules($listing, ['sold_by_owner''sold_by_owner_sponsored']);
  1057.         } else {
  1058.             $listingRules $this->listingFeatureService->getFeaturedListingRules($listing, ['featured''premium''sponsored''spotlight']);
  1059.         }
  1060.         /** @var User $user */
  1061.         $user $this->getUser();
  1062.         return $this->render(
  1063.             '@AqarmapListing/Listing/featuredListingCheckout.html.twig',
  1064.             [
  1065.                 'listingRules' => $listingRules,
  1066.                 'listingId' => $listing->getId(),
  1067.                 'haveFeesToFeature' => $this->listingManager->userHasFeesToFeature($user$listing),
  1068.             ]
  1069.         );
  1070.     }
  1071.     /**
  1072.      * @Route("/listing/{id}/make_it_featured",  options={"expose"=true} ,requirements={"id" = "\d+"},
  1073.      * name="listing_confirm_publish_featured_credit_post", methods={"POST"})
  1074.      *
  1075.      * @Security("is_granted('ROLE_OWNER', listing)")
  1076.      */
  1077.     public function prepareFeaturedListingPayment(Listing $listingRequest $request): RedirectResponse
  1078.     {
  1079.         $listingRules $this->listingManager->getListingRules($listing);
  1080.         $fees $request->query->get('fees'$listingRules['featured_fees']);
  1081.         $duration $request->query->get('duration'$listingRules['featured_duration']);
  1082.         $listingFeaturedType $request->query->get('listingFeaturedType'ListingFeaturedTypes::FEATURED);
  1083.         $listingFeature $request->query->get('listingFeature'ListingFeatures::FEATURED);
  1084.         $listingStatus $listing->getStatus();
  1085.         /** @var User $user */
  1086.         $user $this->getUser();
  1087.         if (!$this->listingManager->isAffordable($user$fees)) {
  1088.             $this->addFlash('danger'$this->translator->trans('credit.not_enough_featuring_credit', [
  1089.                 'link' => $this->generateUrl('aqarmap_buy_credit', ['listing_id' => $listing->getId()]),
  1090.             ]));
  1091.             return $this->redirect($this->generateUrl('listing_confirm_featured_credit', [
  1092.                 'id' => $listing->getId(),
  1093.             ]), Response::HTTP_FOUND);
  1094.         }
  1095.         $featuredText $this->translator->trans(ListingFeaturedTypes::getFeaturedText($listingFeaturedType));
  1096.         $rules = [
  1097.             'featuredFees' => $fees,
  1098.             'featuredDuration' => $duration,
  1099.             'listingFeaturedType' => $listingFeaturedType,
  1100.             'listingFeature' => $listingFeature,
  1101.             'featuredText' => $featuredText,
  1102.         ];
  1103.         if ($this->listingManager->requiresFeaturingReview($listingFeaturedType)) {
  1104.             try {
  1105.                 $this->listingManager->makeItFeatured($listing$rules);
  1106.                 if (ListingStatus::LIVE == $listingStatus) {
  1107.                     $this->addFlash(
  1108.                         'success',
  1109.                         $this->translator->trans('add_listing_page.success_messages.pending_featuring', [':featured_type:' => $featuredText])
  1110.                     );
  1111.                 } else {
  1112.                     $this->addFlash(
  1113.                         'success',
  1114.                         $this->translator->trans('add_listing_page.success_messages.padding_review')
  1115.                     );
  1116.                     if ($this->featureToggleManager->isEnabled('web.delayed.review.eid.info.message')) {
  1117.                         $this->addFlash(
  1118.                             'info',
  1119.                             $this->translator->trans('add_listing_page.info_messages.eid_delayed_review')
  1120.                         );
  1121.                     }
  1122.                 }
  1123.             } catch (\Exception $exception) {
  1124.                 $this->addFlash('danger'$this->translator->trans($exception->getMessage()));
  1125.             }
  1126.             if (ListingStatus::LIVE == $listingStatus) {
  1127.                 return $this->redirect($this->generateUrl('aqarmap_listing_default_mylistings'));
  1128.             }
  1129.             return $this->redirect($this->generateUrl('listing_finish', [
  1130.                 'id' => $listing->getId(),
  1131.             ]));
  1132.         }
  1133.         try {
  1134.             $this->listingManager->makeItFeatured($listing$rules);
  1135.             if (ListingStatus::LIVE == $listing->getStatus()) {
  1136.                 $this->addFlash(
  1137.                     'success',
  1138.                     $this->translator->trans(
  1139.                         'add_listing_page.success_messages.featured',
  1140.                         [':listing_title:' => $listing->getTitle(), ':featured_type:' => $featuredText]
  1141.                     )
  1142.                 );
  1143.                 $redirectTo $user->hasValidAccessToLiveApp() ?
  1144.                     $this->redirect(sprintf('%s/%s'$this->getParameter('user_dashboard_url'), 'listings')) :
  1145.                     $this->redirectToRoute('aqarmap_listing_default_mylistings');
  1146.                 return $redirectTo;
  1147.             }
  1148.             $this->addFlash(
  1149.                 'success',
  1150.                 $this->translator->trans('add_listing_page.success_messages.padding_review')
  1151.             );
  1152.             if ($this->featureToggleManager->isEnabled('web.delayed.review.eid.info.message')) {
  1153.                 $this->addFlash(
  1154.                     'info',
  1155.                     $this->translator->trans('add_listing_page.info_messages.eid_delayed_review')
  1156.                 );
  1157.             }
  1158.             return $this->redirectToRoute('listing_finish', [
  1159.                 'id' => $listing->getId(),
  1160.             ]);
  1161.         } catch (\Exception $e) {
  1162.             $buyCreditLink $this->generateUrl('page_view', ['slug' => 'buy-credit'], true);
  1163.             if ($this->setting->getSetting('features''payments')) {
  1164.                 $buyCreditLink $this->generateUrl('aqarmap_buy_credit');
  1165.             }
  1166.             $this->addFlash('danger'$this->translator->trans(
  1167.                 $e->getMessage(),
  1168.                 ['%link%' => $buyCreditLink],
  1169.                 'exceptions'
  1170.             ));
  1171.         }
  1172.         return $this->redirect($this->generateUrl('listing_confirm_featured_credit', [
  1173.             'id' => $listing->getId(),
  1174.         ]), Response::HTTP_FOUND);
  1175.     }
  1176.     /**
  1177.      * @Route(
  1178.      *     "/listing/{id}/payment_confirmation",
  1179.      *     requirements={"id" = "\d+"}, name="listing_confirm_publish_credit", methods={"GET"}
  1180.      * )
  1181.      *
  1182.      * @Security("is_granted('ROLE_ADMIN') or is_granted('ROLE_OWNER', listing)")
  1183.      *
  1184.      * @return array|RedirectResponse
  1185.      */
  1186.     public function confirmPublishing(Listing $listingUserPackagesService $userPackagesService): Response
  1187.     {
  1188.         $listingRule $this->listingRuleMatcher->match($listing);
  1189.         /** @var $em \Doctrine\ORM\EntityManager */
  1190.         $em $this->getDoctrine()->getManager();
  1191.         // User Balance
  1192.         $userDetails $listing->getUser();
  1193.         $available_balance $this->userPackagesRepository->getTotalCreditsByUser($userDetails);
  1194.         $userId $userDetails->getId();
  1195.         $em->getRepository(User::class)->findOneBy(['id' => $userId]);
  1196.         $listingManger $this->listingManager;
  1197.         if (!$userPackagesService->canListInLocation($listing)) {
  1198.             $this->addFlash('danger'$this->translator->trans('credit.can_not_list_in_location'));
  1199.             return $this->redirect($this->generateUrl('listing_upload', [
  1200.                 'id' => $listing->getId(),
  1201.             ]), Response::HTTP_FOUND);
  1202.         }
  1203.         $userServiceRepository $em->getRepository(UserServices::class);
  1204.         if ($this->userServicesManager->hasActiveService(UserServicesType::UNLIMITED_LISTINGS$userId)
  1205.             && ListingCategories::UNLIMITED != $listing->getCategory()
  1206.             && ListingStatus::DRAFT != $listing->getStatus()
  1207.         ) {
  1208.             if ($userServiceRepository
  1209.                     ->passUnlimitedListing($listing$this->creditManager$listingManger) || $listing->getPublicationCredit()
  1210.             ) {
  1211.                 if ($this->listingFeatureService->isFeaturedOffersAvailable($listing)) {
  1212.                     return $this->redirect($this->generateUrl('listing_confirm_featured_credit', [
  1213.                         'id' => $listing->getId(),
  1214.                     ]));
  1215.                 }
  1216.                 return $this->redirect($this->generateUrl('listing_finish', [
  1217.                     'id' => $listing->getId(),
  1218.                 ]));
  1219.             }
  1220.         }
  1221.         $isUserInSpecialAddListingGroup $this->specialAddListingService->hasSpecialAddListingGroup($userDetails);
  1222.         $userUnlimitedListings $this->userServicesManager->hasActiveService(UserServicesType::UNLIMITED_LISTINGS$userId);
  1223.         $userHasNoFreeListingService = !$userUnlimitedListings;
  1224.         $userHasNoFreeListingQuote = ($userUnlimitedListings && == $userUnlimitedListings['remainingQuota']);
  1225.         if ($isUserInSpecialAddListingGroup) {
  1226.             if ($userHasNoFreeListingService || $userHasNoFreeListingQuote) {
  1227.                 return $this->redirectToRoute('special_add_listing_feature', ['id' => $listing->getId()]);
  1228.             }
  1229.         }
  1230.         $form $this->ConfirmPaymentForm($listing);
  1231.         return $this->render(
  1232.             '@AqarmapListing/Listing/confirmPublishing.html.twig',
  1233.             [
  1234.                 'listing' => $listing,
  1235.                 'fees' => $listingRule['publication_fees'],
  1236.                 'duration' => $listingRule['duration'],
  1237.                 'available_balance' => $available_balance,
  1238.                 'form' => $form->createView(),
  1239.             ]
  1240.         );
  1241.     }
  1242.     /**
  1243.      * @Route(
  1244.      *     "/listing/{id}/list_rejections",
  1245.      *     requirements={"id" = "\d+"},
  1246.      *     name="listing_list_rejections", methods={"GET"}
  1247.      * )
  1248.      *
  1249.      * @Security("is_granted('ROLE_OWNER', listing)")
  1250.      *
  1251.      * @return array
  1252.      */
  1253.     public function listRejections(Listing $listingRequest $request): Response
  1254.     {
  1255.         if ($request->get('notification')) {
  1256.             try {
  1257.                 $this->databaseNotification->markOneAsRead($request->get('notification'));
  1258.             } catch (\Exception $exception) {
  1259.                 $this->logger->log(LogLevel::ERROR$exception->getMessage());
  1260.             }
  1261.         }
  1262.         return $this->render(
  1263.             '@AqarmapListing/Listing/confirmPublishing.html.twig',
  1264.             [
  1265.                 'listing' => $listing,
  1266.             ]
  1267.         );
  1268.     }
  1269.     /**
  1270.      * @Route(
  1271.      *     "/listing/{id}/payment_confirmation",
  1272.      *     requirements={"id" = "\d+"}, name="listing_confirm_publish_credit_post", methods={"POST"}
  1273.      * )
  1274.      *
  1275.      * @Security("is_granted('ROLE_ADMIN') or is_granted('ROLE_OWNER', listing)")
  1276.      *
  1277.      * @return array|RedirectResponse
  1278.      */
  1279.     public function prepareListingPayment(Listing $listingRequest $requestUserPackagesService $userPackagesService): RedirectResponse
  1280.     {
  1281.         $listingRule $this->listingRuleMatcher->match($listing);
  1282.         /** @var EntityManager $em */
  1283.         $em $this->getDoctrine()->getManager();
  1284.         // User Balance
  1285.         $available_balance $this->userPackagesRepository->getTotalCreditsByUser($listing->getUser());
  1286.         $userId $listing->getUser()->getId();
  1287.         $listingManger $this->listingManager;
  1288.         if (!$userPackagesService->canListInLocation($listing)) {
  1289.             $this->addFlash('danger'$this->translator->trans('credit.can_not_list_in_location'));
  1290.             return $this->redirect($this->generateUrl('listing_upload', [
  1291.                 'id' => $listing->getId(),
  1292.             ]), Response::HTTP_FOUND);
  1293.         }
  1294.         $userServiceRepository $em->getRepository(UserServices::class);
  1295.         if ($this->userServicesManager->hasActiveService(UserServicesType::UNLIMITED_LISTINGS$userId)) {
  1296.             if ($userServiceRepository->passUnlimitedListing($listing$this->creditManager$listingManger)
  1297.             ) {
  1298.                 if (!$this->listingFeatureService->isFeaturedOffersAvailable($listing)) {
  1299.                     return $this->redirect($this->generateUrl('listing_finish', [
  1300.                         'id' => $listing->getId(),
  1301.                     ]));
  1302.                 }
  1303.                 return $this->redirect($this->generateUrl('listing_confirm_featured_credit', [
  1304.                     'id' => $listing->getId(),
  1305.                 ]));
  1306.             }
  1307.         }
  1308.         $form $this->ConfirmPaymentForm($listing);
  1309.         $form->handleRequest($request);
  1310.         if ($form->isSubmitted() && $form->isValid()) {
  1311.             // Payment Confirmed?
  1312.             // If user cancel payment redirect him to his listing,
  1313.             if (!$form->get('confirm')->isClicked()) {
  1314.                 return $this->redirect($this->generateUrl('listing_view', [
  1315.                     'id' => $listing->getId(),
  1316.                 ]), Response::HTTP_FOUND);
  1317.             }
  1318.             // If user credit expired, complain.
  1319.             $enforceCredit $this->setting->getSetting('features''enforce_credits_expiration');
  1320.             /** @var User $user */
  1321.             $user $this->getUser();
  1322.             if ($enforceCredit && === $user->getAbsoluteCreditExpiryDays()) {
  1323.                 $this->addFlash('danger'$this->translator->trans('credit.credit_can_not_use', [
  1324.                     'link' => $this->generateUrl('aqarmap_buy_credit', ['listing_id' => $listing->getId()]),
  1325.                 ]));
  1326.                 return $this->redirect($this->generateUrl('listing_confirm_publish_credit', [
  1327.                     'id' => $listing->getId(),
  1328.                 ]), Response::HTTP_FOUND);
  1329.             }
  1330.             // User already paid
  1331.             if ($listing->getPublicationCredit()) {
  1332.                 $this->addFlash('info'$this->translator->trans('credit.already_paid'));
  1333.             } else {
  1334.                 // User don't have enough credits
  1335.                 if ($listingRule['publication_fees'] > $available_balance) {
  1336.                     $this->addFlash('danger'$this->translator->trans('credit.not_enough_credits'));
  1337.                 } else {
  1338.                     // Subtract publication fees
  1339.                     $credits $this->creditManager->deduction(
  1340.                         $listing->getUser(),
  1341.                         $listingRule['publication_fees'],
  1342.                         'Listing Fees'
  1343.                     );
  1344.                     foreach ($credits as $credit) {
  1345.                         if ($credit instanceof Credit) {
  1346.                             $credit->setStatus(CreditStatus::SUCCESS);
  1347.                             $this->listingManager->addFeature($listingListingFeatures::PAIDnull$credit);
  1348.                             if (!$this->listingFeatureService->isFeaturedOffersAvailable($listing)) {
  1349.                                 return $this->redirect($this->generateUrl('listing_finish', [
  1350.                                     'id' => $listing->getId(),
  1351.                                 ]));
  1352.                             }
  1353.                         }
  1354.                     }
  1355.                     return $this->redirect($this->generateUrl('listing_confirm_featured_credit', [
  1356.                         'id' => $listing->getId(),
  1357.                         'ref' => 'add_listing',
  1358.                     ]));
  1359.                 }
  1360.             }
  1361.         }
  1362.         $this->addFlash('danger''Unexpected error occurred.');
  1363.         return $this->redirect($this->generateUrl('listing_confirm_publish_credit', [
  1364.             'id' => $listing->getId(),
  1365.         ]));
  1366.     }
  1367.     private function ConfirmPaymentForm(Listing $listing)
  1368.     {
  1369.         return $this->createForm(ConfirmFormType::class, null, [
  1370.             'method' => 'POST',
  1371.             'action' => $this->generateUrl('listing_confirm_publish_credit_post', ['id' => $listing->getId()]),
  1372.         ]);
  1373.     }
  1374.     /**
  1375.      * @return \Symfony\Component\Form\Form
  1376.      */
  1377.     private function confirmFeaturedPaymentForm(Listing $listing)
  1378.     {
  1379.         return $this->createForm(ConfirmFeaturedFormType::class, null, [
  1380.             'method' => 'POST',
  1381.             'action' => $this
  1382.                 ->generateUrl(
  1383.                     'listing_confirm_publish_featured_credit_post',
  1384.                     ['id' => $listing->getId()]
  1385.                 ),
  1386.         ]);
  1387.     }
  1388.     /**
  1389.      * Delete Listing entity.
  1390.      *
  1391.      * @Route("/listing/{id}/delete", requirements={"id" = "\d+"}, name="listing_delete", options={"expose"=true})
  1392.      *
  1393.      * @Security("is_granted('ROLE_ADMIN') or is_granted('ROLE_OWNER', listing)")
  1394.      */
  1395.     public function delete(Listing $listingRequest $request): RedirectResponse
  1396.     {
  1397.         if (\in_array('ROLE_PREVENT_DELETE_LISTING'$this->getUser()->getRoles())) {
  1398.             throw new AccessDeniedHttpException("Forbidden, user don't have this permession.");
  1399.         }
  1400.         if (ListingStatus::EXPIRED == $listing->getStatus()) {
  1401.             throw $this->createNotFoundException('Listing is expired.');
  1402.         }
  1403.         $this->listingManager->remove($listingListingStatus::USER_DELETED);
  1404.         $this->addFlash(
  1405.             'success',
  1406.             $this->translator->trans('add_listing_page.success_messages.deleted')
  1407.         );
  1408.         return $this->redirect($request->headers->get('referer') ?: $this->generateUrl('homepage'));
  1409.     }
  1410.     /**
  1411.      * unDelete Listing entity.
  1412.      *
  1413.      * @Route("/listing/{id}/undelete", requirements={"id" = "\d+"}, name="listing_undelete")
  1414.      *
  1415.      * @Security("is_granted('ROLE_ADMIN') or is_granted('ROLE_OWNER', listing)")
  1416.      *
  1417.      * @return RedirectResponse|Response|null
  1418.      */
  1419.     public function undelete(Listing $listing)
  1420.     {
  1421.         if (ListingStatus::USER_DELETED != $listing->getStatus()) {
  1422.             throw $this->createNotFoundException('Unable to find this listing.');
  1423.         }
  1424.         $this->getDoctrine()->getManager();
  1425.         $this->listingManager->changeStatus($listingListingStatus::PENDING);
  1426.         $listingEvent = new ListingEvent($listing);
  1427.         $this->dispatcher->dispatch($listingEvent'aqarmap.listing.submitted');
  1428.         $response $listingEvent->getResponse();
  1429.         if (null === $response) {
  1430.             if (ListingStatus::PENDING === $listing->getStatus()) {
  1431.                 $this->addFlash(
  1432.                     'success',
  1433.                     $this->translator->trans('add_listing_page.success_messages.padding_review')
  1434.                 );
  1435.                 if ($this->featureToggleManager->isEnabled('web.delayed.review.eid.info.message')) {
  1436.                     $this->addFlash(
  1437.                         'info',
  1438.                         $this->translator->trans('add_listing_page.info_messages.eid_delayed_review')
  1439.                     );
  1440.                 }
  1441.             }
  1442.             $response = new RedirectResponse(
  1443.                 $this->generateUrl(
  1444.                     'listing_slug',
  1445.                     ['id' => $listing->getId(), 'slug' => $listing->getSlug()]
  1446.                 )
  1447.             );
  1448.         }
  1449.         return $response;
  1450.     }
  1451.     /**
  1452.      * Creates "Request a Call" button.
  1453.      *
  1454.      * @return \Symfony\Component\Form\Form
  1455.      */
  1456.     public function callRequestForm(Listing $listing)
  1457.     {
  1458.         return $this->createForm(CallRequestFormType::class, null, [
  1459.             'method' => 'POST',
  1460.             'action' => $this->generateUrl('aqarmap_listing_call_request', ['id' => $listing->getId()]),
  1461.         ]);
  1462.     }
  1463.     /**
  1464.      * Creates contact seller form.
  1465.      *
  1466.      * @param Listing $listing The listing entity
  1467.      *
  1468.      * @return \Symfony\Component\Form\Form The form
  1469.      */
  1470.     public function contactSellerForm(Listing $listing)
  1471.     {
  1472.         return $this->createForm(ContactSellerFormType::class, null, [
  1473.             'method' => 'POST',
  1474.             'action' => $this->generateUrl('aqarmap_listing_contact_seller', ['id' => $listing->getId()]),
  1475.         ]);
  1476.     }
  1477.     /**
  1478.      * Creates contact seller form.
  1479.      *
  1480.      * @param Listing $listing The listing entity
  1481.      *
  1482.      * @return \Symfony\Component\Form\Form The form
  1483.      */
  1484.     public function contactSellerWideForm(Listing $listing)
  1485.     {
  1486.         return $this->createForm(ContactSellerWideFormType::class, null, [
  1487.             'method' => 'POST',
  1488.             'action' => $this->generateUrl('aqarmap_listing_contact_seller', ['id' => $listing->getId()]),
  1489.         ]);
  1490.     }
  1491.     /**
  1492.      * Creates quick registration form.
  1493.      *
  1494.      * @return \Symfony\Component\Form\Form The form
  1495.      */
  1496.     public function quickRegistrationForm()
  1497.     {
  1498.         return $this->createForm(QuickRegistrationFormType::class, null, [
  1499.             'method' => 'POST',
  1500.             'action' => $this->generateUrl('aqarmap_user_quick_registration'),
  1501.         ]);
  1502.     }
  1503.     /**
  1504.      * Contact Seller Action.
  1505.      *
  1506.      * @Route("/listing/{id}/contact_seller", requirements={"id" = "\d+"}, name="aqarmap_listing_contact_seller", options={"expose"=true}, defaults={"_format": "json"}, methods={"POST"})
  1507.      *
  1508.      * @Rest\View()
  1509.      *
  1510.      * @return array|\Symfony\Component\Form\Form
  1511.      */
  1512.     public function contactSeller(Listing $listingRequest $request)
  1513.     {
  1514.         $form $this->contactSellerForm($listing);
  1515.         if ($request->request->has('contact_seller_wide')) {
  1516.             $form $this->contactSellerWideForm($listing);
  1517.         }
  1518.         $lead $request->get('lead');
  1519.         $originalPhoneNumber $lead['phone'];
  1520.         $phoneNumber $lead $this->phoneManager->trimZero($lead['phone'], $request->get('countryCode')) : null;
  1521.         $message json_decode((string) $request->get('message'), true);
  1522.         $hasEmail = !$request->get('isAutoGeneratedEmail'0);
  1523.         $user $this->getUser();
  1524.         $form->handleRequest($request);
  1525.         if ($lead) {
  1526.             $form $this->createForm(QuickLeadType::class, null, [
  1527.                 'method' => 'POST',
  1528.                 'csrf_protection' => false,
  1529.             ]);
  1530.             /** @var User $user */
  1531.             $user $this->FOSUserManager->findUserByEmail($lead['email']);
  1532.             if (!$user && !$hasEmail) {
  1533.                 $user $this->userManager->findLatestByPhone($phoneNumber$request->get('countryCode'));
  1534.             }
  1535.             if (!$user && $hasEmail) {
  1536.                 $user $this->userManager->findAndReplaceUserAndEmail($phoneNumber$lead['email'], $request->get('countryCode'));
  1537.             }
  1538.             $phone $this->phoneManager->findOrSavePhoneNumber($phoneNumber$request->get('countryCode'), null$originalPhoneNumber);
  1539.             if (!$user) {
  1540.                 $user $this->FOSUserManager->createUser();
  1541.                 $user
  1542.                     ->setFullName($lead['name'])
  1543.                     ->setPhoneNumber($lead['phone'])
  1544.                     ->setTempOriginalPhoneNumber($originalPhoneNumber)
  1545.                     ->setEmail($lead['email'])
  1546.                     ->setHasEmail($hasEmail)
  1547.                     ->setIsQucikRegistered(true)
  1548.                 ;
  1549.                 $this->userManager->quickRegister($user$form$requesttruefalsefalse);
  1550.                 $registerMessage $this->translator->trans('popup_form.success');
  1551.             }
  1552.             $this->phoneManager->addNewUserPhone($phoneNumber$request->get('countryCode'), $usertruefalsenull$originalPhoneNumber);
  1553.         }
  1554.         if ($request->isMethod('POST')) {
  1555.             // Get current logged in user
  1556.             $user ??= $this->getUser();
  1557.             $composer $this->messageComposer;
  1558.             $composer
  1559.                 ->setSender($user)
  1560.                 ->compose($message['content'], $listingnull$message['type'] ?? LeadTypes::SEND_MESSAGE)
  1561.             ;
  1562.             $this->addFlash(
  1563.                 'success',
  1564.                 $this->translator->trans('add_listing_page.success_messages.message_sent')
  1565.             );
  1566.             return [
  1567.                 'status' => 'ok',
  1568.                 'message' => $this->translator->trans('listing.success_message_seller'),
  1569.             ];
  1570.         }
  1571.         return $form;
  1572.     }
  1573.     /**
  1574.      * Contact Seller Action.
  1575.      *
  1576.      * @Route("/listing/{id}/call_request", requirements={"id" = "\d+", "_format" = "json"},
  1577.      *      name="aqarmap_listing_call_request",
  1578.      *      options={"expose"=true},
  1579.      *      defaults={"_format": "json"},
  1580.      *      methods={"POST"}
  1581.      * )
  1582.      *
  1583.      * @Rest\View()
  1584.      */
  1585.     public function callRequest(Request $requestListing $listing)
  1586.     {
  1587.         $lead $request->get('lead');
  1588.         $countryCode $request->get('countryCode'$lead['countryCode'] ?? '+20');
  1589.         $originalPhoneNumber $lead['phone'];
  1590.         $phoneNumber $lead $this->phoneManager->trimZero($lead['phone'], $countryCode) : null;
  1591.         $user $this->getUser();
  1592.         $registerMessage '';
  1593.         $callRequest = new CallRequest();
  1594.         if ($lead) {
  1595.             $form $this->createForm(QuickLeadType::class, null, [
  1596.                 'method' => 'POST',
  1597.                 'csrf_protection' => false,
  1598.             ]);
  1599.             $form->handleRequest($request);
  1600.             $hasEmail = !$request->get('isAutoGeneratedEmail'0);
  1601.             /** @var User $user */
  1602.             $user $this->FOSUserManager->findUserByEmail($lead['email']);
  1603.             if (!$user && !$hasEmail) {
  1604.                 $user $this->userManager->findLatestByPhone($phoneNumber$countryCode);
  1605.             }
  1606.             if (!$user && $hasEmail) {
  1607.                 $user $this->userManager->findAndReplaceUserAndEmail($phoneNumber$lead['email'], $request->get('countryCode'));
  1608.             }
  1609.             $phone $this->phoneManager->findOrSavePhoneNumber($phoneNumber$countryCodenull$originalPhoneNumber);
  1610.             if (!$user) {
  1611.                 $user $this->FOSUserManager->createUser();
  1612.                 $user
  1613.                     ->setFullName($lead['name'])
  1614.                     ->setPhoneNumber($lead['phone'])
  1615.                     ->setTempCountryCode($countryCode)
  1616.                     ->setTempOriginalPhoneNumber($originalPhoneNumber)
  1617.                     ->setEmail($lead['email'])
  1618.                     ->setHasEmail($hasEmail)
  1619.                     ->setIsQucikRegistered(true)
  1620.                 ;
  1621.                 $this->userManager->quickRegister($user$form$requesttruefalsefalse);
  1622.                 $registerMessage $this->translator->trans('popup_form.success');
  1623.             }
  1624.             $callRequest->setPhone($phone);
  1625.             $callRequest->setLeadEmail($lead['email']);
  1626.             $callRequest->setLeadFullName($lead['name']);
  1627.             $this->phoneManager->addNewUserPhone($phoneNumber$countryCode$usertruefalsenull$originalPhoneNumber);
  1628.         }
  1629.         // Create Call Request
  1630.         $callRequest->setUser($user);
  1631.         $callRequest->setListing($listing);
  1632.         $form $this->callRequestForm($listing);
  1633.         $form->handleRequest($request);
  1634.         $isPostRequestAndValidForm $request->isMethod('POST') && ($form->isSubmitted() && $form->isValid());
  1635.         $isNotCheckForm = (false == $request->get('check_form'));
  1636.         if ($isPostRequestAndValidForm || $isNotCheckForm) {
  1637.             try {
  1638.                 $this->callRequestManager->submitCallRequest($callRequestnull$request->query->get('sourceRoute'''));
  1639.                 return [
  1640.                     'status' => 'ok',
  1641.                     'message' => $this->translator->trans('listing.success_call_request'),
  1642.                     'registerMessage' => $registerMessage,
  1643.                 ];
  1644.             } catch (InvalidLeadValidationHttpException $exception) {
  1645.                 return [
  1646.                     'status' => $exception->getStatusCode(),
  1647.                     'message' => $exception->getMessage(),
  1648.                 ];
  1649.             }
  1650.         }
  1651.         return $form;
  1652.     }
  1653.     /**
  1654.      * Show how to add a listing for new users.
  1655.      *
  1656.      * @Route("/add_listing", name="aqarmap_add_listing")
  1657.      */
  1658.     public function addListingRoles(): Response
  1659.     {
  1660.         return $this->render(
  1661.             '@AqarmapListing/Listing/addListingRoles.html.twig',
  1662.             [
  1663.             ]
  1664.         );
  1665.     }
  1666.     /**
  1667.      * @Route("/listing/{id}/relist", requirements={"id" = "\d+"}, name="aqarmap_listing_relist", options={"expose"=true} )
  1668.      *
  1669.      * @Security("is_granted('ROLE_ADMIN') or is_granted('ROLE_OWNER', listing)")
  1670.      *
  1671.      * @return RedirectResponse|Response
  1672.      */
  1673.     public function relist(Listing $listing)
  1674.     {
  1675.         if (!\in_array($listing->getStatus(), [ListingStatus::EXPIREDListingStatus::USER_DELETED])) {
  1676.             throw new LogicHttpException('Whoops! Looks like the listing you are trying to relist in not expired!');
  1677.         }
  1678.         $em $this->getDoctrine()->getManager();
  1679.         $listingRepo $em->getRepository(Listing::class);
  1680.         $relistChild $listingRepo->getRelistChild($listing);
  1681.         if ($relistChild) {
  1682.             $this->addFlash(
  1683.                 'success',
  1684.                 $this->translator->trans('add_listing_page.success_messages.relist')
  1685.             );
  1686.             return new RedirectResponse(
  1687.                 $this
  1688.                     ->generateUrl(
  1689.                         'listing_slug',
  1690.                         ['id' => $relistChild->getId(),
  1691.                             'slug' => $relistChild->getSlug(), ]
  1692.                     )
  1693.             )
  1694.             ;
  1695.         }
  1696.         $listing $this->listingManager->relist($listing);
  1697.         // Check if the listing require more photos or require repayment, and redirection.
  1698.         $listingEvent = new ListingEvent($listing);
  1699.         $this->dispatcher->dispatch($listingEvent'aqarmap.listing.resubmitted');
  1700.         $response $listingEvent->getResponse();
  1701.         if (null === $response) {
  1702.             if (\in_array($listing->getStatus(), [ListingStatus::PENDINGListingStatus::LIVE])) {
  1703.                 $this->addFlash(
  1704.                     'success',
  1705.                     $this->translator->trans('add_listing_page.success_messages.relist')
  1706.                 );
  1707.             }
  1708.             $response = new RedirectResponse(
  1709.                 $this
  1710.                     ->generateUrl(
  1711.                         'listing_slug',
  1712.                         [
  1713.                             'id' => $listing->getId(),
  1714.                             'slug' => $listing->getSlug(),
  1715.                         ]
  1716.                     )
  1717.             );
  1718.         }
  1719.         return $response;
  1720.     }
  1721.     /**
  1722.      * @Route(
  1723.      *     "/listing/transfer/scraped/{id}",
  1724.      *     requirements={"id" = "\d+"},
  1725.      *     name="aqarmap_listing_transfer_ownership",
  1726.      *     options={"expose"=true},
  1727.      *     methods={"POST"},
  1728.      * )
  1729.      */
  1730.     public function transferScrapedListingOwnership(Listing $listing)
  1731.     {
  1732.         /** @var User $user */
  1733.         $user $this->getUser();
  1734.         /** @var EntityManager $em */
  1735.         $em $this->getDoctrine()->getManager();
  1736.         if (!$listing->canChangeScrapedListing()) {
  1737.             throw new LogicHttpException();
  1738.         }
  1739.         $listing->setUser($user);
  1740.         $em->persist($listing);
  1741.         $em->flush($listing);
  1742.         return new JsonResponse();
  1743.     }
  1744.     /**
  1745.      * @Route("/listing/{id}/pump_up",
  1746.      * requirements={"id" = "\d+"}, name="confirm_listing_pump_up", methods={"POST"})
  1747.      *
  1748.      * @Security("is_granted('ROLE_OWNER', listing)")
  1749.      */
  1750.     public function confirmPumpUpListing(Listing $listingRequest $request): RedirectResponse
  1751.     {
  1752.         $pumpUpForm $this->confirmFeaturedPaymentForm($listing);
  1753.         $pumpUpForm->handleRequest($request);
  1754.         if ($request->isMethod('POST') && $pumpUpForm->isValid()) {
  1755.             if (!$pumpUpForm->get('confirm')->isClicked()) {
  1756.                 return $this->redirect($this->generateUrl('aqarmap_listing_default_mylistings'), Response::HTTP_FOUND);
  1757.             }
  1758.             try {
  1759.                 $this->listingManager->pumpUp($listing);
  1760.                 $this->addFlash(
  1761.                     'success',
  1762.                     $this->translator->trans('credit.pump_up_success', [':listing_title:' => $listing->getTitle()])
  1763.                 );
  1764.             } catch (\Exception $e) {
  1765.                 $this->addFlash('danger'$e->getMessage());
  1766.             }
  1767.         }
  1768.         return $this->redirect($this->generateUrl('aqarmap_listing_default_mylistings'));
  1769.     }
  1770.     /**
  1771.      * @Route("/listing/{id}/pump_up",
  1772.      * requirements={"id" = "\d+"}, name="listing_pump_up", methods={"GET"})
  1773.      *
  1774.      * @Security("is_granted('ROLE_OWNER', listing)")
  1775.      *
  1776.      * @return array|RedirectResponse
  1777.      */
  1778.     public function pumpUpListing(Listing $listing)
  1779.     {
  1780.         $listingRules $this->listingManager->getListingRules($listing);
  1781.         $listingOwner $listing->getUser();
  1782.         $pumpUpFees $listingRules['pump_up_fees'];
  1783.         $pumpUpOccurrence $listingRules['pump_up_occurrence'];
  1784.         $pumpUpDuration $listingRules['pump_up_duration'];
  1785.         if (!$this->listingManager->isPumpUpAvailable($listingRules)) {
  1786.             $this->addFlash(
  1787.                 'danger',
  1788.                 $this->translator->trans('credit.pump_up_not_available')
  1789.             );
  1790.             return $this->redirect($this->generateUrl('aqarmap_listing_default_mylistings'));
  1791.         }
  1792.         if (!$this->listingManager->isAffordable($listingOwner$pumpUpFees)) {
  1793.             $this->addFlash(
  1794.                 'danger',
  1795.                 $this->translator->trans('credit.pump_up_can_not_use')
  1796.             );
  1797.             return $this->redirect($this->generateUrl('aqarmap_listing_default_mylistings'));
  1798.         }
  1799.         /** @var $em \Doctrine\ORM\EntityManager */
  1800.         $em $this->getDoctrine()->getManager();
  1801.         $em->getRepository(Credit::class);
  1802.         $pumpUpForm $this->createForm(ConfirmFeaturedFormType::class, null, [
  1803.             'method' => 'POST',
  1804.             'action' => $this
  1805.                 ->generateUrl(
  1806.                     'listing_pump_up',
  1807.                     ['id' => $listing->getId()]
  1808.                 ),
  1809.             'confirm_message' => $this->translator->trans('listing.pump_up.confirm'),
  1810.             'cancel_message' => $this->translator->trans('listing.pump_up.cancel'),
  1811.         ]);
  1812.         return $this->render(
  1813.             '@AqarmapListing/Listing/pumpUpListing.html.twig',
  1814.             [
  1815.                 'fees' => $pumpUpFees,
  1816.                 'duration' => $pumpUpDuration,
  1817.                 'occurrence' => $pumpUpOccurrence,
  1818.                 'form' => $pumpUpForm->createView(),
  1819.             ]
  1820.         );
  1821.     }
  1822.     /**
  1823.      * Listing Details Single Page App.
  1824.      *
  1825.      * @Route("/listingApp/{id}", requirements={"id" = "\d+"} , options={"expose" = true} , name="listing_details_app", methods={"GET"})
  1826.      */
  1827.     public function listingDetailsApp(Listing $listing): Response
  1828.     {
  1829.         return $this->render(
  1830.             '@AqarmapListing/Listing/listingDetailsApp.html.twig',
  1831.             [
  1832.                 'listingId' => $listing->getReferenceId(),
  1833.             ]
  1834.         );
  1835.     }
  1836.     /**
  1837.      * Delete Listing Photos.
  1838.      *
  1839.      * @Route("/photos/delete", name="listing_bulk_delete_photo", requirements={"id" = "\d+"})
  1840.      *
  1841.      * @throws \Doctrine\ORM\OptimisticLockException
  1842.      */
  1843.     public function bulkDeletePhoto(Request $requestListingPhotoRepository $listingPhotoRepositoryListingManager $listingManager): RedirectResponse
  1844.     {
  1845.         $photosIds $request->get('photos');
  1846.         try {
  1847.             if ($photosIds) {
  1848.                 $photos $listingPhotoRepository->getPhotos($photosIds);
  1849.                 $listingManager->bulkDeletePhotos($photos);
  1850.             } else {
  1851.                 $this->addFlash('danger''No photos selected for deletion');
  1852.             }
  1853.         } catch (\Exception $e) {
  1854.             $this->addFlash('danger''Something went wrong');
  1855.         }
  1856.         return $this->redirect($request->headers->get('referer') ?: $this->generateUrl('homepage'));
  1857.     }
  1858.     /**
  1859.      * @throws \Exception
  1860.      *
  1861.      * @Route("/brochure/{file}/download", name="download_brochure", options={"expose"=true})
  1862.      */
  1863.     public function downloadBrochure(File $fileDownloadHandler $downloadHandler): Response
  1864.     {
  1865.         $response $downloadHandler->downloadObject($file'file');
  1866.         // force specific content type instead of using default "application/octet-stream".
  1867.         $response->headers->set('content-type''application/pdf');
  1868.         return $response;
  1869.     }
  1870.     /**
  1871.      * Update WhatsApp Phones.
  1872.      */
  1873.     private function updateWhatsAppPhones(int $userId, array $phones = [], array $whatsApp = []): void
  1874.     {
  1875.         foreach ($phones as $index => $phone) {
  1876.             $whatsApp[$index] = isset($whatsApp[$index]) && 'true' === $whatsApp[$index];
  1877.             $this->phoneManager->updateWhatsApp($userId, (int) $phone$whatsApp[$index], true);
  1878.         }
  1879.     }
  1880. }