src/Aqarmap/Bundle/ListingBundle/Controller/Api/ListingController.php line 303

Open in your IDE?
  1. <?php
  2. namespace Aqarmap\Bundle\ListingBundle\Controller\Api;
  3. use App\Exception\BadRequestHttpException;
  4. use App\Exception\LogicHttpException;
  5. use Aqarmap\Bundle\CreditBundle\Constant\CreditStatus;
  6. use Aqarmap\Bundle\CreditBundle\Contract\CreditManagerInterface;
  7. use Aqarmap\Bundle\CreditBundle\Entity\Credit;
  8. use Aqarmap\Bundle\FeatureToggleBundle\Service\FeatureToggleManager;
  9. use Aqarmap\Bundle\ListingBundle\Constant\CountryCodes;
  10. use Aqarmap\Bundle\ListingBundle\Constant\LeadTypes;
  11. use Aqarmap\Bundle\ListingBundle\Constant\ListingFeaturedTypes;
  12. use Aqarmap\Bundle\ListingBundle\Constant\ListingFeatures;
  13. use Aqarmap\Bundle\ListingBundle\Constant\ListingStatus;
  14. use Aqarmap\Bundle\ListingBundle\Constant\ListingSyncedFields;
  15. use Aqarmap\Bundle\ListingBundle\Constant\PhotoTypes;
  16. use Aqarmap\Bundle\ListingBundle\Contracts\PhoneManagerInterface;
  17. use Aqarmap\Bundle\ListingBundle\Entity\CallRequest;
  18. use Aqarmap\Bundle\ListingBundle\Entity\Listing;
  19. use Aqarmap\Bundle\ListingBundle\Entity\ListingNote;
  20. use Aqarmap\Bundle\ListingBundle\Entity\ListingPhone;
  21. use Aqarmap\Bundle\ListingBundle\Entity\ListingPhoto;
  22. use Aqarmap\Bundle\ListingBundle\Entity\Photo;
  23. use Aqarmap\Bundle\ListingBundle\Entity\PropertyType;
  24. use Aqarmap\Bundle\ListingBundle\Entity\Section;
  25. use Aqarmap\Bundle\ListingBundle\Event\LeadEvent;
  26. use Aqarmap\Bundle\ListingBundle\Event\ListingEvent;
  27. use Aqarmap\Bundle\ListingBundle\Event\ListingUpdatedEvent;
  28. use Aqarmap\Bundle\ListingBundle\Form\ContactSellerFormType;
  29. use Aqarmap\Bundle\ListingBundle\Form\ListingApiType;
  30. use Aqarmap\Bundle\ListingBundle\Form\ListingNoteType;
  31. use Aqarmap\Bundle\ListingBundle\Form\PhotoType;
  32. use Aqarmap\Bundle\ListingBundle\Form\QuickContactSellerType;
  33. use Aqarmap\Bundle\ListingBundle\Form\QuickCreateLeadFormType;
  34. use Aqarmap\Bundle\ListingBundle\Form\QuickLeadType;
  35. use Aqarmap\Bundle\ListingBundle\Model\LeadModel;
  36. use Aqarmap\Bundle\ListingBundle\Repository\ListingNoteRepository;
  37. use Aqarmap\Bundle\ListingBundle\Repository\ListingRepository;
  38. use Aqarmap\Bundle\ListingBundle\Service\CallLog\Logger;
  39. use Aqarmap\Bundle\ListingBundle\Service\CallRequestManager;
  40. use Aqarmap\Bundle\ListingBundle\Service\FavouriteService;
  41. use Aqarmap\Bundle\ListingBundle\Service\InteractionService;
  42. use Aqarmap\Bundle\ListingBundle\Service\LeadService;
  43. use Aqarmap\Bundle\ListingBundle\Service\ListingManager;
  44. use Aqarmap\Bundle\ListingBundle\Service\ListingNoteService;
  45. use Aqarmap\Bundle\ListingBundle\Service\ListingRateService;
  46. use Aqarmap\Bundle\ListingBundle\Service\ListingRuleMatcher;
  47. use Aqarmap\Bundle\ListingBundle\Service\LocationManager;
  48. use Aqarmap\Bundle\ListingBundle\Service\Mortgage\MortgageService;
  49. use Aqarmap\Bundle\ListingBundle\Service\NewsFeed\ListingNewsFeed;
  50. use Aqarmap\Bundle\ListingBundle\Twig\ListingExtension;
  51. use Aqarmap\Bundle\MainBundle\Controller\Api\BaseController;
  52. use Aqarmap\Bundle\MainBundle\Service\Setting;
  53. use Aqarmap\Bundle\MessageBundle\Service\Composer;
  54. use Aqarmap\Bundle\TopSellerBundle\Model\TopSeller;
  55. use Aqarmap\Bundle\TopSellerBundle\Service\TopSellerRetrievalService;
  56. use Aqarmap\Bundle\UserBundle\Entity\User;
  57. use Aqarmap\Bundle\UserBundle\Services\UserManager;
  58. use DateTime;
  59. use Doctrine\Common\Collections\Collection;
  60. use Doctrine\ORM\EntityManager;
  61. use Doctrine\ORM\EntityManagerInterface;
  62. use Doctrine\ORM\OptimisticLockException;
  63. use Doctrine\ORM\ORMException;
  64. use FOS\RestBundle\Controller\Annotations as Rest;
  65. use FOS\RestBundle\View\View;
  66. use FOS\UserBundle\Model\UserManagerInterface;
  67. use Gedmo\Translatable\TranslatableListener;
  68. use Knp\Component\Pager\PaginatorInterface;
  69. use Nelmio\ApiDocBundle\Annotation\Operation;
  70. use OpenApi\Annotations as OA;
  71. use Psr\Log\LoggerInterface;
  72. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
  73. use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
  74. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
  75. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  76. use Symfony\Component\Form\Form;
  77. use Symfony\Component\HttpFoundation\File\UploadedFile;
  78. use Symfony\Component\HttpFoundation\Request;
  79. use Symfony\Component\HttpFoundation\Response;
  80. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  81. use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
  82. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  83. use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  84. use Symfony\Contracts\Translation\TranslatorInterface;
  85. /**
  86.  * Class ListingController.
  87.  */
  88. class ListingController extends BaseController
  89. {
  90.     /**
  91.      * @var CallRequestManager
  92.      */
  93.     private $callRequestManager;
  94.     /**
  95.      * @var ListingNewsFeed
  96.      */
  97.     private $listingNewsFeed;
  98.     /**
  99.      * @var LoggerInterface
  100.      */
  101.     private $errorLogger;
  102.     /**
  103.      * @var MortgageService
  104.      */
  105.     private $mortgageService;
  106.     /**
  107.      * @var TokenStorageInterface
  108.      */
  109.     protected $tokenStorage;
  110.     /**
  111.      * @var Composer
  112.      */
  113.     private $messageComposer;
  114.     /**
  115.      * @var FavouriteService
  116.      */
  117.     private $favouriteService;
  118.     /**
  119.      * @var PaginatorInterface
  120.      */
  121.     private $paginator;
  122.     /** @var ListingManager */
  123.     private $listingManager;
  124.     /**
  125.      * @var InteractionService
  126.      */
  127.     private $interactionService;
  128.     /**
  129.      * @var EventDispatcherInterface
  130.      */
  131.     private $dispatcher;
  132.     /** @var FOSUserManager */
  133.     private $fosUserManager;
  134.     /**
  135.      * @var TranslatorInterface
  136.      */
  137.     private $translator;
  138.     /**
  139.      * @var TranslatableListener
  140.      */
  141.     private $translatableListener;
  142.     /**
  143.      * @var Logger
  144.      */
  145.     private $logger;
  146.     private UserManager $userManager;
  147.     /** @var ListingManager */
  148.     private $listingService;
  149.     /** @var ListingRateService */
  150.     private $listingRateService;
  151.     /** @var ListingNoteService */
  152.     private $listingNoteService;
  153.     /**
  154.      * @var ListingRuleMatcher
  155.      */
  156.     private $listingRuleMatcher;
  157.     /**
  158.      * @var LocationManager
  159.      */
  160.     private $locationManager;
  161.     /**
  162.      * @var FeatureToggleManager
  163.      */
  164.     private $featureToggle;
  165.     /**
  166.      * @var PhoneManagerInterface
  167.      */
  168.     private $phoneManager;
  169.     /** @var LeadService */
  170.     private $leadManager;
  171.     /** @var CreditManagerInterface */
  172.     private $creditManager;
  173.     /**
  174.      * @var ListingExtension
  175.      */
  176.     private $listingExtension;
  177.     private EntityManagerInterface $entityManager;
  178.     public function __construct(
  179.         Composer $messageComposer,
  180.         FavouriteService $favouriteService,
  181.         PaginatorInterface $paginator,
  182.         SessionInterface $session,
  183.         InteractionService $interactionService,
  184.         ListingManager $listingManager,
  185.         EventDispatcherInterface $dispatcher,
  186.         UserManagerInterface $fosUserManager,
  187.         TranslatorInterface $translator,
  188.         TranslatableListener $translatableListener,
  189.         Logger $logger,
  190.         UserManager $userManager,
  191.         ListingManager $listingService,
  192.         ListingNoteService $listingNoteService,
  193.         ListingRuleMatcher $listingRuleMatcher,
  194.         LocationManager $locationManager,
  195.         Setting $setting,
  196.         PhoneManagerInterface $phoneManager,
  197.         FeatureToggleManager $featureToggle,
  198.         ListingRateService $listingRateService,
  199.         TokenStorageInterface $tokenStorage,
  200.         LeadService $leadManager,
  201.         CallRequestManager $callRequestManager,
  202.         MortgageService $mortgageService,
  203.         CreditManagerInterface $creditManager,
  204.         ListingExtension $listingExtension,
  205.         ListingNewsFeed $listingNewsFeed,
  206.         EntityManagerInterface $entityManager
  207.     ) {
  208.         $this->messageComposer $messageComposer;
  209.         $this->favouriteService $favouriteService;
  210.         $this->callRequestManager $callRequestManager;
  211.         $this->featureToggle $featureToggle;
  212.         $this->paginator $paginator;
  213.         $this->interactionService $interactionService;
  214.         $this->listingManager $listingManager;
  215.         $this->dispatcher $dispatcher;
  216.         $this->fosUserManager $fosUserManager;
  217.         $this->translator $translator;
  218.         $this->translatableListener $translatableListener;
  219.         $this->logger $logger;
  220.         $this->userManager $userManager;
  221.         $this->listingService $listingService;
  222.         $this->listingNoteService $listingNoteService;
  223.         $this->listingRuleMatcher $listingRuleMatcher;
  224.         $this->locationManager $locationManager;
  225.         $this->phoneManager $phoneManager;
  226.         $this->listingRateService $listingRateService;
  227.         $this->tokenStorage $tokenStorage;
  228.         $this->leadManager $leadManager;
  229.         $this->mortgageService $mortgageService;
  230.         $this->creditManager $creditManager;
  231.         $this->listingExtension $listingExtension;
  232.         $this->listingNewsFeed $listingNewsFeed;
  233.         $this->entityManager $entityManager;
  234.     }
  235.     /**
  236.      * Get Listing.
  237.      *
  238.      * @Operation(
  239.      *     tags={"Listing"},
  240.      *     summary="Returns a Listing Object",
  241.      *
  242.      *     @OA\Response(
  243.      *         response="404",
  244.      *         description="Returned when the listing is not found"
  245.      *     )
  246.      * )
  247.      *
  248.      * @Rest\Get("/api/v2/listing/{id}", requirements={"id" = "\d+"}, options={"i18n" = false}, name="aqarmap_api_get_listing_v2")
  249.      *
  250.      * @Rest\View(serializerGroups={"Default", "Details", "Compound"})
  251.      *
  252.      * @Cache(
  253.      *  expires="+2 hours", maxage="+2 hours", smaxage="+2 hours",
  254.      *  public=false, vary={"Accept-Language", "X-Accept-Version", "Accept"}
  255.      * )
  256.      */
  257.     public function getListing(Listing $listing): array
  258.     {
  259.         return ['listing' => $listing];
  260.     }
  261.     /**
  262.      * Listing details.
  263.      *
  264.      * @Rest\Get("/api/v4/listing/{id}", requirements={"id" = "\d+"}, options={"i18n" = false}, name="aqarmap_api_get_listing_v4")
  265.      *
  266.      * @Rest\View(serializerGroups={"listingDetails", "listingDetailsWithLocationCompound"})
  267.      *
  268.      * @Cache(
  269.      *  expires="+6 hours", maxage="+6 hours", smaxage="+6 hours",
  270.      *  public=true, vary={"Accept-Language", "X-Accept-Version", "Accept"}
  271.      * )
  272.      */
  273.     public function getListingDetails(int $idListingRepository $listingRepository): array
  274.     {
  275.         $entityManagerFilters $this->entityManager->getFilters();
  276.         if ($entityManagerFilters->isEnabled('softdeleteable')) {
  277.             $entityManagerFilters->disable('softdeleteable');
  278.         }
  279.         $listing $listingRepository->find($id);
  280.         $entityManagerFilters->enable('softdeleteable');
  281.         return ['listing' => $listing];
  282.     }
  283.     /**
  284.      * Get Listing Children (Project Units).
  285.      *
  286.      * @Operation(
  287.      *     tags={"Listing"},
  288.      *     summary="Returns a Listing Children",
  289.      *
  290.      *     @OA\Response(
  291.      *         response="404",
  292.      *         description="Returned when the listing is not found"
  293.      *     )
  294.      * )
  295.      *
  296.      * @Rest\Get("/api/v2/listing/{id}/children", options={"i18n" = false}, name="aqarmap_api_get_listing_children_v2")
  297.      *
  298.      * @Rest\View(serializerGroups={"Default", "Details"})
  299.      *
  300.      * @return array
  301.      */
  302.     public function getListingChildren(Listing $listing)
  303.     {
  304.         return $this->respond($listing->getLiveChildren());
  305.     }
  306.     /**
  307.      * @Operation(
  308.      *     tags={"Web API Calls"},
  309.      *     summary="",
  310.      *
  311.      *     @OA\Parameter(
  312.      *         name="lead",
  313.      *          in="query",
  314.      *         description="",
  315.      *         required=false,
  316.      *     ),
  317.      *
  318.      * )
  319.      *
  320.      * @Rest\Post("/api/v2/listing/{listing}/phones", options={"i18n" = false}, name="aqarmap_api_get_listing_phones_v2")
  321.      *
  322.      * @Rest\View(serializerGroups={"Default", "Details"})
  323.      *
  324.      * @return Collection
  325.      *
  326.      * @throws ORMException
  327.      * @throws OptimisticLockException
  328.      */
  329.     public function getListingPhone(Listing $listingRequest $request, ?User $user null)
  330.     {
  331.         $version = (float) ltrim((string) $request->headers->get('X-Accept-Version'), 'v');
  332.         $leadModel = new LeadModel();
  333.         $currentUrl $request->getUri();
  334.         if (str_contains($currentUrl'v2')) {
  335.             if (!$user $this->getUser() && $version <= 2.13) {
  336.                 throw new AccessDeniedHttpException();
  337.             }
  338.         }
  339.         $form $this->createForm(QuickLeadType::class, null, [
  340.             'method' => 'POST',
  341.             'csrf_protection' => false,
  342.         ]);
  343.         $form->handleRequest($request);
  344.         $lead $form->getData();
  345.         $phoneManager $this->phoneManager;
  346.         $originalPhoneNumber $lead['phone'];
  347.         $phoneNumber $phoneManager->trimZero($lead['phone'], $lead['countryCode']);
  348.         $aqarmapUserService $this->userManager;
  349.         $hasEmail = !$lead['isAutoGeneratedEmail'];
  350.         /** @var $userManager \FOS\UserBundle\Model\UserManagerInterface */
  351.         $userManager $this->fosUserManager;
  352.         /** @var User $user */
  353.         $user $userManager->findUserByEmail($lead['email']);
  354.         $countryCode $lead['countryCode'];
  355.         if (!$user && !$hasEmail) {
  356.             $user $aqarmapUserService->findLatestByPhone($phoneNumber$countryCode);
  357.         }
  358.         if (!$user && $hasEmail) {
  359.             $user $aqarmapUserService->findAndReplaceUserAndEmail($phoneNumber$lead['email'], $countryCode);
  360.         }
  361.         if (!$user) {
  362.             $user $userManager->createUser();
  363.             $user
  364.                 ->setFullName($lead['name'])
  365.                 ->setPhoneNumber($lead['phone'])
  366.                 ->setTempOriginalPhoneNumber($originalPhoneNumber)
  367.                 ->setTempCountryCode($lead['countryCode'])
  368.                 ->setEmail($lead['email'])
  369.                 ->setHasEmail($hasEmail)
  370.                 ->setLanguage('ar');
  371.             $user $aqarmapUserService->quickRegistration($form$user$request);
  372.         }
  373.         $phone $phoneManager->addNewUserPhone($phoneNumber$lead['countryCode'], $usertruefalsenull$originalPhoneNumber);
  374.         $userManager->updateUser($user);
  375.         $userManager->reloadUser($user);
  376.         $leadModel->setPhone($phone->getPhone());
  377.         $leadModel->setName($request->request->get('name'$lead['name']));
  378.         $leadModel->setEmail($request->request->get('email'$lead['email']));
  379.         $leadService $this->leadManager;
  380.         $leadModel->setLeadType(LeadTypes::SHOW_PHONE);
  381.         $leadModel->setListing($listing);
  382.         $leadModel->setSource('api');
  383.         $leadModel->setUser($user);
  384.         $lead $leadService->addLead($leadModel);
  385.         if ($lead) {
  386.             $this->dispatcher->dispatch(
  387.                 new LeadEvent(
  388.                     $listing,
  389.                     $user,
  390.                     $lead
  391.                 ),
  392.                 'aqarmap.listing.show_seller_number'
  393.             );
  394.         }
  395.         return $listing->getPhones();
  396.     }
  397.     /**
  398.      * @Operation(
  399.      *     tags={"Listing"},
  400.      *     summary="Send message to listing owner & set lead",
  401.      *
  402.      *     @OA\Parameter(
  403.      *         name="campaign",
  404.      *         in="query",
  405.      *         description="Campaign Name",
  406.      *         required=false,
  407.      *     ),
  408.      *     @OA\Parameter(
  409.      *         name="contact_seller",
  410.      *          in="query",
  411.      *         description="",
  412.      *         required=false,
  413.      *     ),
  414.      *
  415.      *     @OA\Response(
  416.      *         response="404",
  417.      *         description="Returned when the listing is not found"
  418.      *     )
  419.      * )
  420.      *
  421.      * @Rest\Post("/api/v2/listing/{listing}/contact_seller", options={"i18n" = false}, name="aqarmap_api_listing_contact_seller_v2")
  422.      *
  423.      * @Rest\QueryParam(name="campaign", description="Campaign Name")
  424.      *
  425.      * @Rest\View(serializerGroups={"Default", "Details"})
  426.      *
  427.      * @return bool|Form
  428.      *
  429.      * @throws AccessDeniedHttpException
  430.      */
  431.     public function contactSeller(Request $requestListing $listing, ?User $user null)
  432.     {
  433.         $currentUrl $request->getUri();
  434.         if (str_contains($currentUrl'v2')) {
  435.             if (!$user $this->getUser()) {
  436.                 throw new AccessDeniedHttpException();
  437.             }
  438.         }
  439.         $form $this->createForm(ContactSellerFormType::class, null, [
  440.             'method' => 'POST',
  441.             'csrf_protection' => false,
  442.         ]);
  443.         $form->handleRequest($request);
  444.         if ($form->isSubmitted() && $form->isValid()) {
  445.             // Get campaign name
  446.             $campaign $request->query->get('campaign');
  447.             $message $form->getData();
  448.             // Send contact seller message and send a lead
  449.             $composer $this->messageComposer;
  450.             $composer
  451.                 ->setSender($user)
  452.                 ->compose($message['message'], $listing$campaign);
  453.             return true;
  454.         }
  455.         return $form;
  456.     }
  457.     /**
  458.      * @Operation(
  459.      *     tags={"Listing"},
  460.      *     summary="Quick register a user, send message to listing owner & set lead",
  461.      *
  462.      *     @OA\Parameter(
  463.      *         name="campaign",
  464.      *         in="query",
  465.      *         description="Campaign Name",
  466.      *         required=false,
  467.      *     ),
  468.      *     @OA\Parameter(
  469.      *         name="contact_seller",
  470.      *          in="query",
  471.      *         description="",
  472.      *         required=false,
  473.      *     ),
  474.      *
  475.      *     @OA\Response(
  476.      *         response="201",
  477.      *         description="Returned when user created and message sent successfully"
  478.      *     ),
  479.      *     @OA\Response(
  480.      *         response="404",
  481.      *         description="Returned when the listing is not found"
  482.      *     ),
  483.      *     @OA\Response(
  484.      *         response="403",
  485.      *         description="Returned when parameter is missing"
  486.      *     )
  487.      * )
  488.      *
  489.      * @Rest\Post("/api/v2/listing/{listing}/contact_seller/quick", options={"i18n" = false}, name="aqarmap_api_listing_quick_contact_seller_v2")
  490.      *
  491.      * @Rest\QueryParam(name="campaign", description="Campaign Name")
  492.      *
  493.      * @Rest\View(serializerGroups={"Default", "Details"})
  494.      *
  495.      * @return Response $response
  496.      *
  497.      * @throws \Exception
  498.      */
  499.     public function contactSellerWithQuickRegistration(Request $requestListing $listing): Response
  500.     {
  501.         if (!$this->isValidQuickContactSellerParameters($request->get('contact_seller'))) {
  502.             return new Response(nullResponse::HTTP_FORBIDDEN);
  503.         }
  504.         $form $this->createForm(QuickContactSellerType::class, null, [
  505.             'method' => 'POST',
  506.             'csrf_protection' => false,
  507.         ]);
  508.         $form->handleRequest($request);
  509.         if ($form->isSubmitted() && !$form->isValid()) {
  510.             return new Response(nullResponse::HTTP_FORBIDDEN);
  511.         }
  512.         $userManager $this->userManager;
  513.         $fromData $form->getData();
  514.         $user $userManager->createQuickUser($request$form);
  515.         $campaign $request->query->get('campaign');
  516.         $composer $this->messageComposer;
  517.         $composer
  518.             ->setSender($user)
  519.             ->compose($fromData['message'], $listing$campaign);
  520.         return new Response(nullResponse::HTTP_CREATED);
  521.     }
  522.     private function isValidQuickContactSellerParameters(array $parameters): bool
  523.     {
  524.         if (
  525.             !\array_key_exists('email'$parameters)
  526.             || !\array_key_exists('phone'$parameters)
  527.             || !\array_key_exists('countryCode'$parameters)
  528.         ) {
  529.             return false;
  530.         }
  531.         return true;
  532.     }
  533.     /**
  534.      * @Operation(
  535.      *     tags={"Listing"},
  536.      *     summary="",
  537.      *
  538.      * )
  539.      *
  540.      * @Rest\Post("/api/v2/listing/{listing}/call_request", options={"i18n" = false}, name="aqarmap_api_listing_call_request_v2")
  541.      *
  542.      * @Rest\QueryParam(name="campaign", description="Campaign Name")
  543.      *
  544.      * @Rest\View(serializerGroups={"Default", "Details"})
  545.      *
  546.      * @return bool|array
  547.      */
  548.     public function callRequest(Listing $listingRequest $request, ?User $user null)
  549.     {
  550.         $version = (float) ltrim((string) $request->headers->get('X-Accept-Version'), 'v');
  551.         $callRequest = new CallRequest();
  552.         $currentUrl $request->getUri();
  553.         if (str_contains($currentUrl'v2')) {
  554.             if (!$user $this->getUser() && $version <= 2.13) {
  555.                 throw new AccessDeniedHttpException();
  556.             }
  557.         }
  558.         $form $this->createForm(QuickLeadType::class, null, [
  559.             'method' => 'POST',
  560.             'csrf_protection' => false,
  561.         ]);
  562.         $form->handleRequest($request);
  563.         $lead $form->getData();
  564.         /** @var $userManager \FOS\UserBundle\Model\UserManagerInterface */
  565.         $userManager $this->fosUserManager;
  566.         $aqarmapUserManager $this->userManager;
  567.         $hasEmail = !$lead['isAutoGeneratedEmail'];
  568.         $phoneManager $this->phoneManager;
  569.         $originalPhoneNumber $lead['phone'];
  570.         $countryCode $lead['countryCode'];
  571.         $phoneNumber $phoneManager->trimZero($lead['phone'], $countryCode);
  572.         /** @var User $user */
  573.         $user $userManager->findUserByEmail($lead['email']);
  574.         if (!$user && !$hasEmail) {
  575.             $user $aqarmapUserManager->findLatestByPhone($phoneNumber$countryCode);
  576.         }
  577.         if (!$user && $hasEmail) {
  578.             $user $aqarmapUserManager->findAndReplaceUserAndEmail($phoneNumber$lead['email'], $countryCode);
  579.         }
  580.         if (!$user) {
  581.             $user $userManager->createUser();
  582.             $user
  583.                 ->setFullName($lead['name'])
  584.                 ->setPhoneNumber($lead['phone'])
  585.                 ->setTempOriginalPhoneNumber($originalPhoneNumber)
  586.                 ->setTempCountryCode($lead['countryCode'])
  587.                 ->setEmail($lead['email'])
  588.                 ->setHasEmail($hasEmail)
  589.                 ->setLanguage('ar');
  590.             $user $aqarmapUserManager->quickRegistration($form$user$request);
  591.         }
  592.         $phone $phoneManager->addNewUserPhone($phoneNumber$lead['countryCode'], $usertruefalsenull$originalPhoneNumber);
  593.         $userManager->updateUser($user);
  594.         $userManager->reloadUser($user);
  595.         $callRequest->setPhone($phone->getPhone());
  596.         $callRequest->setLeadFullName($request->request->get('name'));
  597.         $callRequest->setLeadEmail($request->request->get('email'));
  598.         $campaign $request->request->get('campaign');
  599.         $callRequest->setUser($user);
  600.         $callRequest->setListing($listing);
  601.         $this->callRequestManager->submitCallRequest($callRequest$campaign);
  602.         return true;
  603.     }
  604.     /**
  605.      * Add New User Listing.
  606.      *
  607.      * @Operation(
  608.      *     tags={"Listing"},
  609.      *     summary="Add New User Listing.",
  610.      *
  611.      *     @OA\Parameter(
  612.      *         name="listing",
  613.      *          in="query",
  614.      *         description="",
  615.      *         required=false,
  616.      *     ),
  617.      *
  618.      *     @OA\Response(
  619.      *         response="201",
  620.      *         description="Returned when successfully created"
  621.      *     ),
  622.      *     @OA\Response(
  623.      *         response="400",
  624.      *         description="Returned when validation error"
  625.      *     )
  626.      * )
  627.      *
  628.      * @Rest\Post("/api/v2/listing", options={"i18n" = false}, name="aqarmap_api_add_listing")
  629.      *
  630.      * @Security("is_granted('ROLE_USER')")
  631.      *
  632.      * @return View|Form
  633.      */
  634.     public function addListing(Request $request)
  635.     {
  636.         $form $this->createForm(ListingApiType::class, $listing = new Listing(), [
  637.             'csrf_protection' => false,
  638.         ]);
  639.         $form->handleRequest($request);
  640.         if ($form->isSubmitted() && $form->isValid()) {
  641.             if ($this->getUser()->getPhoneNumber()) {
  642.                 $listing->addPhone(new ListingPhone($this->getUser()->getPhoneNumber()));
  643.             }
  644.             $listingManager $this->listingService;
  645.             $listing->setUser($this->getUser());
  646.             $listing->setStatus(ListingStatus::DRAFT);
  647.             $listingManager->saveListing($listing);
  648.             $listingEvent = new ListingEvent($listing);
  649.             $this->dispatcher->dispatch($listingEvent'aqarmap.listing.submitted');
  650.             return View::create()->setData($listing)->setStatusCode(Response::HTTP_CREATED);
  651.         }
  652.         return View::create()->setData($form)->setStatusCode(Response::HTTP_BAD_REQUEST);
  653.     }
  654.     /**
  655.      * Create Single Listing Note.
  656.      *
  657.      * @Rest\Post("/api/v2/listing/{id}/note", options={"i18n" = false})
  658.      *
  659.      * @Rest\RequestParam(name="body", description="Note Body")
  660.      * @Rest\RequestParam(name="source", description="Supported sources: 1 = Website, 2 = Consumer App, 3 = Live App")
  661.      * @Rest\RequestParam(name="last_modified_at", description="dateTime")
  662.      * @Rest\RequestParam(name="created_at", description="dateTime")
  663.      *
  664.      * @ParamConverter("Listing", options={"mapping": {"listing": "id"}}, converter="querystring")
  665.      *
  666.      * @Security("is_granted('ROLE_USER')")
  667.      */
  668.     public function postListingSingleNote(Request $requestListing $listingListingNoteRepository $listingNoteRepositoryEntityManagerInterface $em)
  669.     {
  670.         $currentUser $this->getUser();
  671.         $listingNote $listingNoteRepository->findOneBy([
  672.             'user' => $currentUser,
  673.             'listing' => $listing,
  674.         ]);
  675.         if (empty($listingNote)) {
  676.             $listingNote = new ListingNote();
  677.             $listingNote->setUser($currentUser);
  678.             $listingNote->setListing($listing);
  679.             $listingNote->setCreatedAt(new \DateTime());
  680.         }
  681.         $form $this->createForm(ListingNoteType::class, $listingNote);
  682.         $form->handleRequest($request);
  683.         if ($form->isSubmitted() && $form->isValid()) {
  684.             $em->persist($listingNote);
  685.             $em->flush();
  686.             return $this->json([
  687.                 'message' => 'Successfully submitted',
  688.             ], Response::HTTP_CREATED);
  689.         }
  690.         return $this->json([
  691.             'message' => 'Error occurred',
  692.         ], Response::HTTP_BAD_REQUEST);
  693.     }
  694.     /**
  695.      * Create Bulk Listing Note.
  696.      *
  697.      * @Rest\Post("/api/v2/listing/note", options={"i18n" = false})
  698.      *
  699.      * @Security("is_granted('ROLE_USER')")
  700.      *
  701.      * @return array
  702.      */
  703.     public function postListingBulkNote(Request $request)
  704.     {
  705.         $listingNoteService $this->listingNoteService;
  706.         $listingNoteService->addBulk($request);
  707.         return $this->respond('Note Added Successfully!');
  708.     }
  709.     /**
  710.      * Update Listing.
  711.      *
  712.      * @Operation(
  713.      *     tags={"Listing"},
  714.      *     summary="Update Listing.",
  715.      *
  716.      *     @OA\Parameter(
  717.      *         name="listing",
  718.      *          in="query",
  719.      *         description="",
  720.      *         required=false,
  721.      *     ),
  722.      *
  723.      *     @OA\Response(
  724.      *         response="200",
  725.      *         description="Returned when successfully Updated"
  726.      *     ),
  727.      *     @OA\Response(
  728.      *         response="400",
  729.      *         description="Returned when validation error"
  730.      *     )
  731.      * )
  732.      *
  733.      * @Rest\Post("/api/v2/listing/{id}", options={"i18n" = false}, name="aqarmap_api_update_listing")
  734.      *
  735.      * @Rest\View
  736.      *
  737.      * @Security("is_granted('ROLE_OWNER', listing)")
  738.      *
  739.      * @return View|Form
  740.      */
  741.     public function updateListing(Listing $listingRequest $request)
  742.     {
  743.         $listing->clearAttributes();
  744.         $form $this->createForm(ListingApiType::class, $listing, [
  745.             'csrf_protection' => false,
  746.         ]);
  747.         $form->handleRequest($request);
  748.         if ($form->isSubmitted() && $form->isValid()) {
  749.             if ($this->getUser()->getPhoneNumber()) {
  750.                 $listing->addPhone(new ListingPhone($this->getUser()->getPhoneNumber()));
  751.             }
  752.             $listingManager $this->listingService;
  753.             $listingManager->saveListing($listing);
  754.             $listingEvent = new ListingEvent($listing);
  755.             $this->dispatcher->dispatch($listingEvent'aqarmap.listing.submitted');
  756.             return View::create()->setData($listing)->setStatusCode(Response::HTTP_OK);
  757.         }
  758.         return View::create()->setData($form)->setStatusCode(Response::HTTP_BAD_REQUEST);
  759.     }
  760.     /**
  761.      * Upload listing photos.
  762.      *
  763.      * @Operation(
  764.      *     tags={"Listing"},
  765.      *     summary="Upload listing photos.",
  766.      *
  767.      *     @OA\Parameter(
  768.      *         name="photos",
  769.      *          in="query",
  770.      *         description="",
  771.      *         required=false,
  772.      *     ),
  773.      *
  774.      *     @OA\Response(
  775.      *         response="201",
  776.      *         description="Returned when successfully created"
  777.      *     ),
  778.      *     @OA\Response(
  779.      *         response="400",
  780.      *         description="Returned when validation error"
  781.      *     )
  782.      * )
  783.      *
  784.      * @Rest\Post("/api/v2/listing/{id}/photos", options={"i18n" = false}, name="aqarmap_api_upload_listing_photos")
  785.      *
  786.      * @Security("is_granted('ROLE_OWNER', listing)")
  787.      *
  788.      * @return View|array
  789.      */
  790.     public function upload(Request $requestListing $listing)
  791.     {
  792.         $form $this->createForm(PhotoType::class, null, [
  793.             'csrf_protection' => false,
  794.         ]);
  795.         $form->handleRequest($request);
  796.         if ($form->isSubmitted() && $form->isValid()) {
  797.             $outputFiles = [];
  798.             $listingManager $this->listingService;
  799.             $maxOrder $listingManager->getMaxListingPhotoOrder($listing);
  800.             foreach ($form->get('file')->getData() as $index => $file) {
  801.                 $photo = new Photo();
  802.                 $photo->setFile($file);
  803.                 $listingPhoto = new ListingPhoto();
  804.                 $listingPhoto->setFile($photo);
  805.                 $listingPhoto->setCaption($photo->getFile()->getClientOriginalName());
  806.                 $listingPhoto->setOrder($maxOrder $index 1);
  807.                 $outputFiles[] = $listingPhoto;
  808.                 $listing->addPhoto($listingPhoto);
  809.             }
  810.             $listingEvent = new ListingEvent($listing);
  811.             $this->dispatcher->dispatch($listingEvent'aqarmap.listing.submitted');
  812.             $listingManager->saveListing($listing);
  813.             return View::create()->setData($outputFiles)->setStatusCode(Response::HTTP_CREATED);
  814.         }
  815.         return [
  816.             'listing' => $listing,
  817.             'form' => $form->createView(),
  818.         ];
  819.     }
  820.     /**
  821.      * Delete Listing entity.
  822.      *
  823.      * @Operation(
  824.      *     tags={"Listing"},
  825.      *     summary="Delete Listing entity.",
  826.      *
  827.      *     @OA\Response(
  828.      *         response="204",
  829.      *         description="Returned when successfully Deleted"
  830.      *     ),
  831.      *     @OA\Response(
  832.      *         response="404",
  833.      *         description="Returned when Listing is not found"
  834.      *     ),
  835.      *     @OA\Response(
  836.      *         response="403",
  837.      *         description="Returned when you are trying to remove listing that not yours."
  838.      *     )
  839.      * )
  840.      *
  841.      * @Rest\Delete("/api/v2/listing/{listing}", options={"i18n" = false}, name="aqarmap_api_delete_listing")
  842.      *
  843.      * @Security("is_granted('ROLE_OWNER', listing)")
  844.      */
  845.     public function delete(Listing $listing)
  846.     {
  847.         if (\in_array('ROLE_PREVENT_DELETE_LISTING'$this->getUser()->getRoles())) {
  848.             throw new AccessDeniedHttpException("Forbidden, user don't have this permession.");
  849.         }
  850.         $listingManager $this->listingService;
  851.         $listingManager->remove($listingListingStatus::USER_DELETED);
  852.         return new Response(nullResponse::HTTP_NO_CONTENT);
  853.     }
  854.     /**
  855.      * Undelete Listing entity.
  856.      *
  857.      * @Operation(
  858.      *     tags={"Listing"},
  859.      *     summary="Undelete Listing entity.",
  860.      *
  861.      *     @OA\Response(
  862.      *         response="200",
  863.      *         description="Returned when successfully undeleted"
  864.      *     ),
  865.      *     @OA\Response(
  866.      *         response="404",
  867.      *         description="Returned when Listing is not found or is not on user deleted state"
  868.      *     ),
  869.      *     @OA\Response(
  870.      *         response="403",
  871.      *         description="Returned when you are trying to remove listing that not yours."
  872.      *     )
  873.      * )
  874.      *
  875.      * @Rest\get("/api/v2/listing/{listing}/undelete", options={"i18n" = false}, name="aqarmap_api_undelete_listing")
  876.      *
  877.      * @Security("is_granted('ROLE_OWNER', listing)")
  878.      *
  879.      * @Rest\View()
  880.      *
  881.      * @return array
  882.      */
  883.     public function undelete(Listing $listing)
  884.     {
  885.         if (ListingStatus::USER_DELETED != $listing->getStatus()) {
  886.             throw $this->createNotFoundException('Unable to find this listing.');
  887.         }
  888.         $listingManager $this->listingService;
  889.         $listingManager->changeStatus($listingListingStatus::PENDING);
  890.         $listingEvent = new ListingEvent($listing);
  891.         $this->dispatcher->dispatch($listingEvent'aqarmap.listing.resubmitted');
  892.         return ['listing' => $listing];
  893.     }
  894.     /**
  895.      * Republish Listing entity.
  896.      *
  897.      * @Operation(
  898.      *     tags={"Listing"},
  899.      *     summary="Republish Listing entity.",
  900.      *
  901.      *     @OA\Response(
  902.      *         response="200",
  903.      *         description="Returned when successfully Republished"
  904.      *     ),
  905.      *     @OA\Response(
  906.      *         response="404",
  907.      *         description="Returned when Listing is not found or is not on Expired state"
  908.      *     ),
  909.      *     @OA\Response(
  910.      *         response="403",
  911.      *         description="Returned when you are trying to Republish listing that not yours."
  912.      *     )
  913.      * )
  914.      *
  915.      * @Rest\get("/api/v2/listing/{listing}/relist", options={"i18n" = false}, name="aqarmap_api_republish_listing")
  916.      *
  917.      * @Security("is_granted('ROLE_OWNER', listing)")
  918.      *
  919.      * @Rest\View()
  920.      *
  921.      * @return array
  922.      */
  923.     public function relist(Listing $listing)
  924.     {
  925.         if (ListingStatus::EXPIRED != $listing->getStatus()) {
  926.             throw $this->createNotFoundException('Unable to find this listing.');
  927.         }
  928.         $em $this->getDoctrine()->getManager();
  929.         $listingRepo $em->getRepository(Listing::class);
  930.         $relistChild $listingRepo->getRelistChild($listing);
  931.         // If the expired listing already republished before .. return the republished version.
  932.         if ($relistChild) {
  933.             return ['listing' => $relistChild];
  934.         }
  935.         $listingManager $this->listingService;
  936.         $listing $listingManager->relist($listing);
  937.         $listingEvent = new ListingEvent($listing);
  938.         $this->dispatcher->dispatch($listingEvent'aqarmap.listing.resubmitted');
  939.         return ['listing' => $listing];
  940.     }
  941.     /**
  942.      * Feature A Listing.
  943.      *
  944.      * @Operation(
  945.      *     tags={"Listing"},
  946.      *     summary="Remove listing from favourite",
  947.      *
  948.      * )
  949.      *
  950.      * @Rest\Post("/api/v2/listing/{listing}/feature", options={"i18n" = false}, name="aqarmap_api_feature_listing")
  951.      *
  952.      * @Rest\RequestParam(name="type", description="Feature Type, 1 for payment, 2 for making it featured")
  953.      *
  954.      * @Security("is_granted('ROLE_OWNER', listing)")
  955.      *
  956.      * @return View
  957.      */
  958.     public function feature(Listing $listingRequest $request)
  959.     {
  960.         $type $request->get('type');
  961.         if (!$type) {
  962.             throw new BadRequestHttpException('Please Specify the feature type');
  963.         }
  964.         $matcher $this->listingRuleMatcher;
  965.         $listingRule $matcher->match($listing);
  966.         $translator $this->translator;
  967.         $featuredDuration $listingRule['featured_duration'];
  968.         $featuredFees $listingRule['featured_fees'];
  969.         if (ListingFeatures::FEATURED == $type) {
  970.             // Check if there is a value for featured_duration & featured_fees
  971.             if (empty($featuredDuration) || empty($featuredFees)) {
  972.                 throw new LogicHttpException($translator->trans('Making a listing Featured is not available for this listing.', [], 'exceptions'));
  973.             }
  974.             try {
  975.                 $this->listingService->makeItFeatured(
  976.                     $listing,
  977.                     [
  978.                         'featuredFees' => $featuredFees,
  979.                         'featuredDuration' => $featuredDuration,
  980.                         'listingFeaturedType' => ListingFeaturedTypes::FEATURED,
  981.                         'listingFeature' => $type,
  982.                     ]
  983.                 );
  984.             } catch (\Exception $e) {
  985.                 throw new LogicHttpException($translator->trans($e->getMessage(), [], 'exceptions'));
  986.             }
  987.         } elseif (ListingFeatures::PAID == $type) {
  988.             /** @var \Aqarmap\Bundle\CreditBundle\Services\CreditManager $creditManager */
  989.             $creditManager $this->creditManager;
  990.             if ($listing->getPublicationCredit()) {
  991.                 throw new LogicHttpException($translator->trans('credit.already_paid'));
  992.             } elseif ($listingRule['publication_fees'] > $creditManager->getBalance($listing->getUser())) {
  993.                 throw new LogicHttpException($translator->trans('credit.not_enough_credits'));
  994.             }
  995.             // Subtract publication fees
  996.             $credits $creditManager->deduction($listing->getUser(), $listingRule['publication_fees'], 'Listing Fees'CreditStatus::PENDING);
  997.             foreach ($credits as $credit) {
  998.                 if ($credit instanceof Credit) {
  999.                     $this->listingService->addFeature($listingListingFeatures::PAIDnull$credit);
  1000.                 }
  1001.             }
  1002.             $listingEvent = new ListingEvent($listing);
  1003.             $this->dispatcher->dispatch($listingEvent'aqarmap.listing.submitted');
  1004.         }
  1005.         return View::create()->setData(['listing' => $listing]);
  1006.     }
  1007.     // -------------------------------------------------------------------------//
  1008.     // ++++++++++++++ Quick contact seller & call request Actions +++++++++++++++//
  1009.     // -------------------------------------------------------------------------//
  1010.     /**
  1011.      * @Operation(
  1012.      *     tags={"Listing"},
  1013.      *     summary="Returns Rules for a specific listing",
  1014.      *
  1015.      *     @OA\Response(
  1016.      *         response="404",
  1017.      *         description="Returned when the listing is not found"
  1018.      *     )
  1019.      * )
  1020.      *
  1021.      * @Rest\Post("/api/v2/listing/{listing}/quick_create_lead", options={"i18n" = false}, name="aqarmap_api_listing_quick_create_lead")
  1022.      *
  1023.      * @Rest\QueryParam(name="campaign", description="Campaign Name")
  1024.      * @Rest\QueryParam(name="country_code", default=null, description="Country Code")
  1025.      *
  1026.      * @Rest\View(serializerGroups={"Default", "Details"})
  1027.      *
  1028.      * @return bool|Form|array
  1029.      *
  1030.      * @throws AccessDeniedHttpException
  1031.      *
  1032.      * ===============================================================
  1033.      * |
  1034.      * | DEPRECATED: USE QuickCreateLeadAction::LeadController instead
  1035.      * |
  1036.      * ===============================================================
  1037.      */
  1038.     public function quickCreateLead(Request $requestListing $listing)
  1039.     {
  1040.         $form $this->createForm(QuickCreateLeadFormType::class, null, [
  1041.             'method' => 'POST',
  1042.             'csrf_protection' => false,
  1043.         ]);
  1044.         $form->handleRequest($request);
  1045.         if ($form->isSubmitted() && $form->isValid()) {
  1046.             $lead $form->getData();
  1047.             /** @var $userManager \FOS\UserBundle\Model\UserManagerInterface */
  1048.             $userManager $this->fosUserManager;
  1049.             $leadModel = new LeadModel();
  1050.             try {
  1051.                 /** @var User $user */
  1052.                 if ($user $userManager->findUserByEmail($form->get('email')->getData())) {
  1053.                     $phone $this->phoneManager->addNewUserPhone(
  1054.                         $lead['phoneNumber'],
  1055.                         '+'.str_replace(' '''$request->get('country_code')),
  1056.                         $user,
  1057.                         true,
  1058.                         true,
  1059.                         CountryCodes::getCountryFromCodeNumber('+'.str_replace(' '''$request->get('country_code'))),
  1060.                         $lead['phoneNumber']
  1061.                     );
  1062.                     $userManager->updateUser($user);
  1063.                     $leadModel->setUser($user);
  1064.                 } else {
  1065.                     $user $userManager->createUser();
  1066.                     $user
  1067.                         ->setFullName($lead['fullName'])
  1068.                         ->setEmail($lead['email'])
  1069.                         ->setLanguage($request->getLocale());
  1070.                     $user $this->userManager->quickRegistration($form$user$request);
  1071.                     $phone $this->phoneManager->addNewUserPhone(
  1072.                         $lead['phoneNumber'],
  1073.                         '+'.str_replace(' '''$request->get('country_code')),
  1074.                         $user,
  1075.                         true,
  1076.                         true,
  1077.                         CountryCodes::getCountryFromCodeNumber('+'.str_replace(' '''$request->get('country_code'))),
  1078.                         $lead['phoneNumber']
  1079.                     );
  1080.                     $userManager->reloadUser($user);
  1081.                     $leadModel->setUser($user);
  1082.                 }
  1083.             } catch (\Exception $e) {
  1084.                 return [
  1085.                     'status' => 'error',
  1086.                     'message' => 'Cannot create a user.',
  1087.                 ];
  1088.             }
  1089.             if ($user) {
  1090.                 try {
  1091.                     $leadModel->setEmail($lead['email']);
  1092.                     $leadModel->setName($lead['fullName']);
  1093.                     $leadModel->setPhone($phone->getPhone());
  1094.                     $leadModel->setCampaign($request->request->get('campaign'));
  1095.                     $leadModel->setMessage($form->get('message')->getData());
  1096.                     $leadModel->setListing($listing);
  1097.                     $this->listingService->quickCreateLead($leadModel);
  1098.                     return [
  1099.                         'status' => 'ok',
  1100.                     ];
  1101.                 } catch (\Exception $e) {
  1102.                     return [
  1103.                         'status' => 'error',
  1104.                         'message' => 'Cannot create the lead.',
  1105.                     ];
  1106.                 }
  1107.             }
  1108.         }
  1109.         return $form;
  1110.     }
  1111.     /**
  1112.      * Get Listing Rules.
  1113.      *
  1114.      * @Operation(
  1115.      *     tags={"Listing"},
  1116.      *     summary="Returns a Note for a specific listing",
  1117.      *
  1118.      *     @OA\Response(
  1119.      *         response="404",
  1120.      *         description="Returned when the listing is not found"
  1121.      *     )
  1122.      * )
  1123.      *
  1124.      * @Rest\Get("/api/v2/listing/{id}/rules", options={"i18n" = false}, name="aqarmap_api_get_listing_rules")
  1125.      *
  1126.      * @Security("is_granted('ROLE_OWNER', listing)")
  1127.      *
  1128.      * @Rest\View()
  1129.      *
  1130.      * @return array
  1131.      */
  1132.     public function getListingRules(Listing $listing)
  1133.     {
  1134.         $listingMatcher $this->listingRuleMatcher;
  1135.         $rules $listingMatcher->match($listing);
  1136.         return ['rules' => $rules];
  1137.     }
  1138.     /**
  1139.      * Get Listing Note.
  1140.      *
  1141.      * @Operation(
  1142.      *     tags={"Listing"},
  1143.      *     summary="Returns a Listing",
  1144.      *
  1145.      *     @OA\Parameter(
  1146.      *         name="propertyType",
  1147.      *          in="query",
  1148.      *         description="propertyType of the unites",
  1149.      *         required=false,
  1150.      *     ),
  1151.      *     @OA\Parameter(
  1152.      *         name="section",
  1153.      *          in="query",
  1154.      *         description="Section of the unites",
  1155.      *         required=false,
  1156.      *     ),
  1157.      *
  1158.      *     @OA\Response(
  1159.      *         response="404",
  1160.      *         description="Returned when the listing is not found"
  1161.      *     )
  1162.      * )
  1163.      *
  1164.      * @Rest\Get("/api/v2/listing/{id}/note", options={"i18n" = false}, name="aqarmap_api_get_listing_note")
  1165.      *
  1166.      * @Security("is_granted('ROLE_USER')")
  1167.      *
  1168.      * @Rest\View()
  1169.      *
  1170.      * @return array
  1171.      */
  1172.     public function getListingNote(Listing $listing)
  1173.     {
  1174.         /** @var EntityManager $em */
  1175.         $em $this->getDoctrine()->getManager();
  1176.         $listingNoteRepo $em->getRepository(ListingNote::class);
  1177.         return $listingNoteRepo->findOneBy([
  1178.             'user' => $this->getUser(),
  1179.             'listing' => $listing,
  1180.         ]);
  1181.     }
  1182.     /**
  1183.      * Get account statistics (Listings Statistics).
  1184.      *
  1185.      * @Operation(
  1186.      *     tags={"User"},
  1187.      *     summary="Get account statistics (Listings Statistics).",
  1188.      *
  1189.      * )
  1190.      *
  1191.      * @Rest\Get("/api/user/listings/statistics", requirements={"id":"\d+"}, options={"expose" = true, "i18n" = false}, name="aqarmap_api_get_user_listings_rates_counts")
  1192.      *
  1193.      * @Rest\Post("/api/v2/user/listings/statistics", options={"i18n" = false}, name="aqarmap_api_get_user_listings_rates_counts_v2")
  1194.      *
  1195.      * @ParamConverter("user", options={"mapping": {"user": "id"}}, isOptional="true", converter="querystring")
  1196.      *
  1197.      * @Rest\View(serializerGroups={"Default", "Details"})
  1198.      *
  1199.      * @Security("is_granted('ROLE_USER')")
  1200.      *
  1201.      * @throws \Exception
  1202.      */
  1203.     public function getUserListingsRatesCounts(Request $request, ?User $user null): View
  1204.     {
  1205.         $isSubAccount null != $user && $this->getUser() === $user->getParent();
  1206.         $startDate null;
  1207.         $period $request->query->get('period'null);
  1208.         if (!$this->getUser() && !$isSubAccount) {
  1209.             throw new AccessDeniedHttpException();
  1210.         }
  1211.         $user $user ?: $this->getUser();
  1212.         if ('7Days' == $period) {
  1213.             $startDate date('Y-m-d'strtotime('-7 days'));
  1214.         } elseif ('30Days' == $period) {
  1215.             $startDate date('Y-m-d'strtotime('-30 days'));
  1216.         }
  1217.         return $this->respond([
  1218.             'rates' => $this->listingService->getUserListingsRatesCounts($user$startDate$period),
  1219.         ]);
  1220.     }
  1221.     /**
  1222.      * Generates XML file for Listings News feed for marketing purpose.
  1223.      *
  1224.      * @Operation(
  1225.      *     tags={"Listing"},
  1226.      *     summary="Generates XML file for Listings News feed for marketing purpose.",
  1227.      *
  1228.      * )
  1229.      *
  1230.      * @Rest\Get(
  1231.      *     "/api/listings/feed/{platform}",
  1232.      *     options={"expose" = true, "i18n" = false},
  1233.      *     name="aqarmap_api_get_listings_news_feed",
  1234.      *     defaults={"page"=1}
  1235.      * )
  1236.      *
  1237.      * @Rest\View(serializerGroups={"Default", "Details"})
  1238.      *
  1239.      * @return Response
  1240.      */
  1241.     public function getNewsFeed($platformRequest $request)
  1242.     {
  1243.         $criteria = [];
  1244.         $page min($request->query->get('page') ?: 1ListingNewsFeed::MAX_PAGES);
  1245.         $limit min($request->query->get('limit'100), 100);
  1246.         if ((int) $request->query->get('page'1) > $page) {
  1247.             throw new NotFoundHttpException('Exceeded maximum number of pages');
  1248.         }
  1249.         if ($request->query->get('ugc')) {
  1250.             $data explode(','$request->query->get('ugc'));
  1251.             $data array_map('intval'$data);
  1252.             $criteria['groupCategory'] = array_filter($data);
  1253.         }
  1254.         if ($request->query->get('ug')) {
  1255.             $data explode(','$request->query->get('ug'));
  1256.             $data array_map('intval'$data);
  1257.             $criteria['userGroup'] = array_filter($data);
  1258.         }
  1259.         if ($request->query->get('hl')) {
  1260.             $criteria['locale'] = $request->query->get('hl');
  1261.         }
  1262.         if ($request->query->get('maxlead')) {
  1263.             $criteria['maxlead'] = $request->query->get('maxlead');
  1264.         }
  1265.         if ($request->query->get('feat')) {
  1266.             $criteria['feat'] = $request->query->get('feat');
  1267.         }
  1268.         if ($request->query->get('location')) {
  1269.             $locations $this->locationManager
  1270.                 ->buildLocationsArrayByParentId($request->query->get('location'));
  1271.             if (!empty($locations)) {
  1272.                 $criteria['locations'] = $locations;
  1273.             }
  1274.         }
  1275.         if ($request->query->get('section')) {
  1276.             $data explode(','$request->query->get('section'));
  1277.             $data array_map('intval'$data);
  1278.             $criteria['sections'] = array_filter($data);
  1279.         }
  1280.         $news $this->listingNewsFeed;
  1281.         $offset = ($page 1) * $limit;
  1282.         $excludedKeys = ['sections''maxlead'];
  1283.         if (!array_diff(array_keys($criteria), $excludedKeys)) {
  1284.             throw new BadRequestHttpException(sprintf('The request must contain parameters others than the following: %s'implode(', '$excludedKeys)));
  1285.         }
  1286.         if ('json' == $request->query->get('format')) {
  1287.             return $this->responseJson($news->asJson($offset$limit$criteria));
  1288.         }
  1289.         return $this->responseXml($news->asXml($offset$limit$platform$criteria));
  1290.     }
  1291.     /**
  1292.      * Get call log.
  1293.      *
  1294.      * @deprecated
  1295.      *
  1296.      * @Operation(
  1297.      *     tags={"Listing"},
  1298.      *     summary="Get call log.",
  1299.      *
  1300.      * )
  1301.      *
  1302.      * @Rest\Get(
  1303.      *     "/api/listings/calllog",
  1304.      *     options={"expose" = true, "i18n" = false},
  1305.      *     name="aqarmap_api_get_listings_calllog"
  1306.      * )
  1307.      *
  1308.      * @Rest\View(serializerGroups={"CallLog"})
  1309.      *
  1310.      * @return Response
  1311.      */
  1312.     public function getCallLog(Request $request)
  1313.     {
  1314.         $this->translatableListener->setTranslatableLocale($request->get('lang'));
  1315.         $em $this->getDoctrine()->getManager();
  1316.         $listings $em
  1317.             ->getRepository(Listing::class)
  1318.             ->getByIds($this->logger->get());
  1319.         return View::create()->setData($listings);
  1320.     }
  1321.     /**
  1322.      * Remove call log.
  1323.      *
  1324.      * @Operation(
  1325.      *     tags={"Listing"},
  1326.      *     summary="Remove call log.",
  1327.      *
  1328.      * )
  1329.      *
  1330.      * @Rest\Post(
  1331.      *     "/api/listings/calllog",
  1332.      *     options={"expose" = true, "i18n" = false},
  1333.      *     name="aqarmap_api_remove_listings_calllog"
  1334.      * )
  1335.      *
  1336.      * @Rest\View
  1337.      *
  1338.      * @return Response
  1339.      */
  1340.     public function removeCallLog()
  1341.     {
  1342.         $this->logger->remove();
  1343.         return View::create()->setData([]);
  1344.     }
  1345.     /**
  1346.      * update listing fields.
  1347.      *
  1348.      * @Rest\Post("api/listing/{id}/edit", options={"i18n" = false, "expose" = true}, name="update_listing_field")
  1349.      *
  1350.      * @Rest\View(serializerGroups={"Default", "Details"})
  1351.      *
  1352.      * @Security("is_granted('ROLE_EDIT_REVIEW_LISTINGS')")
  1353.      *
  1354.      * @return View
  1355.      */
  1356.     public function update(Listing $listingRequest $request)
  1357.     {
  1358.         $listingManager $this->listingManager;
  1359.         $isEnabled $this->featureToggle
  1360.             ->isEnabled('web.mortgage.options');
  1361.         $mortgage $request->get('eligibleForMortgage');
  1362.         $fields $request->request->all();
  1363.         if ($isEnabled) {
  1364.             if (true == $mortgage) {
  1365.                 $this->mortgageService->addEligibleMortgageTypes($listing);
  1366.             } else {
  1367.                 $listingManager->setEligibleMortgageToNull($listing);
  1368.             }
  1369.             unset($fields['eligibleForMortgage']);
  1370.         }
  1371.         $this->dispatcher->dispatch(
  1372.             new ListingUpdatedEvent($listing$fields),
  1373.             ListingUpdatedEvent::UPDATED
  1374.         );
  1375.         $listing $listingManager->update($listing$fields);
  1376.         if ($listing->getStatus() == ListingStatus::LIVE){
  1377.             $listingManager->changeStatus($listingListingStatus::PENDING);
  1378.         }
  1379.         return $this->respond([
  1380.             'listing' => $listing,
  1381.             'msg' => 'Listing was updated successfully',
  1382.         ]);
  1383.     }
  1384.     /**
  1385.      * Get Photos Of The Given Listings.
  1386.      *
  1387.      * @Operation(
  1388.      *     tags={"Listing"},
  1389.      *     summary="Get Photos Of The Given Listings.",
  1390.      *
  1391.      * )
  1392.      *
  1393.      * @Rest\Get(
  1394.      *     "/api/listings/{listing}/photos",
  1395.      *     options={"expose" = true, "i18n" = false},
  1396.      *     name="aqarmap_api_get_listing_photos",
  1397.      * )
  1398.      *
  1399.      * @return Response
  1400.      */
  1401.     public function getListingPhotos(Listing $listing)
  1402.     {
  1403.         $listingPhotos $listing->getPhotos();
  1404.         $listingPhotosData = [];
  1405.         foreach ($listingPhotos as $listingPhoto) {
  1406.             $listingPhotosData[] = [
  1407.                 'id' => $listingPhoto->getId(),
  1408.                 'type' => $listingPhoto->getType(),
  1409.                 'caption' => $listingPhoto->getCaption(),
  1410.                 'file' => $listingPhoto->getFile(),
  1411.             ];
  1412.         }
  1413.         return $this->respond($listingPhotosData);
  1414.     }
  1415.     /**
  1416.      * Get Photo Types.
  1417.      *
  1418.      * @Operation(
  1419.      *     tags={"Listing"},
  1420.      *     summary="Get Photo Types.",
  1421.      *
  1422.      * )
  1423.      *
  1424.      * @Rest\Get(
  1425.      *     "/api/listings/photoTypes",
  1426.      *     options={"expose" = true, "i18n" = false},
  1427.      *     name="aqarmap_api_get_listing_photo_types",
  1428.      * )
  1429.      *
  1430.      * @return Response
  1431.      */
  1432.     public function getPhotoTypes()
  1433.     {
  1434.         return $this->respond(PhotoTypes::getPhotoTypes());
  1435.     }
  1436.     /**
  1437.      * Upload Listing Photo.
  1438.      *
  1439.      * @Operation(
  1440.      *     tags={"Listing"},
  1441.      *     summary="Upload Listing Photo.",
  1442.      *
  1443.      * )
  1444.      *
  1445.      * @Rest\Post(
  1446.      *     "/api/listing/{id}/upload_photo",
  1447.      *     options={"expose" = true, "i18n" = false},
  1448.      *     name="aqarmap_api_admin_upload_listing_photo",
  1449.      * )
  1450.      *
  1451.      * @return array
  1452.      *
  1453.      * @throws OptimisticLockException
  1454.      */
  1455.     public function uploadListingPhoto(Listing $listing)
  1456.     {
  1457.         $outputFiles = [];
  1458.         $listingManager $this->listingManager;
  1459.         $maxOrder $listingManager->getMaxListingPhotoOrder($listing);
  1460.         $photo = new Photo();
  1461.         $file $_FILES['file'];
  1462.         $file = new UploadedFile($file['tmp_name'], $file['name'], $file['type']);
  1463.         $photo->setFile($file);
  1464.         $listingPhoto = new ListingPhoto();
  1465.         $listingPhoto->setFile($photo);
  1466.         $listingPhoto->setCaption($photo->getFile()->getClientOriginalName());
  1467.         $listingPhoto->setOrder($maxOrder 1);
  1468.         $outputFiles[] = $listingPhoto;
  1469.         $listing->addPhoto($listingPhoto);
  1470.         $em $this->getDoctrine()->getManager();
  1471.         $em->persist($listing);
  1472.         $em->flush();
  1473.         return $this->respond(['status' => 'OK']);
  1474.     }
  1475.     /**
  1476.      * Gets rate details of listing.
  1477.      *
  1478.      * @Operation(
  1479.      *     tags={"Listing"},
  1480.      *     summary="Gets rate details of listing.",
  1481.      *
  1482.      * )
  1483.      *
  1484.      * @Rest\Get("/api/v2/listing/{listing}/rates", options={"i18n" = false})
  1485.      * @Rest\Get("/api/listing/{listing}/rates", options={"expose" = true, "i18n" = false}, name="aqarmap_api_listing_rates_details")
  1486.      *
  1487.      * @Rest\View(serializerGroups={"Rates"})
  1488.      *
  1489.      * @Cache(
  1490.      *   expires="+1 week",
  1491.      *   maxage="+1 week",
  1492.      *   smaxage="+1 week",
  1493.      *   public=false,
  1494.      *   vary={"Accept-Language",
  1495.      *   "X-Accept-Version", "Accept"}
  1496.      * )
  1497.      */
  1498.     public function getRateDetails(Listing $listing)
  1499.     {
  1500.         return $this->respond(
  1501.             current($this->listingRateService->getRatesDetails([$listing]))
  1502.         );
  1503.     }
  1504.     /**
  1505.      * @Operation(
  1506.      *     tags={"Listing"},
  1507.      *     summary="",
  1508.      *
  1509.      * )
  1510.      *
  1511.      * @Rest\Get("/api/v2/listing/{listing}/preview", options={"i18n" = false})
  1512.      * @Rest\Get("/api/listing/{listing}/preview", options={"expose" = true, "i18n" = false}, name="aqarmap_api_listing_preview_data")
  1513.      *
  1514.      * @Rest\View(serializerGroups={"Preview"})
  1515.      *
  1516.      * @return View
  1517.      */
  1518.     public function getListingPreviewData(Listing $listing)
  1519.     {
  1520.         return $this->respond($listing);
  1521.     }
  1522.     /**
  1523.      * @Operation(
  1524.      *     tags={"Lead"},
  1525.      *     summary="Return Lead Distribution Analytics",
  1526.      *
  1527.      * )
  1528.      *
  1529.      * @Rest\Get("/api/listing/{listing}/lead-analytics",
  1530.      * options={"i18n"=false, "expose"=true},
  1531.      * name="aqarmap_api_listing_lead_analytics")
  1532.      *
  1533.      * @return JsonResponse
  1534.      *
  1535.      * @throws \Exception
  1536.      */
  1537.     public function getLeadAnalytics(Listing $listing)
  1538.     {
  1539.         $analytics $this->listingService->getLeadAnalytics($listing);
  1540.         return $this->respond($analytics);
  1541.     }
  1542.     /**
  1543.      * @Operation(
  1544.      *     tags={"Listing"},
  1545.      *     summary="Remove listing from favourite",
  1546.      *
  1547.      * )
  1548.      *
  1549.      * @Rest\Delete("/api/v2/listing/{listing}/favourite", options={"i18n" = false})
  1550.      * @Rest\Delete("/api/listing/{listing}/favourite", options={"i18n" = false, "expose" = true}, name="aqarmap_api_remove_favourite_listing")
  1551.      *
  1552.      * @Security("is_granted('ROLE_USER')")
  1553.      *
  1554.      * @return string
  1555.      */
  1556.     public function deleteFavourite(Request $request)
  1557.     {
  1558.         $this->favouriteService->deleteByListing($request->attributes->get('listing'));
  1559.         return $this->respond('Favourite Deleted Successfully!');
  1560.     }
  1561.     /**
  1562.      * @Operation(
  1563.      *     tags={"Listing"},
  1564.      *     summary="Remove listing note",
  1565.      *
  1566.      * )
  1567.      *
  1568.      * @Rest\Delete("/api/v2/listing/{listing}/note", options={"i18n" = false})
  1569.      * @Rest\Delete("/api/listing/{listing}/note", options={"i18n" = false, "expose" = true}, name="aqarmap_api_remove_listing_note")
  1570.      *
  1571.      * @Security("is_granted('ROLE_USER')")
  1572.      *
  1573.      * @return string
  1574.      */
  1575.     public function deleteNote(Request $request)
  1576.     {
  1577.         $this->listingNoteService->deleteByListing($request->attributes->get('listing'));
  1578.         return $this->respond('Note Deleted Successfully!');
  1579.     }
  1580.     /**
  1581.      * @Operation(
  1582.      *     tags={"Listing"},
  1583.      *     summary="Change listing rate review",
  1584.      *
  1585.      * )
  1586.      *
  1587.      * @Rest\Post("/api/listing/{listing}/rate-review", options={"i18n" = false, "expose" = true}, name="aqarmap_api_change_listing_rate_review_status")
  1588.      *
  1589.      * @Security("is_granted('ROLE_ADMIN')")
  1590.      *
  1591.      * @return string
  1592.      */
  1593.     public function rateReview(Request $requestListing $listing)
  1594.     {
  1595.         $this->listingService->updateIsRateReviewed($listing$request->request->get('isReviewed'));
  1596.         return $this->respond('Listing rate review status changed successfully');
  1597.     }
  1598.     /**
  1599.      * Get Similar Listings Count.
  1600.      *
  1601.      * @Operation(
  1602.      *     tags={"Listing"},
  1603.      *     summary="Returns a Listing Count",
  1604.      *
  1605.      *     @OA\Response(
  1606.      *         response="404",
  1607.      *         description="Returned when the listing is not found"
  1608.      *     )
  1609.      * )
  1610.      *
  1611.      * @Rest\Get("/api/listing/{id}/similar_listings_count", options={"i18n" = false, "expose" = true}, name="aqarmap_api_get_similar_listings_count")
  1612.      *
  1613.      * @Rest\View(serializerGroups={"Default", "Details"})
  1614.      */
  1615.     public function getSimilarListingsCount(Listing $listing): int
  1616.     {
  1617.         $listingManager $this->listingService;
  1618.         try {
  1619.             $count $listingManager->countSimilarListings($listing);
  1620.         } catch (\Exception $exception) {
  1621.             echo $exception->getMessage();
  1622.             $this->errorLogger->error(shell_exec("Error retriving similar listings count! {$exception->getMessage()}"));
  1623.             $count 0;
  1624.         }
  1625.         return $count;
  1626.     }
  1627.     /**
  1628.      * ApiDoc(
  1629.      *   resource = true,
  1630.      *   section = "Listing",
  1631.      *   description="Get Listings Objects with notes",
  1632.      *   statusCodes={
  1633.      *       200="Returned when successful",
  1634.      *   }
  1635.      * ).
  1636.      *
  1637.      * @Rest\Get("/api/v2/listings/notes", options={"i18n" = false})
  1638.      * @Rest\Get("/api/listings/notes", options={"i18n" = false, "expose" = true}, name="aqarmap_api_listing_notes_and_favourites")
  1639.      *
  1640.      * @Rest\QueryParam(name="from", description="[favourites|notes]")
  1641.      *
  1642.      * @Rest\View(serializerGroups={"Default", "List"})
  1643.      * )
  1644.      *
  1645.      * @return array
  1646.      */
  1647.     public function getListingsWithNotes(Request $request)
  1648.     {
  1649.         $listingsIdWithNotes = [];
  1650.         if ($content $request->getContent()) {
  1651.             $listingsIdWithNotes json_decode($contenttrue);
  1652.         }
  1653.         $listings $this->getDoctrine()->getRepository(Listing::class)
  1654.             ->getByIdsQuery(array_column($listingsIdWithNotes'listingId'));
  1655.         $pagination $this->paginator->paginate(
  1656.             $listings,
  1657.             $request->query->get('page'1),
  1658.             $request->query->get('limit'10)
  1659.         );
  1660.         $data $this->listingService->setStaticNotesFromPaginator($pagination$listingsIdWithNotes);
  1661.         if ('favourites' == $request->query->get('from')) {
  1662.             return ['favourite' => $data];
  1663.         }
  1664.         return ['note' => $data];
  1665.     }
  1666.     /**
  1667.      * ApiDoc(
  1668.      *   resource = true,
  1669.      *   section = "Listing",
  1670.      *   description="Get ApprovalRejectionWaitingTime",
  1671.      *   statusCodes={
  1672.      *       200="Returned when successful",
  1673.      *   }
  1674.      * ).
  1675.      *
  1676.      * @Rest\Get("/api/listing/arwt", options={"i18n" = false, "expose" = true}, name="aqarmap_api_listing_arwt")
  1677.      *
  1678.      * @Rest\View()
  1679.      * )
  1680.      *
  1681.      * @return array
  1682.      *
  1683.      * @throws \Exception
  1684.      */
  1685.     public function getApprovalRejectionWaitingTime(Request $request)
  1686.     {
  1687.         $criteria array_merge(
  1688.             $request->query->all(),
  1689.             ['actionTime' => true]
  1690.         );
  1691.         $listingManager $this->listingService;
  1692.         $listingExtension $this->listingExtension;
  1693.         return [
  1694.             'arwt' => $listingExtension->waited($listingManager->getApprovalRejectionWaitingTime($criteria)),
  1695.         ];
  1696.     }
  1697.     /**
  1698.      * filter Listing Children with property type (Project Units).
  1699.      *
  1700.      * @Operation(
  1701.      *     tags={"Listing"},
  1702.      *     summary="Returns a Listing Children",
  1703.      *
  1704.      *     @OA\Parameter(
  1705.      *         name="propertyType",
  1706.      *         in="query",
  1707.      *         description="propertyType of the unites",
  1708.      *         required=false,
  1709.      *     ),
  1710.      *
  1711.      *     @OA\Response(
  1712.      *         response="404",
  1713.      *         description="Returned when the listing is not found"
  1714.      *     )
  1715.      * )
  1716.      *
  1717.      * @Rest\Get("/api/listing/{id}/children", options={"i18n" = false}, name="aqarmap_api_get_listing_children")
  1718.      *
  1719.      * @Rest\QueryParam(name="propertyType", description="propertyType of the unites")
  1720.      *
  1721.      * @ParamConverter("propertyType", options={"mapping": {"propertyType": "id"}}, isOptional="true", converter="querystring")
  1722.      *
  1723.      * @Rest\View(serializerGroups={"UnitDetails"})
  1724.      *
  1725.      * @return array
  1726.      */
  1727.     public function filterListingChildren(Listing $listing, ?PropertyType $propertyType null): View
  1728.     {
  1729.         if (!$this->getUser()) {
  1730.             throw new AccessDeniedHttpException();
  1731.         }
  1732.         return $this->respond($listing->getLiveChildren($propertyType));
  1733.     }
  1734.     /**
  1735.      * Api for clonning listing.
  1736.      *
  1737.      * @Operation(
  1738.      *     tags={"Listing"},
  1739.      *     summary="Returns a Listing",
  1740.      *
  1741.      *     @OA\Parameter(
  1742.      *         name="propertyType",
  1743.      *          in="query",
  1744.      *         description="propertyType of the unites",
  1745.      *         required=false,
  1746.      *     ),
  1747.      *     @OA\Parameter(
  1748.      *         name="section",
  1749.      *          in="query",
  1750.      *         description="Section of the unites",
  1751.      *         required=false,
  1752.      *     ),
  1753.      *
  1754.      *     @OA\Response(
  1755.      *         response="404",
  1756.      *         description="Returned when the listing is not found"
  1757.      *     )
  1758.      * )
  1759.      *
  1760.      * @Rest\Post("/api/listing/{id}/clone", options={"i18n" = false}, name="aqarmap_api_clone_listing_children")
  1761.      * @Rest\Post("/api/v2/listing/{id}/clone", options={"i18n" = false}, name="aqarmap_api_v2_clone_listing_children")
  1762.      *
  1763.      * @Rest\RequestParam(name="propertyType", description="propertyType of the unites")
  1764.      * @Rest\RequestParam(name="section", description="Section of the unites")
  1765.      *
  1766.      * @ParamConverter("propertyType", options={"mapping": {"propertyType": "id"}}, converter="querystring")
  1767.      * @ParamConverter("section", options={"mapping": {"section": "id"}}, converter="querystring")
  1768.      *
  1769.      * @Security("is_granted('IS_AUTHENTICATED_REMEMBERED')")
  1770.      *
  1771.      * @Rest\View(serializerGroups={"UnitDetails"})
  1772.      */
  1773.     public function cloneListing(Listing $sourceListingPropertyType $propertyTypeSection $section): View
  1774.     {
  1775.         $syncedFields $sourceListing->getParent() ? ListingSyncedFields::UNIT_FIELDS ListingSyncedFields::PARENT_FIELDS;
  1776.         try {
  1777.             $listing $this->listingManager->initializeListingForCloning($sourceListing$propertyType$section$this->getUser());
  1778.             $this->listingManager->syncListingForProject(
  1779.                 [
  1780.                     'targetListingId' => $listing->getId(),
  1781.                     'sourceListingId' => $sourceListing->getId(),
  1782.                     'syncedFields' => $syncedFields,
  1783.                     'targetListingSavedAt' => $listing->getUpdatedAt()->getTimestamp(),
  1784.                 ]
  1785.             );
  1786.             return $this->respond($listing->getId());
  1787.         } catch (\Exception $e) {
  1788.             throw new \Exception('something went wrong');
  1789.         }
  1790.     }
  1791.     /**
  1792.      * @Rest\Get("/api/v2/listing/{listing}/top-seller", options={"i18n" = false}, name="aqarmap_api_listing_top_seller")
  1793.      *
  1794.      * @Rest\View(serializerGroups={"TopCustomers"})
  1795.      */
  1796.     public function getListingTopSeller(Listing $listingTopSellerRetrievalService $topSellerRetrievalService)
  1797.     {
  1798.         $topSeller = new TopSeller();
  1799.         $topSeller->setLocation($listing->getLocation()->getId());
  1800.         $topSeller->setSection($listing->getSection()->getId());
  1801.         $topSeller->setPropertyType($listing->getPropertyType()->getId());
  1802.         return $topSellerRetrievalService->getTopSellerPersonalData($topSeller);
  1803.     }
  1804.     /**
  1805.      * @Rest\Get("/api/v2/listing/{listing}/related-listings", options={"i18n" = false}, name="aqarmap_api_listing_related_listings")
  1806.      *
  1807.      * @Cache(expires="+1 days", maxage="+1 days", smaxage="+1 days", public=true, vary={"Accept-Language", "X-Accept-Version", "Accept"})
  1808.      *
  1809.      * @Rest\View(serializerGroups={"RelatedListingsV2"})
  1810.      */
  1811.     public function getRelatedListing(Listing $listingListingManager $listingManagerListingRepository $listingRepository)
  1812.     {
  1813.         try {
  1814.             $relatedListingsElasticResponse $listingManager->getRelatedListingsElasticResponse($listing);
  1815.             $listingsQueryBuilder $listingRepository->getListingsByIds(array_column($relatedListingsElasticResponse['items'], 'id'));
  1816.             return $listingsQueryBuilder->getQuery()->getResult();
  1817.         } catch (\Exception $exception) {
  1818.             throw new \Exception('something went wrong');
  1819.         }
  1820.     }
  1821.     /**
  1822.      * @Operation(
  1823.      *     tags={"Views"},
  1824.      *     summary="Add listing views",
  1825.      *
  1826.      * )
  1827.      *
  1828.      * @Rest\Post("/api/v2/listing/{id}/views", options={"i18n" = false, "expose"=true}, requirements={"id"="\d+"}, name="aqarmap_api_add_listing_views")
  1829.      *
  1830.      * @Rest\View()
  1831.      */
  1832.     public function increaseListingViews(Listing $listing): array
  1833.     {
  1834.         try {
  1835.             $this->interactionService->increaseViews($listing$this->getUser());
  1836.             return [
  1837.                 'status' => 'ok',
  1838.                 'message' => 'Views Created Successfully!',
  1839.             ];
  1840.         } catch (\Exception $exception) {
  1841.             throw new \Exception('something went wrong');
  1842.         }
  1843.     }
  1844. }