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

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