<?php
namespace Aqarmap\Bundle\ListingBundle\Controller;
use App\Exception\LogicHttpException;
use Aqarmap\Bundle\CreditBundle\Constant\CreditStatus;
use Aqarmap\Bundle\CreditBundle\Entity\Credit;
use Aqarmap\Bundle\CreditBundle\Services\CreditManager;
use Aqarmap\Bundle\FeatureToggleBundle\Service\FeatureToggleManager;
use Aqarmap\Bundle\FinancialAidsBundle\Service\FinancialAidService;
use Aqarmap\Bundle\ListingBundle\Constant\LeadTypes;
use Aqarmap\Bundle\ListingBundle\Constant\ListingCategories;
use Aqarmap\Bundle\ListingBundle\Constant\ListingFeaturedTypes;
use Aqarmap\Bundle\ListingBundle\Constant\ListingFeatures;
use Aqarmap\Bundle\ListingBundle\Constant\ListingSections;
use Aqarmap\Bundle\ListingBundle\Constant\ListingSellerRoles;
use Aqarmap\Bundle\ListingBundle\Constant\ListingSource;
use Aqarmap\Bundle\ListingBundle\Constant\ListingStatus;
use Aqarmap\Bundle\ListingBundle\Constant\PropertyRegistrationStatusOption;
use Aqarmap\Bundle\ListingBundle\Constant\ResaleListingsConstant;
use Aqarmap\Bundle\ListingBundle\Contracts\PhoneManagerInterface;
use Aqarmap\Bundle\ListingBundle\Contracts\RelatedResultServiceInterface;
use Aqarmap\Bundle\ListingBundle\Entity\CallRequest;
use Aqarmap\Bundle\ListingBundle\Entity\Listing;
use Aqarmap\Bundle\ListingBundle\Entity\ListingPhone;
use Aqarmap\Bundle\ListingBundle\Entity\Phone;
use Aqarmap\Bundle\ListingBundle\Entity\Section;
use Aqarmap\Bundle\ListingBundle\Event\ListingEvent;
use Aqarmap\Bundle\ListingBundle\Exception\InvalidLeadValidationHttpException;
use Aqarmap\Bundle\ListingBundle\Form\AdvancedFilterType;
use Aqarmap\Bundle\ListingBundle\Form\AdvancedSearchType;
use Aqarmap\Bundle\ListingBundle\Form\CallRequestFormType;
use Aqarmap\Bundle\ListingBundle\Form\ContactSellerFormType;
use Aqarmap\Bundle\ListingBundle\Form\ContactSellerWideFormType;
use Aqarmap\Bundle\ListingBundle\Form\LandingPageFormType;
use Aqarmap\Bundle\ListingBundle\Form\ListingInitializeType;
use Aqarmap\Bundle\ListingBundle\Form\ListingType;
use Aqarmap\Bundle\ListingBundle\Form\LiteListingType;
use Aqarmap\Bundle\ListingBundle\Form\Model\LandingPage;
use Aqarmap\Bundle\ListingBundle\Form\MultipleSearchFormType;
use Aqarmap\Bundle\ListingBundle\Form\PhotoType;
use Aqarmap\Bundle\ListingBundle\Form\QuickLeadType;
use Aqarmap\Bundle\ListingBundle\Repository\ListingPhotoRepository;
use Aqarmap\Bundle\ListingBundle\Service\AdvancedFilterFormTypeManager;
use Aqarmap\Bundle\ListingBundle\Service\AdvancedSearchFormTypeManager;
use Aqarmap\Bundle\ListingBundle\Service\CallRequestManager;
use Aqarmap\Bundle\ListingBundle\Service\Contracts\ListingLeadManagerInterface;
use Aqarmap\Bundle\ListingBundle\Service\Contracts\LocationManagerInterface;
use Aqarmap\Bundle\ListingBundle\Service\FreeListingService;
use Aqarmap\Bundle\ListingBundle\Service\InteractionService;
use Aqarmap\Bundle\ListingBundle\Service\ListingFeatureService;
use Aqarmap\Bundle\ListingBundle\Service\ListingManager;
use Aqarmap\Bundle\ListingBundle\Service\ListingRuleMatcher;
use Aqarmap\Bundle\ListingBundle\Service\Mortgage\MortgageService;
use Aqarmap\Bundle\ListingBundle\Service\SpecialAddListingService;
use Aqarmap\Bundle\ListingBundle\Service\SpecialListingFeatureDecorator;
use Aqarmap\Bundle\ListingBundle\Service\V4\CompoundDetailService;
use Aqarmap\Bundle\MainBundle\Form\ConfirmFeaturedFormType;
use Aqarmap\Bundle\MainBundle\Form\ConfirmFormType;
use Aqarmap\Bundle\MainBundle\Service\MobileDetectionService;
use Aqarmap\Bundle\MainBundle\Service\Setting;
use Aqarmap\Bundle\MessageBundle\Service\Composer;
use Aqarmap\Bundle\NeighborhoodBundle\Service\NeighborhoodManager;
use Aqarmap\Bundle\NotificationBundle\DatabaseNotification;
use Aqarmap\Bundle\NotifierBundle\Event\NotifierEvent;
use Aqarmap\Bundle\OTPBundle\Contract\OtpServiceInterface;
use Aqarmap\Bundle\SearchBundle\Services\CompoundFaqsService;
use Aqarmap\Bundle\SearchBundle\Services\ElasticListingSearch\DefaultListingSearch;
use Aqarmap\Bundle\TopSellerBundle\Model\TopSeller;
use Aqarmap\Bundle\TopSellerBundle\Service\TopSellerRetrievalService;
use Aqarmap\Bundle\UserBundle\Constant\UserServicesType;
use Aqarmap\Bundle\UserBundle\Constant\UserTypes;
use Aqarmap\Bundle\UserBundle\Entity\User;
use Aqarmap\Bundle\UserBundle\Entity\UserServices;
use Aqarmap\Bundle\UserBundle\Form\QuickRegistrationFormType;
use Aqarmap\Bundle\UserBundle\Repository\UserPackagesRepository;
use Aqarmap\Bundle\UserBundle\Services\UserActivityService;
use Aqarmap\Bundle\UserBundle\Services\UserManager;
use Aqarmap\Bundle\UserBundle\Services\UserPackagesService;
use Aqarmap\Bundle\UserBundle\Services\UserServicesManager;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityManagerInterface;
use FOS\RestBundle\Controller\Annotations as Rest;
use FOS\RestBundle\View\View;
use FOS\UserBundle\Model\UserManagerInterface;
use Gedmo\Translatable\TranslatableListener;
use Knp\Component\Pager\PaginatorInterface;
use Liip\ImagineBundle\Imagine\Cache\CacheManager;
use Predis\ClientInterface as RedisClient;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use Vich\UploaderBundle\Templating\Helper\UploaderHelper;
/**
* Listing controller.
*/
class ListingController extends AbstractController
{
/**
* @var Composer
*/
private $messageComposer;
/**
* @var DatabaseNotification
*/
private $databaseNotification;
/**
* @var LoggerInterface
*/
private $logger;
/**
* @var TranslatorInterface
*/
private $translator;
/**
* @var FeatureToggleManager
*/
private $featureToggleManager;
/**
* @var Setting
*/
private $setting;
/**
* @var ListingManager
*/
private $listingManager;
/**
* @var EventDispatcherInterface
*/
private $dispatcher;
/**
* @var InteractionService
*/
private $interactionService;
/**
* @var NeighborhoodManager
*/
private $neighborhoodManager;
/**
* @var DefaultListingSearch
*/
private $defaultListingSearch;
/**
* @var RelatedResultServiceInterface
*/
private $relatedResultService;
/**
* @var TopSellerRetrievalService
*/
private $topSellerRetrievalService;
/**
* @var FinancialAidService
*/
private $financialAidService;
/**
* @var ListingLeadManagerInterface
*/
private $listingLeadManager;
/**
* @var CompoundFaqsService
*/
private $compoundFaqsService;
/**
* @var PaginatorInterface
*/
private $paginator;
/**
* @var UserActivityService
*/
private $userActivityService;
/**
* @var MobileDetectionService
*/
private $mobileDetectionService;
/**
* @var RedisClient
*/
private $redis;
/**
* @var CacheManager
*/
private $imagine;
/**
* @var UploaderHelper
*/
private $uploaderHelper;
/**
* @var CallRequestManager
*/
private $callRequestManager;
/**
* @var AuthorizationCheckerInterface
*/
private $authorizationChecker;
/**
* @var TokenStorage
*/
private $tokenStorage;
/**
* @var MortgageService
*/
private $mortgageService;
/**
* @var ListingRuleMatcher
*/
private $listingRuleMatcher;
/**
* @var CreditManager
*/
private $creditManager;
/**
* @var UserServicesManager
*/
private $userServicesManager;
/**
* @var UserManagerInterface
*/
private $FOSUserManager;
/**
* @var PhoneManagerInterface
*/
private $phoneManager;
/**
* @var ListingFeatureService
*/
private $listingFeatureService;
private UserManager $userManager;
/**
* @var AdvancedSearchFormTypeManager
*/
private $advancedSearchFormTypeManager;
/**
* @var AdvancedFilterFormTypeManager
*/
private $advancedFilterFormTypeManager;
/** @var CompoundDetailService */
private $compoundDetailService;
/** @var TranslatableListener */
private $translatableListener;
/** @var EntityManagerInterface */
private $entityManager;
/** @var UserPackagesRepository */
private $userPackagesRepository;
public function __construct(
Composer $messageComposer,
OtpServiceInterface $otpService,
DatabaseNotification $databaseNotification,
LoggerInterface $logger,
TranslatorInterface $translator,
FeatureToggleManager $featureToggleManager,
Setting $setting,
ListingManager $listingManager,
EventDispatcherInterface $dispatcher,
InteractionService $interactionService,
NeighborhoodManager $neighborhoodManager,
DefaultListingSearch $defaultListingSearch,
RelatedResultServiceInterface $relatedResultService,
LocationManagerInterface $locationManager,
TopSellerRetrievalService $topSellerRetrievalService,
FinancialAidService $financialAidService,
ListingLeadManagerInterface $listingLeadManager,
CompoundFaqsService $compoundFaqsService,
PaginatorInterface $paginator,
UserActivityService $userActivityService,
MobileDetectionService $mobileDetectionService,
RedisClient $redis,
CacheManager $imagine,
UploaderHelper $uploaderHelper,
CallRequestManager $callRequestManager,
AuthorizationCheckerInterface $authorizationChecker,
TokenStorageInterface $tokenStorage,
MortgageService $mortgageService,
ListingRuleMatcher $listingRuleMatcher,
CreditManager $creditManager,
UserServicesManager $userServicesManager,
UserManagerInterface $FOSUserManager,
PhoneManagerInterface $phoneManager,
FreeListingService $freeListingService,
ListingFeatureService $listingFeatureService,
UserManager $userManager,
AdvancedSearchFormTypeManager $advancedSearchFormTypeManager,
AdvancedFilterFormTypeManager $advancedFilterFormTypeManager,
SpecialAddListingService $specialAddListingService,
CompoundDetailService $compoundDetailService,
SpecialListingFeatureDecorator $specialListingFeatureDecorator,
TranslatableListener $translatableListener,
EntityManagerInterface $entityManager,
UserPackagesRepository $userPackagesRepository
) {
$this->messageComposer = $messageComposer;
$this->databaseNotification = $databaseNotification;
$this->logger = $logger;
$this->translator = $translator;
$this->featureToggleManager = $featureToggleManager;
$this->setting = $setting;
$this->listingManager = $listingManager;
$this->dispatcher = $dispatcher;
$this->interactionService = $interactionService;
$this->neighborhoodManager = $neighborhoodManager;
$this->defaultListingSearch = $defaultListingSearch;
$this->relatedResultService = $relatedResultService;
$this->topSellerRetrievalService = $topSellerRetrievalService;
$this->financialAidService = $financialAidService;
$this->listingLeadManager = $listingLeadManager;
$this->compoundFaqsService = $compoundFaqsService;
$this->paginator = $paginator;
$this->userActivityService = $userActivityService;
$this->mobileDetectionService = $mobileDetectionService;
$this->redis = $redis;
$this->imagine = $imagine;
$this->uploaderHelper = $uploaderHelper;
$this->callRequestManager = $callRequestManager;
$this->authorizationChecker = $authorizationChecker;
$this->tokenStorage = $tokenStorage;
$this->mortgageService = $mortgageService;
$this->listingRuleMatcher = $listingRuleMatcher;
$this->creditManager = $creditManager;
$this->userServicesManager = $userServicesManager;
$this->FOSUserManager = $FOSUserManager;
$this->phoneManager = $phoneManager;
$this->listingFeatureService = $listingFeatureService;
$this->userManager = $userManager;
$this->advancedSearchFormTypeManager = $advancedSearchFormTypeManager;
$this->advancedFilterFormTypeManager = $advancedFilterFormTypeManager;
$this->specialAddListingService = $specialAddListingService;
$this->specialListingFeatureDecorator = $specialListingFeatureDecorator;
$this->compoundDetailService = $compoundDetailService;
$this->translatableListener = $translatableListener;
$this->entityManager = $entityManager;
$this->userPackagesRepository = $userPackagesRepository;
}
/**
* Listing Details Action.
*
* @Route("/{id}/{notification}", defaults={"notification"=0}, requirements={"id" = "\d+"}, options={"i18n" = false, "expose" = true}, name="listing_view", methods={"GET"})
* @Route("/listing/{id}/notification/{notification}", defaults={"notification"=0}, name="listing_view_notification", methods={"GET"})
* @Route("/listing/{id}", requirements={"id" = "\d+"} , options={"expose" = true} , name="listing_details", methods={"GET"})
* @Route("/listing/{id}-{slug}", requirements={"id" = "\d+", "slug" = ".+"}, name="listing_slug", methods={"GET"})
*/
public function read(Request $request, Listing $listing, EntityManagerInterface $em)
{
if ($request->get('notification')) {
try {
$this->databaseNotification->markOneAsRead($request->get('notification'));
} catch (\Exception $exception) {
$this->logger->log(LogLevel::ERROR, $exception->getMessage());
}
}
// Redirect to the right URL if the URL is short-URL or the listing slug is incorrect
if (('listing_slug' != $request->get('_route')
|| $request->attributes->get('slug') != $listing->getSlug())
&& !empty($listing->getSlug())
) {
return $this->redirect($this->generateUrl('listing_slug', array_merge($request->query->all(), [
'id' => $listing->getId(),
'slug' => $listing->getSlug(),
])), Response::HTTP_MOVED_PERMANENTLY);
}
$listingStatus = !\in_array($listing->getStatus(), [ListingStatus::LIVE, ListingStatus::PENDING]);
if ($listingStatus && !$request->query->get('noredirect') && $listing->getUser() != $this->getUser()) {
if (!$listing->getSection()->getSearchable()) {
return $this->redirect($this->generateUrl('compound_search'), Response::HTTP_FOUND);
}
try {
$searchableLocation = $listing->getLocation()->getNearestSearchable();
} catch (\Exception $exception) {
$this->addFlash(
'danger',
$this->translator->trans('listing.not_available')
);
return $this->redirect($this->generateUrl('homepage'), Response::HTTP_FOUND);
}
return $this->redirect($this->generateUrl('search', [
'section_slug' => $listing->getSection()->getSlug(),
'property_type_slug' => $listing->getPropertyType()->getSlug(),
'location_slug' => $searchableLocation->getSlug(),
]), Response::HTTP_MOVED_PERMANENTLY);
}
$listingRepo = $em->getRepository(Listing::class);
if ($notifierId = $request->query->get('notifier')) {
if (null !== $notifier = $em->getRepository('AqarmapNotifierBundle:Notifier')->find($notifierId)) {
$this->dispatcher->dispatch(new NotifierEvent($notifier), 'aqarmap.notifier.interaction');
} else {
$this->logger->warning('Notifier with id: '.$notifierId.' was not found!');
}
}
$this->interactionService->increaseViews($listing, $this->getUser());
$relatedListingCriteriaMapper = $this->relatedResultService->getRelatedListingCriteriaMapper($listing);
$relatedListings = $this->defaultListingSearch->search($relatedListingCriteriaMapper)['searchResults'];
$topSeller = $this->createTopSeller($listing);
$topSearchableCompanies = $this->topSellerRetrievalService->getTopSellerPersonalData($topSeller, $request->getLocale());
$searchableLocation = $listing->getLocation()->getNearestSearchable();
$isPlaceHoldered = false;
$userProfilePhoto = $listing->getUser()->isValidPersonalPhoto() ? $listing->getUser()->getPersonalPhoto() : null;
if ($listing->getLogo() || ($listing->getParent() && $listing->getParent()->getLogo())) {
if ($listing->getParent() && $listing->getParent()->getLogo()) {
}
} elseif (!empty($listing->getPhotosForSlider()) && $listing->getUser()->getIsValidLogo()) {
$isPlaceHoldered = true;
}
$this->financialAidService->setFinancialAidInListing($listing);
$activeListingsCount = $listing->getUser()->getActiveListingsCount();
$leadsCount = 0;
if ($this->featureToggleManager->isEnabled('web.client.served.count')) {
$leadsCount = $listing->getUser()->getClientServedCount();
}
$listing = current(
$this->listingManager->setUserActivities(
[$listing],
[$listing->getId()]
)
);
$hasUserMadeLead = false;
if ($user = $this->getUser()) {
$hasUserMadeLead = $this->listingLeadManager->hasUserMadeLead($listing, $user);
}
$compoundFaqs = [];
$listingDetails = $listing;
if ($listing->isProject()) {
$compoundFaqs = $this->compoundFaqsService->generateFaqData($listing);
$resaleRegularListingsPaginated = $this->paginator->paginate(
$listingRepo->getSectionListings($listing, null, ListingSections::FOR_SALE),
$request->query->get('page', ResaleListingsConstant::PAGE),
ResaleListingsConstant::LIMIT
);
$this->compoundDetailService->getPropertyTypeChildrens($listing, $request->getLocale());
$liveUnitsPaginated = $listing->getPropertyTypeChildren();
$this->compoundDetailService->getPropertyTypeUnitsChildrens($listing, ListingSections::FOR_SALE, $request->getLocale());
$resaleUnitsPaginated = $listing->getPropertyTypeChildren();
$this->compoundDetailService->getPropertyTypeUnitsChildrens($listing, ListingSections::FOR_RENT, $request->getLocale());
$rentUnitsPaginated = $listing->getPropertyTypeChildren();
}
$request->cookies->get('user-agent');
$mobileDetection = $this->mobileDetectionService->mobileDetection($request, $return);
$return = [
'listing' => $listingDetails,
'searchableLocation' => $searchableLocation,
'contact_seller_form' => $this->contactSellerForm($listing)->createView(),
'quick_registration_form' => $this->quickRegistrationForm()->createView(),
'call_request' => $this->callRequestForm($listing)->createView(),
'related_listings' => $relatedListings,
'relatedListingsCount' => (null != $relatedListings) ? $relatedListings->getTotalItemCount() : 0,
'location_statistics' => $this->neighborhoodManager->getStatistics(
$listing->getLocation()->getNearestNeighborhood(),
$listing->getPropertyType()
),
'topSearchableCompanies' => $topSearchableCompanies,
'topSearchableCompaniesCount' => \count($topSearchableCompanies),
'isPlaceHoldered' => $isPlaceHoldered,
'userProfilePhoto' => $userProfilePhoto,
'activeListingsCount' => $activeListingsCount,
'leadsCount' => $leadsCount,
'featureToggle' => $this->userActivityService->getFeatureToggles(),
'leadAnalytics' => $this->listingManager->getLeadAnalytics($listing),
'otherUnits' => $this->listingManager->getOtherUnits($listing, $request->getLocale()),
'hasUserMadeLead' => $hasUserMadeLead,
'resaleRegularListings' => $resaleRegularListingsPaginated ?? null,
'resaleUnitsPaginated' => $resaleUnitsPaginated ?? null,
'liveUnitsPaginated' => $liveUnitsPaginated ?? null,
'rentUnitsPaginated' => $rentUnitsPaginated ?? null,
'compoundFaqs' => $compoundFaqs,
'isMobile' => $mobileDetection['isMobile'],
];
if ($mobileDetection['isMobile']) {
$nearestLocations = $em
->getRepository(\Aqarmap\Bundle\ListingBundle\Entity\Location::class)
->getNearestLocations([$listing->getLocation()])
;
$return['nearestLocations'] = $nearestLocations;
foreach ($mobileDetection as $key => $val) {
$return[$key] = $val;
}
return $this->render('@AqarmapListing/Listing/read-mob.html.twig', $return);
}
$return['discussions'] = $em
->getRepository('AqarmapDiscussionBundle:Discussion')
->getTrendingWithLocation($listing->getLocation()->getId(), 3)
;
return $this->render('@AqarmapListing/Listing/read.html.twig', $return);
}
/**
* TopSeller Attributes from listing data.
*
* @param Listing
*
* @return TopSeller
*/
private function createTopSeller($listing)
{
$topSeller = new TopSeller();
$topSeller->setLocation($listing->getLocation()->getId());
$topSeller->setSection($listing->getSection()->getId());
$topSeller->setPropertyType($listing->getPropertyType()->getId());
return $topSeller;
}
/**
* Advanced Search Form.
*/
protected function createAdvancedSearchForm(): FormInterface
{
return $this->advancedSearchFormTypeManager
->setAction($this->generateUrl('listing_advanced_search'))
->setFormType(AdvancedSearchType::class)
->setMethodType('Post')
->setSettings($this->setting)
->applyOptions()
->createForm();
}
/**
* Advanced Search Form.
*/
protected function createAdvancedFilterForm(): FormInterface
{
$customFields = $this->redis->get('customFields');
return $this->advancedFilterFormTypeManager
->setAction($this->generateUrl('listing_filter_search'))
->setFormType(AdvancedFilterType::class)
->setMethodType('Post')
->setSettings($this->setting)
->setCustomFields($customFields ? unserialize($customFields) : [])
->applyOptions()
->createForm();
}
/**
* Multiple Search Form.
*/
protected function createMultipleSearchForm(): FormInterface
{
return $this->advancedSearchFormTypeManager
->setAction($this->generateUrl('listing_multiple_search'))
->setFormType(MultipleSearchFormType::class)
->setMethodType('Post')
->setSettings($this->setting)
->applyOptions()
->createForm();
}
/**
* Latest Listings Action.
*
* @Route("/listing/latest", name="listing_latest", methods={"GET"})
*/
public function latest(Request $request): Response
{
/** @var $em \Doctrine\ORM\EntityManager */
$em = $this->getDoctrine()->getManager();
$pagination = $this->paginator->paginate(
$em->getRepository(Listing::class)->getLatestListings(),
$request->query->get('page', 1)
);
return $this->render('@AqarmapListing/Listing/latest.html.twig', [
'listings' => $pagination,
]);
}
/**
* @Route("/listing/latest/{section}.{_format}")
*
* @return Response
*/
public function CSVLatestListings(Request $request, Section $section)
{
/** @var EntityManager $em */
$em = $this->getDoctrine()->getManager();
$listings = $em->getRepository(Listing::class)->findBy([
'section' => $section,
'status' => ListingStatus::LIVE,
], ['id' => 'desc'], 100);
$handle = fopen('php://memory', 'r+');
fputcsv($handle, [
$request->query->get('id', 'id'),
$request->query->get('section', 'section'),
$request->query->get('description', 'description'),
$request->query->get('image', 'image'),
$request->query->get('link', 'link'),
$request->query->get('title', 'title'),
$request->query->get('price', 'price'),
$request->query->get('formatted_price', 'formatted_price'),
$request->query->get('price_currency', 'price_currency'),
$request->query->get('location', 'location'),
$request->query->get('address', 'address'),
$request->query->get('property_type', 'property_type'),
$request->query->get('availability', 'availability'),
$request->query->get('condition', 'condition'),
]);
foreach ($listings as $listing) {
$thumb = null;
if ($listing->getMainPhoto()) {
$thumb = $this->imagine->generateUrl(
$this->uploaderHelper->asset($listing->getMainPhoto()->getFile(), 'file'),
'large'
);
}
$description = preg_split('/\n/', mb_substr($listing->getDescription(), 0, 200), \PREG_SPLIT_DELIM_CAPTURE);
fputcsv($handle, [
$listing->getId(),
$section->getTitle(),
$description[0],
$thumb,
$this->generateUrl('listing_view', ['id' => $listing->getId()], true),
$listing->getTitle(),
$listing->getPrice(),
number_format($listing->getPrice()),
sprintf('%s %s', number_format($listing->getPrice()), 'EGP'),
$listing->getLocation()->getTitle(),
$listing->getAddress(),
$listing->getPropertyType()->getTitle(),
'in stock',
'new',
]);
}
rewind($handle);
$content = stream_get_contents($handle);
fclose($handle);
return new Response($content, Response::HTTP_OK, [
'Content-Type' => 'application/force-download',
'Content-Disposition' => sprintf(
'attachment; filename="latest-listings - %s - %s.csv"',
$section->getTitle(),
date('Y-m-d H-i-s')
),
]);
}
/**
* @deprecated
*
* @Route("/listing/{id}/one", name="landing_page", methods={"GET", "POST"})
*
* @Rest\View()
*
* @return array
*/
public function landingPage(Request $request, Listing $listing)
{
$form = $this->createForm(LandingPageFormType::class, $landingPage = new LandingPage(), [
'action' => $this->generateUrl('landing_page', ['id' => $listing->getId()]),
]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
if (!($user = $this->FOSUserManager->findUserByEmail($landingPage->getUser()->getEmail()))) {
$user = $this->userManager
->createUserWithoutPassword($form->get('user')->getData(), $form->get('user'), $request)
;
}
if (!$form->get('message')->getData()) {
$callRequest = new CallRequest();
$callRequest->setListing($listing);
$callRequest->setUser($user);
$this->callRequestManager->submitCallRequest($callRequest);
} else {
// Compose a message
$composer = $this->messageComposer;
$composer->setSender($user);
$composer->compose($form->get('message')->getData(), $listing);
}
}
return [
'form' => $form->createView(),
'listing' => $listing,
];
}
/**
* Add Listing First Step Action.
*
* @Route("/listing/initialize", name="listing_initialize", options={"expose"=true})
*/
public function initialize(Request $request)
{
$user = $this->getUser();
if (false === $this->authorizationChecker->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
return $this->redirect($this->generateUrl('aqarmap_add_listing'));
}
$hasRentalPackage = $this->userPackagesRepository->hasRentalPackage($user);
$initializeOptions = [
'action' => $this->generateUrl('listing_initialize'),
'method' => 'POST',
'em' => $this->getDoctrine()->getManager(),
'is_admin' => $this->authorizationChecker->isGranted('ROLE_ADMIN'),
'has_rental_package' => $hasRentalPackage,
'parentUser' => $user,
];
$form = $this->createForm(ListingInitializeType::class, $listing = new Listing(), $initializeOptions);
$listingEvent = new ListingEvent($listing);
$this->dispatcher->dispatch($listingEvent, 'aqarmap.listing.pre_submitted');
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$listing = $this->listingManager->createDraft($listing);
// Add user phone number to the listing
if ($listing->getUser()->getPhoneNumber()) {
// link user phone with this listing
// TODO: Suggest only the main number for now, later on we will suggest the main + last 2 numbers.
$this->listingManager->suggestListingPhoneNumbers(
[$listing->getUser()->getPhoneNumber()],
$listing
);
}
return $this->redirect($this->generateUrl('listing_edit', [
'id' => $listing->getId(),
]));
}
return $this->render('@AqarmapListing/Listing/initialize.html.twig', [
'form' => $form->createView(),
]);
}
/**
* Add Listing V2.
*
* @Route("/listing/initialize/{step}", name="add_listing", options={"expose"=true})
* @Route("/listing/initialize/{id}/{step}", name="edit_listing", options={"expose"=true})
*
* @Security("is_granted('IS_AUTHENTICATED_REMEMBERED')")
*
* @throws \Doctrine\ORM\NonUniqueResultException
*/
public function addListing(): Response
{
return $this->render('@AqarmapListing/Listing/add.html.twig', [
'title' => $this->translator->trans('listing.add_your_listing'),
'featureToggle' => [
'accept_adding_phones' => $this->featureToggleManager->isEnabled('web.addlisting.accept_adding_phones'),
'google_maps_location' => $this->featureToggleManager->isEnabled('web.addlisting.google_maps_location'),
],
]);
}
/**
* Add Listing groups.
*
* @Route("/listing/add/", name="add_listing_steps", options={"expose"=true})
* @Route("/listing/{id}/edit/steps", name="edit_listing_steps", options={"expose"=true})
*
* @Security("is_granted('IS_AUTHENTICATED_REMEMBERED')")
*
* @throws \Doctrine\ORM\NonUniqueResultException
*/
public function addListingSteps(): Response
{
return $this->render('@AqarmapListing/Listing/addSteps.html.twig', [
'title' => $this->translator->trans('listing.add_your_listing'),
'featureToggle' => [
'accept_adding_phones' => $this->featureToggleManager->isEnabled('web.addlisting.accept_adding_phones'),
'google_maps_location' => $this->featureToggleManager->isEnabled('web.addlisting.google_maps_location'),
],
]);
}
/**
* Listing Post Action
* This action manage adding & editing listings.
*
* @Route("/listing/{id}/edit/", name="listing_edit", requirements={"id" = "\d+"}, options={"expose"=true})
*
* @Security(
* "(is_granted('IS_AUTHENTICATED_REMEMBERED') and is_granted('ROLE_OWNER', listing)) or is_granted('ROLE_ADMIN')"
* )
*/
public function post(Request $request, Listing $listing): Response
{
$form = $this->createForm(ListingType::class, $listing, [
'action' => $this->generateUrl('listing_edit', ['id' => $listing->getId()]),
'method' => 'POST',
'listingIsLiveFor5Days' => $this->listingManager->checkListingLiveDays($listing),
'is_admin' => $this->authorizationChecker->isGranted('ROLE_ADMIN'),
'user_country' => $this->setting->getSetting('general', 'country'),
'user_type' => $listing->getUser() ? $listing->getUser()->getUserType() : null,
'isMortgageOptionsEnabled' => $this->featureToggleManager->isEnabled('web.mortgage.options'),
'isListingMarketPropertyTypesEnabled' => $this->featureToggleManager->isEnabled('web.listing.market.property.types'),
]);
$form->handleRequest($request);
if ($request->isMethod('POST')) {
if ($form->isSubmitted() && $form->isValid()) {
$this->updateWhatsAppPhones($listing->getUser()->getId(), (array) $request->request->get('phoneIds', []), (array) $request->request->get('hasWhatsApp', []));
$listing = $this->handleListingPhones($listing, $request->request->all()['listing']['phones']);
$this->handleUserPhones($listing->getUser(), $request->request->all()['listing']['phones']);
$this->listingManager->saveListing($listing);
if ($this->featureToggleManager->isEnabled('web.add.listing.translations')) {
if ('en' == $request->getLocale()) {
$criteria = [
'reversedLocale' => 'ar',
'title-ar' => $request->request->get('title-ar'),
'description-ar' => $request->request->get('description-ar'),
];
} else {
$criteria = [
'reversedLocale' => 'en',
'title-en' => $request->request->get('title-en'),
'description-en' => $request->request->get('description-en'),
];
}
$this->listingManager->updateListingTranslationsFields($listing, $criteria);
} else {
$this->listingManager->updateListingTranslations($listing);
}
if ($this->featureToggleManager->isEnabled('web.mortgage.options')) {
$propertyRegistrationStatus = $form->has('propertyRegistrationStatus') ? $form->get('propertyRegistrationStatus')->getData() : null;
if (\in_array($propertyRegistrationStatus, PropertyRegistrationStatusOption::getValidMorgageOptions())) {
$this->mortgageService->addEligibleMortgageTypes($listing);
} else {
$this->listingManager->setELigibleMortgageToNull($listing);
}
$listing = $this->mortgageService->addMortgageApproval($listing, $form);
}
$listingEvent = new ListingEvent($listing);
$this->dispatcher->dispatch($listingEvent, 'aqarmap.listing.submitted');
if (ListingSource::SCRAPPING == $listing->getSource()
|| ListingSource::LITE == $listing->getSource()
) {
return $this->redirect($this->generateUrl('listing_view', ['id' => $listing->getId()]));
}
return $this
->redirect(
$this->generateUrl(
'listing_upload',
['id' => $listing->getId(), '_locale' => $request->get('_locale')]
)
)
;
}
$this->addFlash('danger', $this->translator->trans('static.problem_error_message'));
}
$translatedLocale = 'en' == $request->getLocale() ? 'ar' : 'en';
return $this->render('@AqarmapListing/Listing/post.html.twig', [
'form' => $form->createView(),
'listing' => $listing,
'title_translation' => $this->listingTitleTranslations($listing, $translatedLocale),
'description_translation' => $this->listingDescriptionTranslations($listing, $translatedLocale),
'brokerChoices' => UserTypes::getBrokerChoices(),
]);
}
/**
* @return array|mixed
*/
private function listingTitleTranslations(Listing $listing, string $locale)
{
$this->translatableListener->setTranslatableLocale($locale);
$listing->setTranslatableLocale($locale);
$this->entityManager->refresh($listing);
return $listing->getTitle() ?? $this->listingManager->listingTitleTranslations($listing, $locale);
}
private function listingDescriptionTranslations(Listing $listing, string $locale)
{
$this->translatableListener->setTranslatableLocale($locale);
$listing->setTranslatableLocale($locale);
$this->entityManager->refresh($listing);
return $listing->getDescription() ?? $this->listingManager->listingTitleTranslations($listing, $locale);
}
private function handleListingPhones(Listing $listing, array $phones): Listing
{
$listing->clearPhones();
foreach ($phones as $phone) {
$phoneNumber = $phone['number'];
$countryCode = $phone['countryCode'];
$phone = new Phone($countryCode.$phoneNumber, $countryCode);
$listing->addPhone(new ListingPhone($phoneNumber, $listing, $countryCode, $phone));
}
return $listing;
}
private function handleUserPhones(User $user, array $phones): void
{
foreach ($phones as $phone) {
$originalPhoneNumber = $phone['number'];
$countryCode = $phone['countryCode'];
$phoneNumber = $this->phoneManager->trimZero($originalPhoneNumber, $countryCode);
$this->phoneManager->addNewUserPhone($phoneNumber, $countryCode, $user, true, false, null, $originalPhoneNumber);
}
}
/**
* Listing Post Action
* This action manage adding & editing listings.
*
* @Route("/listing/{id}/preview/", name="listing_preview", requirements={"id" = "\d+"}, options={"expose"=true})
*
* @Security(
* "(is_granted('IS_AUTHENTICATED_REMEMBERED') and is_granted('ROLE_OWNER', listing)) or is_granted('ROLE_ADMIN')"
* )
*
* @return array|RedirectResponse
*/
public function preview(Listing $listing): Response
{
return $this->render('@AqarmapListing/Listing/preview.html.twig', [
'listing' => $listing,
]);
}
/**
* Listing Post Action
* This action manage adding & editing listings.
*
* @Route("/listing/lite", name="listing_lite_add", options={"expose"=true})
*/
public function postLite(Request $request)
{
/** @var $em \Doctrine\ORM\EntityManager */
$em = $this->getDoctrine()->getManager();
$form = $this->createForm(
LiteListingType::class,
null,
['em' => $em,
'action' => $this->generateUrl('listing_lite_add'),
'method' => 'post', ]
);
if ($request->isMethod('POST')) {
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$listing = $form->getData();
$listing->setSellerRole(ListingSellerRoles::OWNER);
$this->listingManager->saveListing($listing);
// add listing phone to new phones table ;
$this->phoneManager->addListingPhonesList($listing->getPhones(), '', $listing);
$this->listingManager->addLiteListingTitleAndDescriptionTranslation($listing);
$listingEvent = new ListingEvent($listing);
$this->dispatcher->dispatch($listingEvent, 'aqarmap.listing.submitted');
$this->addFlash(
'success',
$this->translator->trans('add_listing_page.success_messages.padding_review')
);
if ($this->featureToggleManager->isEnabled('web.delayed.review.eid.info.message')) {
$this->addFlash(
'info',
$this->translator->trans('add_listing_page.info_messages.eid_delayed_review')
);
}
return $this->redirect($this->generateUrl('homepage'));
}
$this->addFlash('danger', $this->translator->trans('static.problem_error_message'));
}
return $this->render('@AqarmapListing/Listing/postLite.html.twig', [
'form' => $form->createView(),
]);
}
/**
* Add Listing First Step Action.
*
* @Route("/listing/{id}/edit/photos", name="listing_upload", requirements={"id" = "\d+"}, options={"expose"=true})
*
* @Security("is_granted('ROLE_ADMIN') or is_granted('ROLE_OWNER', listing)")
*/
public function upload(Request $request, Listing $listing)
{
$form = $this->createForm(PhotoType::class, null, [
'method' => 'POST',
]);
$form->handleRequest($request);
$listingRules = $this->listingRuleMatcher->match($listing);
if ($form->isSubmitted() && $form->isValid() && $request->isMethod('POST')) {
$listingPhotos = [];
try {
$listingPhotos = $this->listingManager->addListingPhotos($listing, $form->get('file')->getData());
$listingEvent = new ListingEvent($listing);
$this->dispatcher->dispatch($listingEvent, 'aqarmap.listing.submitted');
$this->listingManager->saveListing($listing);
// If not Ajax request
if (!$request->isXmlHttpRequest()) {
$this->logger->error('Not AJAX');
return $this->redirect($request->headers->get('referer') ?: $this->generateUrl('homepage'));
}
} catch (\Exception $exception) {
$this->logger->error($exception->getMessage());
}
return View::create(['files' => $listingPhotos], Response::HTTP_OK);
}
return $this->render('@AqarmapListing/Listing/upload.html.twig', [
'requiredPhotosCount' => $listingRules['required_photos'] ?? 0,
'listing' => $listing,
'form' => $form->createView(),
]);
}
/**
* Should be called after photos are uploaded.
*
* @Route("/listing/{id}/finish", requirements={"id" = "\d+"}, name="listing_finish")
*
* @return RedirectResponse|Response
*/
public function finish(Listing $listing, UserPackagesService $userPackagesService)
{
$listingEvent = new ListingEvent($listing);
if (!$userPackagesService->canListInLocation($listing)) {
$this->addFlash('danger', $this->translator->trans('credit.can_not_list_in_location'));
return $this->redirect($this->generateUrl('listing_upload', [
'id' => $listing->getId(),
]), Response::HTTP_FOUND);
}
$this->dispatcher->dispatch($listingEvent, 'aqarmap.listing.submitted');
$response = $listingEvent->getResponse();
if (null === $response) {
if (ListingStatus::PENDING === $listing->getStatus()) {
$this->addFlash(
'success',
$this->translator->trans('add_listing_page.success_messages.padding_review')
);
if ($this->featureToggleManager->isEnabled('web.delayed.review.eid.info.message')) {
$this->addFlash(
'info',
$this->translator->trans('add_listing_page.info_messages.eid_delayed_review')
);
}
}
$response = new RedirectResponse(
$this->generateUrl(
'listing_slug',
['id' => $listing->getId(), 'slug' => $listing->getSlug()]
)
);
}
return $response;
}
/**
* SWAT special add listing feature page.
*
* @Route("/listing/{id}/feature", requirements={"id" = "\d+"}, name="special_add_listing_feature")
*
* @Security("is_granted('ROLE_OWNER', listing)")
*/
public function specialAddListingFeature(Listing $listing): RedirectResponse
{
return $this->redirectToRoute('listing_finish', ['id' => $listing->getId()]);
}
/**
* @Route("/listing/{id}/make_it_featured",
* requirements={"id" = "\d+"}, name="listing_confirm_featured_credit", methods={"GET"})
*
* @Security("is_granted('ROLE_OWNER', listing)")
*
* @return RedirectResponse|Response
*/
public function confirmFeaturedPublishing(Listing $listing)
{
if (!\in_array($listing->getStatus(), [ListingStatus::PENDING, ListingStatus::LIVE])) {
$this->addFlash(
'danger',
$this->translator->trans('listing.featured_failure_statement.not_live_or_pending')
);
return $this->redirect($this->generateUrl('aqarmap_listing_default_mylistings'));
}
if (UserTypes::INDIVIDUAL == $listing->getUser()->getUserType()) {
$listingRules = $this->listingFeatureService->getFeaturedListingRules($listing, ['sold_by_owner', 'sold_by_owner_sponsored']);
} else {
$listingRules = $this->listingFeatureService->getFeaturedListingRules($listing, ['featured', 'premium', 'sponsored', 'spotlight']);
}
/** @var User $user */
$user = $this->getUser();
return $this->render(
'@AqarmapListing/Listing/featuredListingCheckout.html.twig',
[
'listingRules' => $listingRules,
'listingId' => $listing->getId(),
'haveFeesToFeature' => $this->listingManager->userHasFeesToFeature($user, $listing),
]
);
}
/**
* @Route("/listing/{id}/make_it_featured", options={"expose"=true} ,requirements={"id" = "\d+"},
* name="listing_confirm_publish_featured_credit_post", methods={"POST"})
*
* @Security("is_granted('ROLE_OWNER', listing)")
*/
public function prepareFeaturedListingPayment(Listing $listing, Request $request): RedirectResponse
{
$listingRules = $this->listingManager->getListingRules($listing);
$fees = $request->query->get('fees', $listingRules['featured_fees']);
$duration = $request->query->get('duration', $listingRules['featured_duration']);
$listingFeaturedType = $request->query->get('listingFeaturedType', ListingFeaturedTypes::FEATURED);
$listingFeature = $request->query->get('listingFeature', ListingFeatures::FEATURED);
$listingStatus = $listing->getStatus();
/** @var User $user */
$user = $this->getUser();
if (!$this->listingManager->isAffordable($user, $fees)) {
$this->addFlash('danger', $this->translator->trans('credit.not_enough_featuring_credit', [
'link' => $this->generateUrl('aqarmap_buy_credit', ['listing_id' => $listing->getId()]),
]));
return $this->redirect($this->generateUrl('listing_confirm_featured_credit', [
'id' => $listing->getId(),
]), Response::HTTP_FOUND);
}
$featuredText = $this->translator->trans(ListingFeaturedTypes::getFeaturedText($listingFeaturedType));
$rules = [
'featuredFees' => $fees,
'featuredDuration' => $duration,
'listingFeaturedType' => $listingFeaturedType,
'listingFeature' => $listingFeature,
'featuredText' => $featuredText,
];
if ($this->listingManager->requiresFeaturingReview($listingFeaturedType)) {
try {
$this->listingManager->makeItFeatured($listing, $rules);
if (ListingStatus::LIVE == $listingStatus) {
$this->addFlash(
'success',
$this->translator->trans('add_listing_page.success_messages.pending_featuring', [':featured_type:' => $featuredText])
);
} else {
$this->addFlash(
'success',
$this->translator->trans('add_listing_page.success_messages.padding_review')
);
if ($this->featureToggleManager->isEnabled('web.delayed.review.eid.info.message')) {
$this->addFlash(
'info',
$this->translator->trans('add_listing_page.info_messages.eid_delayed_review')
);
}
}
} catch (\Exception $exception) {
$this->addFlash('danger', $this->translator->trans($exception->getMessage()));
}
if (ListingStatus::LIVE == $listingStatus) {
return $this->redirect($this->generateUrl('aqarmap_listing_default_mylistings'));
}
return $this->redirect($this->generateUrl('listing_finish', [
'id' => $listing->getId(),
]));
}
try {
$this->listingManager->makeItFeatured($listing, $rules);
if (ListingStatus::LIVE == $listing->getStatus()) {
$this->addFlash(
'success',
$this->translator->trans(
'add_listing_page.success_messages.featured',
[':listing_title:' => $listing->getTitle(), ':featured_type:' => $featuredText]
)
);
$redirectTo = $user->hasValidAccessToLiveApp() ?
$this->redirect(sprintf('%s/%s', $this->getParameter('user_dashboard_url'), 'listings')) :
$this->redirectToRoute('aqarmap_listing_default_mylistings');
return $redirectTo;
}
$this->addFlash(
'success',
$this->translator->trans('add_listing_page.success_messages.padding_review')
);
if ($this->featureToggleManager->isEnabled('web.delayed.review.eid.info.message')) {
$this->addFlash(
'info',
$this->translator->trans('add_listing_page.info_messages.eid_delayed_review')
);
}
return $this->redirectToRoute('listing_finish', [
'id' => $listing->getId(),
]);
} catch (\Exception $e) {
$buyCreditLink = $this->generateUrl('page_view', ['slug' => 'buy-credit'], true);
if ($this->setting->getSetting('features', 'payments')) {
$buyCreditLink = $this->generateUrl('aqarmap_buy_credit');
}
$this->addFlash('danger', $this->translator->trans(
$e->getMessage(),
['%link%' => $buyCreditLink],
'exceptions'
));
}
return $this->redirect($this->generateUrl('listing_confirm_featured_credit', [
'id' => $listing->getId(),
]), Response::HTTP_FOUND);
}
/**
* @Route(
* "/listing/{id}/payment_confirmation",
* requirements={"id" = "\d+"}, name="listing_confirm_publish_credit", methods={"GET"}
* )
*
* @Security("is_granted('ROLE_ADMIN') or is_granted('ROLE_OWNER', listing)")
*
* @return array|RedirectResponse
*/
public function confirmPublishing(Listing $listing, UserPackagesService $userPackagesService): Response
{
$listingRule = $this->listingRuleMatcher->match($listing);
/** @var $em \Doctrine\ORM\EntityManager */
$em = $this->getDoctrine()->getManager();
// User Balance
$userDetails = $listing->getUser();
$available_balance = $this->userPackagesRepository->getTotalCreditsByUser($userDetails);
$userId = $userDetails->getId();
$em->getRepository(User::class)->findOneBy(['id' => $userId]);
$listingManger = $this->listingManager;
if (!$userPackagesService->canListInLocation($listing)) {
$this->addFlash('danger', $this->translator->trans('credit.can_not_list_in_location'));
return $this->redirect($this->generateUrl('listing_upload', [
'id' => $listing->getId(),
]), Response::HTTP_FOUND);
}
$userServiceRepository = $em->getRepository(UserServices::class);
if ($this->userServicesManager->hasActiveService(UserServicesType::UNLIMITED_LISTINGS, $userId)
&& ListingCategories::UNLIMITED != $listing->getCategory()
&& ListingStatus::DRAFT != $listing->getStatus()
) {
if ($userServiceRepository
->passUnlimitedListing($listing, $this->creditManager, $listingManger) || $listing->getPublicationCredit()
) {
if ($this->listingFeatureService->isFeaturedOffersAvailable($listing)) {
return $this->redirect($this->generateUrl('listing_confirm_featured_credit', [
'id' => $listing->getId(),
]));
}
return $this->redirect($this->generateUrl('listing_finish', [
'id' => $listing->getId(),
]));
}
}
$isUserInSpecialAddListingGroup = $this->specialAddListingService->hasSpecialAddListingGroup($userDetails);
$userUnlimitedListings = $this->userServicesManager->hasActiveService(UserServicesType::UNLIMITED_LISTINGS, $userId);
$userHasNoFreeListingService = !$userUnlimitedListings;
$userHasNoFreeListingQuote = ($userUnlimitedListings && 0 == $userUnlimitedListings['remainingQuota']);
if ($isUserInSpecialAddListingGroup) {
if ($userHasNoFreeListingService || $userHasNoFreeListingQuote) {
return $this->redirectToRoute('special_add_listing_feature', ['id' => $listing->getId()]);
}
}
$form = $this->ConfirmPaymentForm($listing);
return $this->render(
'@AqarmapListing/Listing/confirmPublishing.html.twig',
[
'listing' => $listing,
'fees' => $listingRule['publication_fees'],
'duration' => $listingRule['duration'],
'available_balance' => $available_balance,
'form' => $form->createView(),
]
);
}
/**
* @Route(
* "/listing/{id}/list_rejections",
* requirements={"id" = "\d+"},
* name="listing_list_rejections", methods={"GET"}
* )
*
* @Security("is_granted('ROLE_OWNER', listing)")
*
* @return array
*/
public function listRejections(Listing $listing, Request $request): Response
{
if ($request->get('notification')) {
try {
$this->databaseNotification->markOneAsRead($request->get('notification'));
} catch (\Exception $exception) {
$this->logger->log(LogLevel::ERROR, $exception->getMessage());
}
}
return $this->render(
'@AqarmapListing/Listing/confirmPublishing.html.twig',
[
'listing' => $listing,
]
);
}
/**
* @Route(
* "/listing/{id}/payment_confirmation",
* requirements={"id" = "\d+"}, name="listing_confirm_publish_credit_post", methods={"POST"}
* )
*
* @Security("is_granted('ROLE_ADMIN') or is_granted('ROLE_OWNER', listing)")
*
* @return array|RedirectResponse
*/
public function prepareListingPayment(Listing $listing, Request $request, UserPackagesService $userPackagesService): RedirectResponse
{
$listingRule = $this->listingRuleMatcher->match($listing);
/** @var EntityManager $em */
$em = $this->getDoctrine()->getManager();
// User Balance
$available_balance = $this->userPackagesRepository->getTotalCreditsByUser($listing->getUser());
$userId = $listing->getUser()->getId();
$listingManger = $this->listingManager;
if (!$userPackagesService->canListInLocation($listing)) {
$this->addFlash('danger', $this->translator->trans('credit.can_not_list_in_location'));
return $this->redirect($this->generateUrl('listing_upload', [
'id' => $listing->getId(),
]), Response::HTTP_FOUND);
}
$userServiceRepository = $em->getRepository(UserServices::class);
if ($this->userServicesManager->hasActiveService(UserServicesType::UNLIMITED_LISTINGS, $userId)) {
if ($userServiceRepository->passUnlimitedListing($listing, $this->creditManager, $listingManger)
) {
if (!$this->listingFeatureService->isFeaturedOffersAvailable($listing)) {
return $this->redirect($this->generateUrl('listing_finish', [
'id' => $listing->getId(),
]));
}
return $this->redirect($this->generateUrl('listing_confirm_featured_credit', [
'id' => $listing->getId(),
]));
}
}
$form = $this->ConfirmPaymentForm($listing);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// Payment Confirmed?
// If user cancel payment redirect him to his listing,
if (!$form->get('confirm')->isClicked()) {
return $this->redirect($this->generateUrl('listing_view', [
'id' => $listing->getId(),
]), Response::HTTP_FOUND);
}
// If user credit expired, complain.
$enforceCredit = $this->setting->getSetting('features', 'enforce_credits_expiration');
/** @var User $user */
$user = $this->getUser();
if ($enforceCredit && 0 === $user->getAbsoluteCreditExpiryDays()) {
$this->addFlash('danger', $this->translator->trans('credit.credit_can_not_use', [
'link' => $this->generateUrl('aqarmap_buy_credit', ['listing_id' => $listing->getId()]),
]));
return $this->redirect($this->generateUrl('listing_confirm_publish_credit', [
'id' => $listing->getId(),
]), Response::HTTP_FOUND);
}
// User already paid
if ($listing->getPublicationCredit()) {
$this->addFlash('info', $this->translator->trans('credit.already_paid'));
} else {
// User don't have enough credits
if ($listingRule['publication_fees'] > $available_balance) {
$this->addFlash('danger', $this->translator->trans('credit.not_enough_credits'));
} else {
// Subtract publication fees
$credits = $this->creditManager->deduction(
$listing->getUser(),
$listingRule['publication_fees'],
'Listing Fees'
);
foreach ($credits as $credit) {
if ($credit instanceof Credit) {
$credit->setStatus(CreditStatus::SUCCESS);
$this->listingManager->addFeature($listing, ListingFeatures::PAID, null, $credit);
if (!$this->listingFeatureService->isFeaturedOffersAvailable($listing)) {
return $this->redirect($this->generateUrl('listing_finish', [
'id' => $listing->getId(),
]));
}
}
}
return $this->redirect($this->generateUrl('listing_confirm_featured_credit', [
'id' => $listing->getId(),
'ref' => 'add_listing',
]));
}
}
}
$this->addFlash('danger', 'Unexpected error occurred.');
return $this->redirect($this->generateUrl('listing_confirm_publish_credit', [
'id' => $listing->getId(),
]));
}
private function ConfirmPaymentForm(Listing $listing)
{
return $this->createForm(ConfirmFormType::class, null, [
'method' => 'POST',
'action' => $this->generateUrl('listing_confirm_publish_credit_post', ['id' => $listing->getId()]),
]);
}
/**
* @return \Symfony\Component\Form\Form
*/
private function confirmFeaturedPaymentForm(Listing $listing)
{
return $this->createForm(ConfirmFeaturedFormType::class, null, [
'method' => 'POST',
'action' => $this
->generateUrl(
'listing_confirm_publish_featured_credit_post',
['id' => $listing->getId()]
),
]);
}
/**
* Delete Listing entity.
*
* @Route("/listing/{id}/delete", requirements={"id" = "\d+"}, name="listing_delete", options={"expose"=true})
*
* @Security("is_granted('ROLE_ADMIN') or is_granted('ROLE_OWNER', listing)")
*/
public function delete(Listing $listing, Request $request): RedirectResponse
{
if (\in_array('ROLE_PREVENT_DELETE_LISTING', $this->getUser()->getRoles())) {
throw new AccessDeniedHttpException("Forbidden, user don't have this permession.");
}
if (ListingStatus::EXPIRED == $listing->getStatus()) {
throw $this->createNotFoundException('Listing is expired.');
}
$this->listingManager->remove($listing, ListingStatus::USER_DELETED);
$this->addFlash(
'success',
$this->translator->trans('add_listing_page.success_messages.deleted')
);
return $this->redirect($request->headers->get('referer') ?: $this->generateUrl('homepage'));
}
/**
* unDelete Listing entity.
*
* @Route("/listing/{id}/undelete", requirements={"id" = "\d+"}, name="listing_undelete")
*
* @Security("is_granted('ROLE_ADMIN') or is_granted('ROLE_OWNER', listing)")
*
* @return RedirectResponse|Response|null
*/
public function undelete(Listing $listing)
{
if (ListingStatus::USER_DELETED != $listing->getStatus()) {
throw $this->createNotFoundException('Unable to find this listing.');
}
$this->getDoctrine()->getManager();
$this->listingManager->changeStatus($listing, ListingStatus::PENDING);
$listingEvent = new ListingEvent($listing);
$this->dispatcher->dispatch($listingEvent, 'aqarmap.listing.submitted');
$response = $listingEvent->getResponse();
if (null === $response) {
if (ListingStatus::PENDING === $listing->getStatus()) {
$this->addFlash(
'success',
$this->translator->trans('add_listing_page.success_messages.padding_review')
);
if ($this->featureToggleManager->isEnabled('web.delayed.review.eid.info.message')) {
$this->addFlash(
'info',
$this->translator->trans('add_listing_page.info_messages.eid_delayed_review')
);
}
}
$response = new RedirectResponse(
$this->generateUrl(
'listing_slug',
['id' => $listing->getId(), 'slug' => $listing->getSlug()]
)
);
}
return $response;
}
/**
* Creates "Request a Call" button.
*
* @return \Symfony\Component\Form\Form
*/
public function callRequestForm(Listing $listing)
{
return $this->createForm(CallRequestFormType::class, null, [
'method' => 'POST',
'action' => $this->generateUrl('aqarmap_listing_call_request', ['id' => $listing->getId()]),
]);
}
/**
* Creates contact seller form.
*
* @param Listing $listing The listing entity
*
* @return \Symfony\Component\Form\Form The form
*/
public function contactSellerForm(Listing $listing)
{
return $this->createForm(ContactSellerFormType::class, null, [
'method' => 'POST',
'action' => $this->generateUrl('aqarmap_listing_contact_seller', ['id' => $listing->getId()]),
]);
}
/**
* Creates contact seller form.
*
* @param Listing $listing The listing entity
*
* @return \Symfony\Component\Form\Form The form
*/
public function contactSellerWideForm(Listing $listing)
{
return $this->createForm(ContactSellerWideFormType::class, null, [
'method' => 'POST',
'action' => $this->generateUrl('aqarmap_listing_contact_seller', ['id' => $listing->getId()]),
]);
}
/**
* Creates quick registration form.
*
* @return \Symfony\Component\Form\Form The form
*/
public function quickRegistrationForm()
{
return $this->createForm(QuickRegistrationFormType::class, null, [
'method' => 'POST',
'action' => $this->generateUrl('aqarmap_user_quick_registration'),
]);
}
/**
* Contact Seller Action.
*
* @Route("/listing/{id}/contact_seller", requirements={"id" = "\d+"}, name="aqarmap_listing_contact_seller", options={"expose"=true}, defaults={"_format": "json"}, methods={"POST"})
*
* @Rest\View()
*
* @return array|\Symfony\Component\Form\Form
*/
public function contactSeller(Listing $listing, Request $request)
{
$form = $this->contactSellerForm($listing);
if ($request->request->has('contact_seller_wide')) {
$form = $this->contactSellerWideForm($listing);
}
$lead = $request->get('lead');
$originalPhoneNumber = $lead['phone'];
$phoneNumber = $lead ? $this->phoneManager->trimZero($lead['phone'], $request->get('countryCode')) : null;
$message = json_decode((string) $request->get('message'), true);
$hasEmail = !$request->get('isAutoGeneratedEmail', 0);
$user = $this->getUser();
$form->handleRequest($request);
if ($lead) {
$form = $this->createForm(QuickLeadType::class, null, [
'method' => 'POST',
'csrf_protection' => false,
]);
/** @var User $user */
$user = $this->FOSUserManager->findUserByEmail($lead['email']);
if (!$user && !$hasEmail) {
$user = $this->userManager->findLatestByPhone($phoneNumber, $request->get('countryCode'));
}
if (!$user && $hasEmail) {
$user = $this->userManager->findAndReplaceUserAndEmail($phoneNumber, $lead['email'], $request->get('countryCode'));
}
$phone = $this->phoneManager->findOrSavePhoneNumber($phoneNumber, $request->get('countryCode'), null, $originalPhoneNumber);
if (!$user) {
$user = $this->FOSUserManager->createUser();
$user
->setFullName($lead['name'])
->setPhoneNumber($lead['phone'])
->setTempOriginalPhoneNumber($originalPhoneNumber)
->setEmail($lead['email'])
->setHasEmail($hasEmail)
->setIsQucikRegistered(true)
;
$this->userManager->quickRegister($user, $form, $request, true, false, false);
$registerMessage = $this->translator->trans('popup_form.success');
}
$this->phoneManager->addNewUserPhone($phoneNumber, $request->get('countryCode'), $user, true, false, null, $originalPhoneNumber);
}
if ($request->isMethod('POST')) {
// Get current logged in user
$user ??= $this->getUser();
$composer = $this->messageComposer;
$composer
->setSender($user)
->compose($message['content'], $listing, null, $message['type'] ?? LeadTypes::SEND_MESSAGE)
;
$this->addFlash(
'success',
$this->translator->trans('add_listing_page.success_messages.message_sent')
);
return [
'status' => 'ok',
'message' => $this->translator->trans('listing.success_message_seller'),
];
}
return $form;
}
/**
* Contact Seller Action.
*
* @Route("/listing/{id}/call_request", requirements={"id" = "\d+", "_format" = "json"},
* name="aqarmap_listing_call_request",
* options={"expose"=true},
* defaults={"_format": "json"},
* methods={"POST"}
* )
*
* @Rest\View()
*/
public function callRequest(Request $request, Listing $listing)
{
$lead = $request->get('lead');
$countryCode = $request->get('countryCode', $lead['countryCode'] ?? '+20');
$originalPhoneNumber = $lead['phone'];
$phoneNumber = $lead ? $this->phoneManager->trimZero($lead['phone'], $countryCode) : null;
$user = $this->getUser();
$registerMessage = '';
$callRequest = new CallRequest();
if ($lead) {
$form = $this->createForm(QuickLeadType::class, null, [
'method' => 'POST',
'csrf_protection' => false,
]);
$form->handleRequest($request);
$hasEmail = !$request->get('isAutoGeneratedEmail', 0);
/** @var User $user */
$user = $this->FOSUserManager->findUserByEmail($lead['email']);
if (!$user && !$hasEmail) {
$user = $this->userManager->findLatestByPhone($phoneNumber, $countryCode);
}
if (!$user && $hasEmail) {
$user = $this->userManager->findAndReplaceUserAndEmail($phoneNumber, $lead['email'], $request->get('countryCode'));
}
$phone = $this->phoneManager->findOrSavePhoneNumber($phoneNumber, $countryCode, null, $originalPhoneNumber);
if (!$user) {
$user = $this->FOSUserManager->createUser();
$user
->setFullName($lead['name'])
->setPhoneNumber($lead['phone'])
->setTempCountryCode($countryCode)
->setTempOriginalPhoneNumber($originalPhoneNumber)
->setEmail($lead['email'])
->setHasEmail($hasEmail)
->setIsQucikRegistered(true)
;
$this->userManager->quickRegister($user, $form, $request, true, false, false);
$registerMessage = $this->translator->trans('popup_form.success');
}
$callRequest->setPhone($phone);
$callRequest->setLeadEmail($lead['email']);
$callRequest->setLeadFullName($lead['name']);
$this->phoneManager->addNewUserPhone($phoneNumber, $countryCode, $user, true, false, null, $originalPhoneNumber);
}
// Create Call Request
$callRequest->setUser($user);
$callRequest->setListing($listing);
$form = $this->callRequestForm($listing);
$form->handleRequest($request);
$isPostRequestAndValidForm = $request->isMethod('POST') && ($form->isSubmitted() && $form->isValid());
$isNotCheckForm = (false == $request->get('check_form'));
if ($isPostRequestAndValidForm || $isNotCheckForm) {
try {
$this->callRequestManager->submitCallRequest($callRequest, null, $request->query->get('sourceRoute', ''));
return [
'status' => 'ok',
'message' => $this->translator->trans('listing.success_call_request'),
'registerMessage' => $registerMessage,
];
} catch (InvalidLeadValidationHttpException $exception) {
return [
'status' => $exception->getStatusCode(),
'message' => $exception->getMessage(),
];
}
}
return $form;
}
/**
* Show how to add a listing for new users.
*
* @Route("/add_listing", name="aqarmap_add_listing")
*/
public function addListingRoles(): Response
{
return $this->render(
'@AqarmapListing/Listing/addListingRoles.html.twig',
[
]
);
}
/**
* @Route("/listing/{id}/relist", requirements={"id" = "\d+"}, name="aqarmap_listing_relist", options={"expose"=true} )
*
* @Security("is_granted('ROLE_ADMIN') or is_granted('ROLE_OWNER', listing)")
*
* @return RedirectResponse|Response
*/
public function relist(Listing $listing)
{
if (!\in_array($listing->getStatus(), [ListingStatus::EXPIRED, ListingStatus::USER_DELETED])) {
throw new LogicHttpException('Whoops! Looks like the listing you are trying to relist in not expired!');
}
$em = $this->getDoctrine()->getManager();
$listingRepo = $em->getRepository(Listing::class);
$relistChild = $listingRepo->getRelistChild($listing);
if ($relistChild) {
$this->addFlash(
'success',
$this->translator->trans('add_listing_page.success_messages.relist')
);
return new RedirectResponse(
$this
->generateUrl(
'listing_slug',
['id' => $relistChild->getId(),
'slug' => $relistChild->getSlug(), ]
)
)
;
}
$listing = $this->listingManager->relist($listing);
// Check if the listing require more photos or require repayment, and redirection.
$listingEvent = new ListingEvent($listing);
$this->dispatcher->dispatch($listingEvent, 'aqarmap.listing.resubmitted');
$response = $listingEvent->getResponse();
if (null === $response) {
if (\in_array($listing->getStatus(), [ListingStatus::PENDING, ListingStatus::LIVE])) {
$this->addFlash(
'success',
$this->translator->trans('add_listing_page.success_messages.relist')
);
}
$response = new RedirectResponse(
$this
->generateUrl(
'listing_slug',
[
'id' => $listing->getId(),
'slug' => $listing->getSlug(),
]
)
);
}
return $response;
}
/**
* @Route(
* "/listing/transfer/scraped/{id}",
* requirements={"id" = "\d+"},
* name="aqarmap_listing_transfer_ownership",
* options={"expose"=true},
* methods={"POST"},
* )
*/
public function transferScrapedListingOwnership(Listing $listing)
{
/** @var User $user */
$user = $this->getUser();
/** @var EntityManager $em */
$em = $this->getDoctrine()->getManager();
if (!$listing->canChangeScrapedListing()) {
throw new LogicHttpException();
}
$listing->setUser($user);
$em->persist($listing);
$em->flush($listing);
return new JsonResponse();
}
/**
* @Route("/listing/{id}/pump_up",
* requirements={"id" = "\d+"}, name="confirm_listing_pump_up", methods={"POST"})
*
* @Security("is_granted('ROLE_OWNER', listing)")
*/
public function confirmPumpUpListing(Listing $listing, Request $request): RedirectResponse
{
$pumpUpForm = $this->confirmFeaturedPaymentForm($listing);
$pumpUpForm->handleRequest($request);
if ($request->isMethod('POST') && $pumpUpForm->isValid()) {
if (!$pumpUpForm->get('confirm')->isClicked()) {
return $this->redirect($this->generateUrl('aqarmap_listing_default_mylistings'), Response::HTTP_FOUND);
}
try {
$this->listingManager->pumpUp($listing);
$this->addFlash(
'success',
$this->translator->trans('credit.pump_up_success', [':listing_title:' => $listing->getTitle()])
);
} catch (\Exception $e) {
$this->addFlash('danger', $e->getMessage());
}
}
return $this->redirect($this->generateUrl('aqarmap_listing_default_mylistings'));
}
/**
* @Route("/listing/{id}/pump_up",
* requirements={"id" = "\d+"}, name="listing_pump_up", methods={"GET"})
*
* @Security("is_granted('ROLE_OWNER', listing)")
*
* @return array|RedirectResponse
*/
public function pumpUpListing(Listing $listing)
{
$listingRules = $this->listingManager->getListingRules($listing);
$listingOwner = $listing->getUser();
$pumpUpFees = $listingRules['pump_up_fees'];
$pumpUpOccurrence = $listingRules['pump_up_occurrence'];
$pumpUpDuration = $listingRules['pump_up_duration'];
if (!$this->listingManager->isPumpUpAvailable($listingRules)) {
$this->addFlash(
'danger',
$this->translator->trans('credit.pump_up_not_available')
);
return $this->redirect($this->generateUrl('aqarmap_listing_default_mylistings'));
}
if (!$this->listingManager->isAffordable($listingOwner, $pumpUpFees)) {
$this->addFlash(
'danger',
$this->translator->trans('credit.pump_up_can_not_use')
);
return $this->redirect($this->generateUrl('aqarmap_listing_default_mylistings'));
}
/** @var $em \Doctrine\ORM\EntityManager */
$em = $this->getDoctrine()->getManager();
$em->getRepository(Credit::class);
$pumpUpForm = $this->createForm(ConfirmFeaturedFormType::class, null, [
'method' => 'POST',
'action' => $this
->generateUrl(
'listing_pump_up',
['id' => $listing->getId()]
),
'confirm_message' => $this->translator->trans('listing.pump_up.confirm'),
'cancel_message' => $this->translator->trans('listing.pump_up.cancel'),
]);
return $this->render(
'@AqarmapListing/Listing/pumpUpListing.html.twig',
[
'fees' => $pumpUpFees,
'duration' => $pumpUpDuration,
'occurrence' => $pumpUpOccurrence,
'form' => $pumpUpForm->createView(),
]
);
}
/**
* Listing Details Single Page App.
*
* @Route("/listingApp/{id}", requirements={"id" = "\d+"} , options={"expose" = true} , name="listing_details_app", methods={"GET"})
*/
public function listingDetailsApp(Listing $listing): Response
{
return $this->render(
'@AqarmapListing/Listing/listingDetailsApp.html.twig',
[
'listingId' => $listing->getReferenceId(),
]
);
}
/**
* Delete Listing Photos.
*
* @Route("/photos/delete", name="listing_bulk_delete_photo", requirements={"id" = "\d+"})
*
* @throws \Doctrine\ORM\OptimisticLockException
*/
public function bulkDeletePhoto(Request $request, ListingPhotoRepository $listingPhotoRepository, ListingManager $listingManager): RedirectResponse
{
$photosIds = $request->get('photos');
try {
if ($photosIds) {
$photos = $listingPhotoRepository->getPhotos($photosIds);
$listingManager->bulkDeletePhotos($photos);
} else {
$this->addFlash('danger', 'No photos selected for deletion');
}
} catch (\Exception $e) {
$this->addFlash('danger', 'Something went wrong');
}
return $this->redirect($request->headers->get('referer') ?: $this->generateUrl('homepage'));
}
/**
* Update WhatsApp Phones.
*/
private function updateWhatsAppPhones(int $userId, array $phones = [], array $whatsApp = []): void
{
foreach ($phones as $index => $phone) {
$whatsApp[$index] = isset($whatsApp[$index]) && 'true' === $whatsApp[$index];
$this->phoneManager->updateWhatsApp($userId, (int) $phone, $whatsApp[$index], true);
}
}
}