src/Aqarmap/Bundle/ListingBundle/Repository/LocationRepository.php line 32

Open in your IDE?
  1. <?php
  2. namespace Aqarmap\Bundle\ListingBundle\Repository;
  3. use Aqarmap\Bundle\ListingBundle\Constant\ListingCategories;
  4. use Aqarmap\Bundle\ListingBundle\Constant\ListingStatus;
  5. use Aqarmap\Bundle\ListingBundle\Entity\Location;
  6. use Aqarmap\Bundle\ListingBundle\Entity\PropertyType;
  7. use Aqarmap\Bundle\MainBundle\Constant\Locales;
  8. use Aqarmap\Bundle\SearchBundle\Entity\SearchResultCombinations;
  9. use Aqarmap\Bundle\UserBundle\Entity\User;
  10. use Doctrine\ORM\EntityManagerInterface;
  11. use Doctrine\ORM\Event\LifecycleEventArgs;
  12. use Doctrine\ORM\Events;
  13. use Doctrine\ORM\Internal\Hydration\IterableResult;
  14. use Doctrine\ORM\NonUniqueResultException;
  15. use Doctrine\ORM\NoResultException;
  16. use Doctrine\ORM\Query;
  17. use Doctrine\ORM\Query\Expr;
  18. use Doctrine\ORM\QueryBuilder;
  19. use Gedmo\Translatable\Query\TreeWalker\TranslationWalker;
  20. use Gedmo\Translatable\TranslatableListener;
  21. use Gedmo\Tree\Entity\Repository\NestedTreeRepository;
  22. class LocationRepository extends NestedTreeRepository
  23. {
  24.     public const RECENT_SEARCHED_LOCATIONS_COUNT 16;
  25.     public const ONE_RESULT_NUMBER 1;
  26.     public function __construct(EntityManagerInterface $manager)
  27.     {
  28.         parent::__construct($manager$manager->getClassMetadata(Location::class));
  29.     }
  30.     public function search(array $criteria)
  31.     {
  32.         $QueryBuilder $this->createQueryBuilder('lo');
  33.         if (isset($criteria['is_disabled'])) {
  34.             $QueryBuilder
  35.                 ->andWhere($QueryBuilder->expr()
  36.                     ->eq('lo.disabled'':disabled'))
  37.                 ->setParameter('disabled'$criteria['is_disabled']);
  38.         }
  39.         if (isset($criteria['level'])) {
  40.             $QueryBuilder
  41.                 ->andWhere($QueryBuilder->expr()->eq('lo.level'':level'))
  42.                 ->setParameter('level'$criteria['level']);
  43.         }
  44.         // Search
  45.         if (!empty($criteria['search']) && !empty($criteria['q'])) {
  46.             $criteria['q'] = trim($criteria['q']);
  47.             switch ($criteria['search']) {
  48.                 case 'location_id':
  49.                     $QueryBuilder
  50.                         ->andWhere($QueryBuilder->expr()->in('lo.id'':location_id'))
  51.                         ->setParameter('location_id'$criteria['q']);
  52.                     break;
  53.                 case 'parent_id':
  54.                     $QueryBuilder
  55.                         ->andWhere($QueryBuilder->expr()->in('lo.parent'':parent_id'))
  56.                         ->setParameter('parent_id'$criteria['q']);
  57.                     break;
  58.                 case 'title':
  59.                     $QueryBuilder
  60.                         ->join('lo.translations''lot'Expr\Join::WITH'lot.field = :title_field')
  61.                         ->andWhere($QueryBuilder->expr()->orX(
  62.                             $QueryBuilder->expr()->like('lot.content'':title'),
  63.                             $QueryBuilder->expr()->like('lo.title'':title')
  64.                         ))
  65.                         ->setParameter('title_field''title')
  66.                         ->setParameter('title'"{$criteria['q']}%");
  67.                     break;
  68.             }
  69.         }
  70.         return $QueryBuilder;
  71.     }
  72.     /**
  73.      * @param bool $searchableOnly
  74.      *
  75.      * @internal param null $locale
  76.      *
  77.      * @return array
  78.      */
  79.     public function getLocationsList($searchableOnly false$estimatable false)
  80.     {
  81.         $QueryBuilder $this->createQueryBuilder('lo');
  82.         $QueryBuilder
  83.             ->andWhere($QueryBuilder->expr()->isNull('lo.parent'));
  84.         $QueryBuilder
  85.             ->andWhere($QueryBuilder->expr()->eq('lo.disabled'':disabled'))
  86.             ->setParameter('disabled'false, \PDO::PARAM_BOOL);
  87.         if ($searchableOnly) {
  88.             $QueryBuilder
  89.                 ->andWhere($QueryBuilder->expr()->eq('lo.searchable'':is_searchable'))
  90.                 ->setParameter('is_searchable'true, \PDO::PARAM_BOOL);
  91.         }
  92.         if ($estimatable) {
  93.             $QueryBuilder
  94.                 ->andWhere($QueryBuilder->expr()->eq('lo.estimate'':is_estimatable'))
  95.                 ->setParameter('is_estimatable'true, \PDO::PARAM_BOOL);
  96.         }
  97.         $query $QueryBuilder->getQuery();
  98.         $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker');
  99.         return $query;
  100.     }
  101.     public function getLocationFlat($criteria)
  102.     {
  103.         $criteria array_merge([
  104.             'searchable' => null,
  105.             'estimatable' => null,
  106.             'level' => null,
  107.         ], $criteria);
  108.         $QueryBuilder $this->createQueryBuilder('lo');
  109.         $QueryBuilder
  110.             ->andWhere($QueryBuilder->expr()->eq('lo.disabled'':disabled'))
  111.             ->setParameter('disabled'false, \PDO::PARAM_BOOL);
  112.         if ((int) $criteria['searchable']) {
  113.             $QueryBuilder
  114.                 ->andWhere($QueryBuilder->expr()->eq('lo.searchable'':is_searchable'))
  115.                 ->setParameter('is_searchable'true, \PDO::PARAM_BOOL);
  116.         }
  117.         if ((int) $criteria['estimatable']) {
  118.             $QueryBuilder
  119.                 ->andWhere($QueryBuilder->expr()->eq('lo.estimate'':is_estimatable'))
  120.                 ->setParameter('is_estimatable'true, \PDO::PARAM_BOOL);
  121.         }
  122.         if (null !== $criteria['level']) {
  123.             $QueryBuilder
  124.                 ->andWhere($QueryBuilder->expr()->eq('lo.level'':level'))
  125.                 ->setParameter('level'$criteria['level']);
  126.         }
  127.         $query $QueryBuilder->getQuery();
  128.         $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker');
  129.         return $query;
  130.     }
  131.     /**
  132.      * Get location children flat.
  133.      *
  134.      * @return Location|array
  135.      */
  136.     public function getLocationChildrenFlat(Location $location)
  137.     {
  138.         $QueryBuilder $this->createQueryBuilder('lo');
  139.         $QueryBuilder
  140.             ->andWhere($QueryBuilder->expr()->eq('lo.parent'':parent_id'))
  141.             ->setParameter('parent_id'$location);
  142.         return $QueryBuilder->getQuery();
  143.     }
  144.     /**
  145.      * Get location children flat Array of Results.
  146.      *
  147.      * @param string $locale
  148.      *
  149.      * @return Location|array
  150.      */
  151.     public function getLocationChildrenFlatResults(Location $location$locale null)
  152.     {
  153.         $QueryBuilder $this->createQueryBuilder('lo');
  154.         $QueryBuilder
  155.             ->andWhere($QueryBuilder->expr()->eq('lo.parent'':parent_id'))
  156.             ->setParameter('parent_id'$location);
  157.         $query $QueryBuilder
  158.             ->getQuery()
  159.             ->setHint(Query::HINT_CUSTOM_OUTPUT_WALKERTranslationWalker::class);
  160.         if ($locale) {
  161.             $query->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE$locale);
  162.         }
  163.         return $query->getArrayResult();
  164.     }
  165.     /**
  166.      * @internal param null $locale
  167.      *
  168.      * @return Query
  169.      *
  170.      * @internal param User $user
  171.      * @internal param bool $iteration
  172.      */
  173.     public function getSectionLocationsWithLiveListings(Section $section)
  174.     {
  175.         $QueryBuilder $this->createQueryBuilder('lo');
  176.         $QueryBuilder
  177.             ->leftJoin('lo.listings''lol');
  178.         $QueryBuilder
  179.             ->andWhere($QueryBuilder->expr()->eq('lo.disabled'':disabled'))
  180.             ->setParameter('disabled'false, \PDO::PARAM_BOOL);
  181.         if ($section) {
  182.             $QueryBuilder
  183.                 ->andWhere($QueryBuilder->expr()->eq('lol.section'':section'))
  184.                 ->setParameter('section'$section);
  185.         }
  186.         $QueryBuilder
  187.             ->andWhere($QueryBuilder->expr()->eq('lol.status'':status'))
  188.             ->setParameter('status'ListingStatus::LIVE);
  189.         $query $QueryBuilder->getQuery();
  190.         $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker');
  191.         return $query->getResult();
  192.     }
  193.     /**
  194.      * @return array
  195.      *
  196.      * @internal param int $level
  197.      * @internal param bool $searchableOnly
  198.      * @internal param null $locale
  199.      */
  200.     public function getLeveledLocations(array $criteria)
  201.     {
  202.         $QueryBuilder $this->createQueryBuilder('lo');
  203.         $QueryBuilder
  204.             ->andWhere($QueryBuilder->expr()->eq('lo.disabled'':disabled'))
  205.             ->setParameter('disabled'false, \PDO::PARAM_BOOL);
  206.         if (!empty($criteria['parent'])) {
  207.             if ('no-parent' == $criteria['parent']) {
  208.                 $QueryBuilder
  209.                     ->andWhere($QueryBuilder->expr()->isNull('lo.parent'));
  210.             } else {
  211.                 $QueryBuilder
  212.                     ->andWhere($QueryBuilder->expr()->eq('lo.parent'':parent'))
  213.                     ->setParameter('parent'$criteria['parent']);
  214.             }
  215.         }
  216.         if (isset($criteria['level'])) {
  217.             $QueryBuilder
  218.                 ->andWhere($QueryBuilder->expr()->lte('lo.level'':level'))
  219.                 ->setParameter('level'$criteria['level']);
  220.         }
  221.         $QueryBuilder->orderBy('lo.listingsCounter''desc');
  222.         $query $QueryBuilder->getQuery();
  223.         $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker');
  224.         return $query->getResult();
  225.     }
  226.     public function getLeveledLocationsArray(array $criteria)
  227.     {
  228.         $queryBuilder $this->createQueryBuilder('location');
  229.         $queryBuilder
  230.             ->select('location.id as id, COALESCE(translation.content, location.title) as title, location.slug as slug')
  231.             ->leftJoin(
  232.                 'location.translations',
  233.                 'translation',
  234.                 Expr\Join::WITH,
  235.                 'translation.locale = :locale and translation.field = :title and translation.object = location.id'
  236.             )
  237.             ->andWhere($queryBuilder->expr()->eq('location.disabled'':disabled'))
  238.             ->setParameter('locale'$criteria['locale'])
  239.             ->setParameter('title''title')
  240.             ->setParameter('disabled'false, \PDO::PARAM_BOOL);
  241.         if (!empty($criteria['parent'])) {
  242.             if ('no-parent' == $criteria['parent']) {
  243.                 $queryBuilder->andWhere($queryBuilder->expr()->isNull('location.parent'));
  244.             } else {
  245.                 $queryBuilder
  246.                     ->andWhere($queryBuilder->expr()->eq('location.parent'':parent'))
  247.                     ->setParameter('parent'$criteria['parent']);
  248.             }
  249.         }
  250.         if (!empty($criteria['level'])) {
  251.             $queryBuilder
  252.                 ->andWhere($queryBuilder->expr()->lte('location.level'':level'))
  253.                 ->setParameter('level'$criteria['level']);
  254.         }
  255.         if (!empty($criteria['searchResultsCombinationMinimumCount'])) {
  256.             $queryBuilder->join(
  257.                 SearchResultCombinations::class,
  258.                 'searchResultCombinations',
  259.                 Expr\Join::WITH,
  260.                 'searchResultCombinations.location = location.id'
  261.             )
  262.                 ->andWhere($queryBuilder->expr()->gte('searchResultCombinations.searchResultCount'':searchResultCount'))
  263.                 ->setParameter('searchResultCount'$criteria['searchResultsCombinationMinimumCount']);
  264.             if (isset($criteria['propertyType'])) {
  265.                 $queryBuilder->andWhere($queryBuilder->expr()->eq('searchResultCombinations.propertyType'':propertyType'))
  266.                     ->setParameter('propertyType'$criteria['propertyType']);
  267.             }
  268.             if (isset($criteria['section'])) {
  269.                 $queryBuilder->andWhere($queryBuilder->expr()->eq('searchResultCombinations.section'':section'))
  270.                     ->setParameter('section'$criteria['section']);
  271.             }
  272.             if (!empty($criteria['searchResultsCombinationMax'])) {
  273.                 $queryBuilder->addSelect('MAX(searchResultCombinations.searchResultCount) as searchResultCount');
  274.             } else {
  275.                 $queryBuilder->addSelect('searchResultCombinations.searchResultCount as searchResultCount');
  276.             }
  277.             $queryBuilder->orderBy('searchResultCombinations.searchResultCount''desc');
  278.         } else {
  279.             $queryBuilder->orderBy('location.listingsCounter''desc');
  280.         }
  281.         return $queryBuilder;
  282.     }
  283.     /**
  284.      * @return Location
  285.      */
  286.     public function getSearchableOrNeighbourhoodNearestParent(Location $location)
  287.     {
  288.         $QueryBuilder $this->createQueryBuilder('lo');
  289.         $QueryBuilder
  290.             ->andWhere('lo.root = :root')
  291.             ->andWhere('lo.left <= :left')
  292.             ->andWhere('lo.right >= :right')
  293.             ->setParameter('left'$location->getLeft())
  294.             ->setParameter('right'$location->getRight())
  295.             ->setParameter('root'$location->getRoot());
  296.         $QueryBuilder
  297.             ->andWhere('lo.neighborhoodFilter = :is_neighbourhood OR lo.searchable  = :is_searchable')
  298.             ->setParameter('is_neighbourhood'true, \PDO::PARAM_BOOL)
  299.             ->setParameter('is_searchable'true, \PDO::PARAM_BOOL);
  300.         $QueryBuilder
  301.             ->orderBy('lo.level''DESC')
  302.             ->setMaxResults(1);
  303.         $query $QueryBuilder->getQuery();
  304.         $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker');
  305.         return $query->getOneOrNullResult();
  306.     }
  307.     // --------------------------------------------------------------------
  308.     /**
  309.      * Get location children.
  310.      *
  311.      * @return Location|array
  312.      */
  313.     public function getLocationChildren(Location $location)
  314.     {
  315.         $locationChildren $this->children($location);
  316.         $location array_merge([$location], $locationChildren);
  317.         return $location;
  318.     }
  319.     /**
  320.      * @return array
  321.      */
  322.     public function getLocationChildrenIds(Location $location)
  323.     {
  324.         $locationChildrenIds $this->childrenIds($location);
  325.         $location array_merge([$location->getId()], array_column(array_values($locationChildrenIds), 'id'));
  326.         return $location;
  327.     }
  328.     /**
  329.      * @return array
  330.      */
  331.     public function childrenIds(Location $location)
  332.     {
  333.         $queryBuilder $this->createQueryBuilder('location');
  334.         $queryBuilder->select('location.id');
  335.         $queryBuilder->where($queryBuilder->expr()->lt('location.right'$location->getRight()));
  336.         $queryBuilder->andWhere($queryBuilder->expr()->gt('location.left'$location->getLeft()));
  337.         $queryBuilder->andWhere($queryBuilder->expr()->eq('location.root'':rid'));
  338.         $queryBuilder->setParameter('rid'$location->getRoot());
  339.         return $queryBuilder
  340.             ->getQuery()
  341.             ->enableResultCache(1800sprintf('location_children_ids_%d_%d'$location->getRight(), $location->getLeft()))
  342.             ->getResult();
  343.     }
  344.     // --------------------------------------------------------------------
  345.     /**
  346.      * Get neighbourhood locations.
  347.      *
  348.      * @return Location|array
  349.      */
  350.     public function getNeighbourhoodLocations($criteria = [])
  351.     {
  352.         $QueryBuilder $this->createQueryBuilder('lo');
  353.         $QueryBuilder
  354.             ->andWhere($QueryBuilder->expr()->eq('lo.neighborhoodFilter'':is_true'))
  355.             ->setParameter('is_true'true, \PDO::PARAM_BOOL);
  356.         $QueryBuilder
  357.             ->andWhere($QueryBuilder->expr()->eq('lo.disabled'':disabled'))
  358.             ->setParameter('disabled'false, \PDO::PARAM_BOOL);
  359.         if (isset($criteria['level'])) {
  360.             $QueryBuilder
  361.                 ->andWhere($QueryBuilder->expr()->eq('lo.level'':level'))
  362.                 ->setParameter('level'$criteria['level']);
  363.         }
  364.         if (isset($criteria['maxLevel'])) {
  365.             $QueryBuilder
  366.                 ->andWhere($QueryBuilder->expr()->lte('lo.level'':maxLevel'))
  367.                 ->setParameter('maxLevel'$criteria['maxLevel']);
  368.         }
  369.         $query $QueryBuilder->getQuery();
  370.         return $query->getResult();
  371.     }
  372.     /**
  373.      * Get neighbourhood  sub-locations.
  374.      *
  375.      * @return Location|array
  376.      */
  377.     public function getNeighbourhoodSubLocations(Location $locationPropertyType $propertyType)
  378.     {
  379.         $QueryBuilder $this->createQueryBuilder('lo')
  380.             ->join('lo.locationStatistics''location_statistics'Expr\Join::LEFT_JOIN);
  381.         $QueryBuilder
  382.             ->andWhere($QueryBuilder->expr()->eq('lo.parent'':location'))
  383.             ->setParameter('location'$location);
  384.         $QueryBuilder
  385.             ->andWhere($QueryBuilder->expr()->eq('lo.disabled'':disabled'))
  386.             ->setParameter('disabled'false, \PDO::PARAM_BOOL);
  387.         $QueryBuilder
  388.             ->andWhere($QueryBuilder->expr()->eq('location_statistics.propertyType'':property_type'))
  389.             ->setParameter('property_type'$propertyType);
  390.         $QueryBuilder
  391.             ->andWhere($QueryBuilder->expr()->eq('lo.neighborhoodFilter'':is_true'))
  392.             ->setParameter('is_true'true, \PDO::PARAM_BOOL);
  393.         $QueryBuilder
  394.             ->andWhere($QueryBuilder->expr()->isNotNull('location_statistics.avgPrice'));
  395.         $QueryBuilder
  396.             ->andWhere($QueryBuilder->expr()->neq('location_statistics.avgPrice'0));
  397.         $QueryBuilder
  398.             ->orderBy('location_statistics.avgPrice''DESC');
  399.         $query $QueryBuilder->getQuery();
  400.         return $query->getResult();
  401.     }
  402.     /**
  403.      * Get neighbourhood Compounds.
  404.      *
  405.      * @param null $state
  406.      *
  407.      * @return Location|array
  408.      */
  409.     public function getNeighbourhoodCompounds($locations null$state null)
  410.     {
  411.         $QueryBuilder $this->createQueryBuilder('lo')
  412.             ->join('lo.locationCompound''lc'Expr\Join::INNER_JOIN);
  413.         $QueryBuilder
  414.             ->andWhere($QueryBuilder->expr()->eq('lo.compoundFilter'':is_true'))
  415.             ->setParameter('is_true'true, \PDO::PARAM_BOOL);
  416.         if ($locations) {
  417.             $QueryBuilder
  418.                 ->andWhere($QueryBuilder->expr()->orX(
  419.                     $QueryBuilder->expr()->in('lo.parent'':locations')
  420.                 ))
  421.                 ->setParameter('locations'$locations);
  422.         }
  423.         if ($state) {
  424.             $QueryBuilder
  425.                 ->andWhere($QueryBuilder->expr()->eq('lc.state'':state'))
  426.                 ->setParameter('state'$state);
  427.         }
  428.         $query $QueryBuilder->getQuery();
  429.         return $query->getResult();
  430.     }
  431.     /**
  432.      * @return array
  433.      */
  434.     public function generateNearestLocations(Location $location$distance)
  435.     {
  436.         $QueryBuilder $this->createQueryBuilder('lo');
  437.         $QueryBuilder
  438.             ->andWhere($QueryBuilder->expr()->eq('lo.disabled'':disabled'))
  439.             ->setParameter('disabled'false, \PDO::PARAM_BOOL);
  440.         $QueryBuilder
  441.             ->andWhere($QueryBuilder->expr()->eq('lo.level'':level'))
  442.             ->setParameter('level'$location->getLevel());
  443.         $QueryBuilder
  444.             ->andWhere($QueryBuilder->expr()->neq('lo'':location'))
  445.             ->setParameter('location'$location);
  446.         if ($location->getParent()) {
  447.             $QueryBuilder
  448.                 ->andWhere($QueryBuilder->expr()->eq('lo.parent'':parent'))
  449.                 ->setParameter('parent'$location->getParent());
  450.         }
  451.         $QueryBuilder $this->getNearestLocationsFormulaQuery($QueryBuilder$location$distance);
  452.         $query $QueryBuilder->getQuery();
  453.         return $query->getResult();
  454.     }
  455.     /**
  456.      * @return Query
  457.      */
  458.     public function generateNearestLocationsQuery(array $criteria)
  459.     {
  460.         /** @var Location $location */
  461.         $location $criteria['location'];
  462.         $listingQueryBuilder $this->_em->createQueryBuilder();
  463.         $listingQueryBuilder $listingQueryBuilder
  464.             ->select('MAX(li.id)')
  465.             ->from(Listing::class, 'li')
  466.             ->andWhere($listingQueryBuilder->expr()->eq('li.status'ListingStatus::LIVE))
  467.             ->andWhere($listingQueryBuilder->expr()->neq('li.category'ListingCategories::PROJECTS));
  468.         if (isset($criteria['propertyType']) && $criteria['propertyType']) {
  469.             $listingQueryBuilder->andWhere($listingQueryBuilder->expr()->in('li.propertyType'$criteria['propertyType']));
  470.         }
  471.         if (isset($criteria['section']) && $criteria['section']) {
  472.             $listingQueryBuilder->andWhere($listingQueryBuilder->expr()->eq('li.section'$criteria['section']));
  473.         }
  474.         $queryBuilder $this->createQueryBuilder('lo');
  475.         $queryBuilder->addSelect('ST_Distance_Sphere( Point(:longitude, :latitude), Point(lo.lon, lo.lat)) AS distance');
  476.         $queryBuilder
  477.             ->andWhere($queryBuilder->expr()->eq('lo.disabled'':disabled'))
  478.             ->setParameter('disabled'false, \PDO::PARAM_BOOL);
  479.         $queryBuilder->innerJoin(
  480.             'lo.listings',
  481.             'listings',
  482.             Expr\Join::WITH,
  483.             $queryBuilder->expr()->eq(
  484.                 'listings.id',
  485.                 sprintf('(%s)'$listingQueryBuilder
  486.                     ->andWhere($listingQueryBuilder->expr()->eq('li.location''lo.id'))
  487.                     ->setMaxResults(1)->getQuery()->getDQL())
  488.             )
  489.         );
  490.         $queryBuilder
  491.             ->andWhere($queryBuilder->expr()->neq('lo'':location'))
  492.             ->setParameter('location'$location);
  493.         if (isset($criteria['excludedSubLocations']) && $criteria['excludedSubLocations']) {
  494.             $queryBuilder
  495.                 ->andWhere($queryBuilder->expr()->notIn('lo'':subLocations'))
  496.                 ->setParameter('subLocations'$this->getLocationChildrenIds($location));
  497.         }
  498.         $queryBuilder->andWhere($queryBuilder->expr()->neq('lo.listingsCounter'0));
  499.         $queryBuilder->andWhere($queryBuilder->expr()->lt('ABS(lo.lat)'90));
  500.         $queryBuilder->andWhere($queryBuilder->expr()->lt('ABS(lo.lon)'180));
  501.         $queryBuilder->andWhere($queryBuilder->expr()->isNotNull('lo.lat'));
  502.         $queryBuilder->andWhere($queryBuilder->expr()->isNotNull('lo.lon'));
  503.         $queryBuilder
  504.             ->having('distance  <= :maxDistance')
  505.             ->setParameter('maxDistance'$criteria['maxDistance'] * 1000)
  506.             ->setParameter('latitude'$location->getCenterLat())
  507.             ->setParameter('longitude'$location->getCenterLng());
  508.         $queryBuilder->orderBy('distance');
  509.         return $queryBuilder->getQuery();
  510.     }
  511.     public function getNearestLocationsFormulaQuery(QueryBuilder $queryBuilderLocation $location$distance): QueryBuilder
  512.     {
  513.         return $queryBuilder
  514.             ->having('( 3959 * acos(cos(radians(:latitude))'.
  515.                 '* cos( radians( lo.lat ) )'.
  516.                 '* cos( radians( lo.lon )'.
  517.                 '- radians(:longitude) )'.
  518.                 '+ sin( radians(:latitude) )'.
  519.                 '* sin( radians( lo.lat ) ) ) )  < :distance')
  520.             ->setParameter('distance'$distance)
  521.             ->setParameter('latitude'$location->getCenterLat())
  522.             ->setParameter('longitude'$location->getCenterLng());
  523.     }
  524.     /**
  525.      * Get Nearest Compounds.
  526.      *
  527.      * @return Location|array
  528.      */
  529.     public function getNearestLocations(array $locations = [], bool $limit trueint $max 3)
  530.     {
  531.         $QueryBuilder $this->createQueryBuilder('lo')
  532.             ->join('lo.nearestLocations''nearest_locations'Expr\Join::INNER_JOIN);
  533.         $QueryBuilder
  534.             ->andWhere($QueryBuilder->expr()->eq('lo.searchable'':is_searchable'))
  535.             ->setParameter('is_searchable'true, \PDO::PARAM_BOOL);
  536.         $QueryBuilder
  537.             ->andWhere($QueryBuilder->expr()->in('nearest_locations.id'':locations'))
  538.             ->setParameter('locations'$locations);
  539.         if ($limit) {
  540.             $QueryBuilder->setMaxResults($max);
  541.         }
  542.         return $QueryBuilder->getQuery()->enableResultCache()->getResult();
  543.     }
  544.     /**
  545.      * @internal param null $locale
  546.      *
  547.      * @param string $locale
  548.      * @param null $levelLimit
  549.      *
  550.      * @return array
  551.      */
  552.     public function getAllSearchableLocationsList($levelLimit null$locale null)
  553.     {
  554.         $QueryBuilder $this->createQueryBuilder('lo');
  555.         $QueryBuilder
  556.             ->andWhere($QueryBuilder->expr()->eq('lo.disabled'':disabled'))
  557.             ->setParameter('disabled'false, \PDO::PARAM_BOOL);
  558.         if ($levelLimit) {
  559.             $QueryBuilder
  560.                 ->andWhere($QueryBuilder->expr()->lt('lo.level'':level'))
  561.                 ->setParameter('level'$levelLimit);
  562.         }
  563.         $query $QueryBuilder
  564.             ->getQuery()
  565.             ->setHint(Query::HINT_CUSTOM_OUTPUT_WALKERTranslationWalker::class);
  566.         if ($locale) {
  567.             $query->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE$locale);
  568.         }
  569.         return $query->getResult();
  570.     }
  571.     /**
  572.      * @return array
  573.      */
  574.     public function getAllLocationsCount()
  575.     {
  576.         $QueryBuilder $this->createQueryBuilder('lo')->select('count(lo.id)');
  577.         $QueryBuilder
  578.             ->andWhere($QueryBuilder->expr()->eq('lo.disabled'':disabled'))
  579.             ->setParameter('disabled'false, \PDO::PARAM_BOOL);
  580.         return $QueryBuilder->getQuery()->getSingleScalarResult();
  581.     }
  582.     /**
  583.      * Get Nearest Neighbourhoods or  Compounds.
  584.      *
  585.      * @return Location|array
  586.      */
  587.     public function getNearestNeighbourhoods(Location $location)
  588.     {
  589.         $QueryBuilder $this->createQueryBuilder('lo')
  590.             ->join('lo.nearestLocations''nearest_locations'Expr\Join::INNER_JOIN);
  591.         if ($location->getCompoundFilter()) {
  592.             $QueryBuilder
  593.                 ->andWhere($QueryBuilder->expr()->eq('lo.compoundFilter'':is_true'))
  594.                 ->setParameter('is_true'true, \PDO::PARAM_BOOL);
  595.         }
  596.         if ($location->getNeighborhoodFilter()) {
  597.             $QueryBuilder
  598.                 ->andWhere($QueryBuilder->expr()->eq('lo.neighborhoodFilter'':is_true'))
  599.                 ->setParameter('is_true'true, \PDO::PARAM_BOOL);
  600.         }
  601.         $QueryBuilder
  602.             ->andWhere($QueryBuilder->expr()->eq('nearest_locations.id'':location'))
  603.             ->setParameter('location'$location);
  604.         $QueryBuilder->setMaxResults(3);
  605.         $query $QueryBuilder->getQuery();
  606.         return $query->getResult();
  607.     }
  608.     /**
  609.      * @param bool $forceLocale
  610.      *
  611.      * @return Location
  612.      */
  613.     public function getLocationLike($location$forceLocale true)
  614.     {
  615.         $queryBuilder $this->createQueryBuilder('p')
  616.             ->where('p.title LIKE :location')
  617.             ->setParameter('location''%'.$location.'%')
  618.             ->getQuery()
  619.             ->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker');
  620.         if ($forceLocale) {
  621.             $queryBuilder->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE'en');
  622.         }
  623.         return $queryBuilder->setMaxResults(1)
  624.             ->getOneOrNullResult();
  625.     }
  626.     /**
  627.      * Get locations by keyword.
  628.      *
  629.      * @return Query
  630.      */
  631.     public function getLocationByKeyword(?string $keyword null)
  632.     {
  633.         return $this->createQueryBuilder('l')
  634.             ->select('l')
  635.             ->where('FIND_IN_SET(:keyword, l.keyword) > 0')
  636.             ->setParameter('keyword'$keyword)
  637.             ->getQuery();
  638.     }
  639.     public function getWhereHasBumpableListings()
  640.     {
  641.         $queryBuilder $this->createQueryBuilder('l');
  642.         return $queryBuilder
  643.             ->select('l, li, lf')
  644.             ->join('l.listings''li'Expr\Join::WITH'l.id=li.location')
  645.             ->join('li.listingFeatures''lf'Expr\Join::WITH'li.id=lf.listing')
  646.             ->where($queryBuilder->expr()->eq('li.isBumped'':isBumped'))
  647.             ->setParameter(':isBumped'true, \PDO::PARAM_BOOL)
  648.             ->andWhere($queryBuilder->expr()->isNull('lf.expiresAt'))
  649.             ->andWhere('lf.bumpsCount < lf.bumpUpOccurrences')
  650.             ->orWhere($queryBuilder->expr()->isNull('lf.bumpsCount'))
  651.             ->andWhere($queryBuilder->expr()->lte('lf.nextBumpDate'':nextBumpDate'))
  652.             ->setParameter(':nextBumpDate', (new \DateTime())->setTime(000))
  653.             ->orderBy('lf.nextBumpDate''DESC')
  654.             ->addOrderBy('lf.id''DESC')
  655.             ->addOrderBy('lf.listing''DESC')
  656.             ->setMaxResults(100)
  657.             ->getQuery()
  658.             ->getResult();
  659.     }
  660.     /**
  661.      * @param bool $status
  662.      *
  663.      * @throws \Doctrine\ORM\OptimisticLockException
  664.      */
  665.     public function changeStatus(Location $location$status true)
  666.     {
  667.         $queryBuilder $this->createQueryBuilder('location');
  668.         $locations $this->getChildren($location);
  669.         $locations[] = $location;
  670.         $locationsIds = [];
  671.         foreach ($locations as $childLocation) {
  672.             $locationsIds[] = $childLocation->getId();
  673.         }
  674.         $disableStatus $queryBuilder
  675.             ->set('location.disabled', (int) $status)
  676.             ->update()
  677.             ->where($queryBuilder->expr()->in('location.id'$locationsIds))
  678.             ->getQuery()
  679.             ->execute();
  680.         $em $this->getEntityManager();
  681.         foreach ($locations as $childLocation) {
  682.             $childLocation->setDisabled((bool) $status);
  683.             $em->getEventManager()->dispatchEvent(
  684.                 Events::postUpdate,
  685.                 new LifecycleEventArgs($childLocation$em)
  686.             );
  687.         }
  688.         $em->flush();
  689.         return $disableStatus;
  690.     }
  691.     /**
  692.      * Get Location full path.
  693.      *
  694.      * @param string $locale
  695.      * @param string $separator
  696.      *
  697.      * @return string
  698.      */
  699.     public function getLocationFullPath(Location $location$locale$separator ' / ')
  700.     {
  701.         $nodes $this->getPathQueryBuilder($location)
  702.             ->getQuery()
  703.             ->setHint(
  704.                 Query::HINT_CUSTOM_OUTPUT_WALKER,
  705.                 TranslationWalker::class
  706.             )->setHint(
  707.                 TranslatableListener::HINT_TRANSLATABLE_LOCALE,
  708.                 $locale
  709.             )
  710.             ->getArrayResult();
  711.         $locationFullPath $this->buildTree($nodes, [
  712.             'decorate' => true,
  713.             'rootOpen' => '',
  714.             'rootClose' => '',
  715.             'childOpen' => function ($node) use ($nodes$separator) {
  716.                 if ($node['id'] === $nodes[0]['id']) {
  717.                     return '';
  718.                 }
  719.                 return $separator;
  720.             },
  721.             'childClose' => '',
  722.         ]);
  723.         return implode($separatorarray_reverse(explode($separator$locationFullPath)));
  724.     }
  725.     /**
  726.      * Get Path of Location.
  727.      *
  728.      * @param string $locale
  729.      *
  730.      * @return array
  731.      */
  732.     public function getLocationPathNodes(Location $location$locale null)
  733.     {
  734.         return $this->getPathQueryBuilder($location)
  735.             ->getQuery()
  736.             ->setHint(Query::HINT_CUSTOM_OUTPUT_WALKERTranslationWalker::class)
  737.             ->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE$locale)
  738.             ->getArrayResult();
  739.     }
  740.     /**
  741.      * @param null $locale
  742.      */
  743.     public function getLocationPathNodesResult(Location $location$locale null)
  744.     {
  745.         return $this
  746.             ->getPathQueryBuilder($location)
  747.             ->getQuery()
  748.             ->setHint(Query::HINT_CUSTOM_OUTPUT_WALKERTranslationWalker::class)
  749.             ->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE$locale)
  750.             ->getResult();
  751.     }
  752.     public function getSameLevelLocations(Location $location, ?int $limit null, array $excluded = [])
  753.     {
  754.         $queryBuilder $this->createQueryBuilder('lo');
  755.         $queryBuilder
  756.             ->where($queryBuilder->expr()->eq('lo.level'':level'))
  757.             ->setParameter('level'$location->getLevel())
  758.             ->andWhere($queryBuilder->expr()->notIn('lo.id'':excluded'))
  759.             ->setParameter('excluded'array_merge($excluded, [$location]));
  760.         if ($limit) {
  761.             $queryBuilder->setMaxResults($limit);
  762.         }
  763.         return $queryBuilder->getQuery()->getResult();
  764.     }
  765.     /**
  766.      * Find locations by slug indexed by id.
  767.      *
  768.      * @return array
  769.      */
  770.     public function getBySlugs(array $slugs = [])
  771.     {
  772.         if (empty($slugs)) {
  773.             return [];
  774.         }
  775.         $queryBuilder $this->createQueryBuilder('location''location.id');
  776.         return $queryBuilder
  777.             ->andWhere($queryBuilder->expr()->in('location.slug'$slugs))
  778.             ->getQuery()
  779.             ->getResult();
  780.     }
  781.     /**
  782.      * @param string $locale
  783.      *
  784.      * @return string
  785.      */
  786.     public function getRootLocation(Location $location$locale 'en')
  787.     {
  788.         $queryBuilder $this->getPathQueryBuilder($location);
  789.         $queryBuilder $queryBuilder->setMaxResults(self::ONE_RESULT_NUMBER);
  790.         $rootLocationQuery $queryBuilder->getQuery()->setHint(
  791.             Query::HINT_CUSTOM_OUTPUT_WALKER,
  792.             TranslationWalker::class
  793.         )->setHint(
  794.             TranslatableListener::HINT_TRANSLATABLE_LOCALE,
  795.             $locale
  796.         );
  797.         return $rootLocationQuery->getOneOrNullResult();
  798.     }
  799.     /**
  800.      * @param int|string $idOrSlug
  801.      *
  802.      * @throws NonUniqueResultException
  803.      */
  804.     public function findOneByIdOrSlug($idOrSlug)
  805.     {
  806.         $queryBuilder $this->createQueryBuilder('l');
  807.         return $queryBuilder
  808.             ->andWhere($queryBuilder->expr()->eq('l.slug'':slug'))
  809.             ->setParameter('slug', (string) $idOrSlug)
  810.             ->orWhere($queryBuilder->expr()->eq('l.id'':id'))
  811.             ->setParameter('id'$idOrSlug)
  812.             ->getQuery()
  813.             ->getOneOrNullResult();
  814.     }
  815.     /**
  816.      * @param int $limit
  817.      *
  818.      * @return array
  819.      */
  820.     public function getMostSearched($limit self::RECENT_SEARCHED_LOCATIONS_COUNT)
  821.     {
  822.         $queryBuilder $this->createQueryBuilder('l');
  823.         return $queryBuilder
  824.             ->addSelect('l')
  825.             ->groupBy('l.id')
  826.             ->orderBy('l.listingsCounter''desc')
  827.             ->setMaxResults($limit)
  828.             ->getQuery()
  829.             ->getResult();
  830.     }
  831.     /**
  832.      * Get locations count by keyword.
  833.      *
  834.      * @return Query
  835.      */
  836.     public function getLocationCountByKeyword(?string $keyword null)
  837.     {
  838.         return $this->createQueryBuilder('l')
  839.             ->select('COUNT(l.id)')
  840.             ->where('FIND_IN_SET(:keyword, l.keyword) > 0')
  841.             ->setParameter('keyword'$keyword)
  842.             ->getQuery()
  843.             ->setMaxResults(1);
  844.     }
  845.     /**
  846.      * Get locations title by ids.
  847.      *
  848.      * @return Query
  849.      */
  850.     public function findTitleById(array $idsstring $locale 'en')
  851.     {
  852.         $queryBuilder $this->createQueryBuilder('l');
  853.         return $queryBuilder->select('l.id, l.title')
  854.             ->where($queryBuilder->expr()->in('l.id'':ids'))
  855.             ->setParameter('ids'$ids)
  856.             ->getQuery()
  857.             ->setHint(Query::HINT_CUSTOM_OUTPUT_WALKERTranslationWalker::class)
  858.             ->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE$locale);
  859.     }
  860.     public function getParentLocationByLevel(Location $locationint $level 1string $locale 'en')
  861.     {
  862.         return $this
  863.             ->getPathQueryBuilder($location)
  864.             ->setFirstResult($level)
  865.             ->setMaxResults(1)
  866.             ->getQuery()
  867.             ->setHint(
  868.                 Query::HINT_CUSTOM_OUTPUT_WALKER,
  869.                 TranslationWalker::class
  870.             )
  871.             ->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE$locale)
  872.             ->getArrayResult();
  873.     }
  874.     /**
  875.      * @return Query
  876.      */
  877.     public function getParentsIds(Location $location)
  878.     {
  879.         $queryBuilder $this->getParents($location);
  880.         $queryBuilder->select('location.id');
  881.         return $queryBuilder->getQuery();
  882.     }
  883.     /**
  884.      * @return Query
  885.      */
  886.     public function getParentsBreadCrumbData(Location $locationstring $locale Locales::AR)
  887.     {
  888.         $queryBuilder $this->getParents($location);
  889.         $queryBuilder->select('location.id, location.title, location.slug');
  890.         return $queryBuilder->getQuery()
  891.             ->setHint(Query::HINT_CUSTOM_OUTPUT_WALKERTranslationWalker::class)
  892.             ->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE$locale)
  893.         ;
  894.     }
  895.     /**
  896.      * @return Location|null
  897.      *
  898.      * @throws NonUniqueResultException
  899.      */
  900.     public function getFirstRoot()
  901.     {
  902.         $queryBuilder $this->createQueryBuilder('location');
  903.         return $queryBuilder
  904.             ->setMaxResults(1)
  905.             ->getQuery()
  906.             ->getOneOrNullResult();
  907.     }
  908.     /**
  909.      * @return int|mixed|string
  910.      */
  911.     public function getPathNodeByLevel(Location $locationint $level 1)
  912.     {
  913.         $queryBuilder $this->getPathQueryBuilder($location);
  914.         $queryBuilder->andWhere($queryBuilder->expr()->eq('node.level'':level'))
  915.             ->setParameter('level'$level);
  916.         return $queryBuilder->getQuery()->getResult();
  917.     }
  918.     /**
  919.      * @return array
  920.      */
  921.     public function getLevelOneLocations()
  922.     {
  923.         $queryBuilder $this->getEntityManager()->createQueryBuilder();
  924.         $queryBuilder->addSelect('l.id');
  925.         $queryBuilder->addSelect('l.title');
  926.         $queryBuilder->from('AqarmapListingBundle:Location''l');
  927.         $queryBuilder->andWhere($queryBuilder->expr()->eq('l.level'':level'))
  928.             ->setParameter('level'1);
  929.         $queryBuilder->andWhere($queryBuilder->expr()->eq('l.disabled'':disabled'))
  930.             ->setParameter('disabled'0);
  931.         $query $queryBuilder
  932.             ->getQuery()
  933.             ->setHint(Query::HINT_CUSTOM_OUTPUT_WALKERTranslationWalker::class)
  934.             ->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE'en');
  935.         return $query->getArrayResult();
  936.     }
  937.     /**
  938.      * @return QueryBuilder
  939.      */
  940.     public function getLevelOneLocationsQuery()
  941.     {
  942.         $locationQueryBuilder $this->getEntityManager()->createQueryBuilder();
  943.         $locationQueryBuilder
  944.             ->addSelect('locations.title AS locationTitle')
  945.             ->from('AqarmapListingBundle:Location''locations');
  946.         $locationQueryBuilder
  947.             ->andWhere($locationQueryBuilder->expr()->eq('locations.disabled'':disabled'))
  948.             ->setParameter('disabled'false);
  949.         $locationQueryBuilder
  950.             ->andWhere($locationQueryBuilder->expr()->eq('locations.level'':level'))
  951.             ->setParameter('level'1);
  952.         return $locationQueryBuilder;
  953.     }
  954.     /**
  955.      * @return array
  956.      */
  957.     public function getLocationChildrenDQL(array $aliases)
  958.     {
  959.         $leftAlias $aliases['leftAlias'];
  960.         $rightAlias $aliases['rightAlias'];
  961.         $rootAlias $aliases['rootAlias'];
  962.         $leftLocationDQL $this->getEntityManager()->createQueryBuilder()
  963.             ->select("$leftAlias.left")
  964.             ->from('AqarmapListingBundle:Location'"$leftAlias");
  965.         $leftLocationDQL
  966.             ->where($leftLocationDQL->expr()->eq("$leftAlias.id"'locations.id'))
  967.             ->getDQL();
  968.         $rightLocationDQL $this->getEntityManager()->createQueryBuilder()
  969.             ->select("$rightAlias.right")
  970.             ->from('AqarmapListingBundle:Location'"$rightAlias");
  971.         $rightLocationDQL
  972.             ->where($rightLocationDQL->expr()->eq("$rightAlias.id"'locations.id'))
  973.             ->getDQL();
  974.         $rootLocationDQL $this->getEntityManager()->createQueryBuilder()
  975.             ->select("$rootAlias.root")
  976.             ->from('AqarmapListingBundle:Location'"$rootAlias");
  977.         $rootLocationDQL
  978.             ->where($rootLocationDQL->expr()->eq("$rootAlias.id"'locations.id'))
  979.             ->getDQL();
  980.         return [
  981.             'leftLocationDQL' => $leftLocationDQL,
  982.             'rightLocationDQL' => $rightLocationDQL,
  983.             'rootLocationDQL' => $rootLocationDQL,
  984.         ];
  985.     }
  986.     public function getIterableLocations(): IterableResult
  987.     {
  988.         $qb $this->createQueryBuilder('location');
  989.         return $qb->select('location')
  990.             ->where($qb->expr()->isNotNull('location.parent'))
  991.             ->getQuery()->iterate();
  992.     }
  993.     /**
  994.      * @return mixed[]
  995.      *
  996.      * @throws \Doctrine\DBAL\DBALException
  997.      */
  998.     public function getLocationParentsAndChildrenIds(Location $location)
  999.     {
  1000.         $statement "
  1001.         SELECT
  1002.             CASE WHEN locations.root = {$location->getRoot()} AND
  1003.             locations._right > {$location->getRight()} AND
  1004.             locations._left < {$location->getLeft()}
  1005.             THEN locations.id
  1006.             ELSE NULL
  1007.             END AS parents,
  1008.             CASE WHEN locations.root = {$location->getRoot()} AND
  1009.             locations._right < {$location->getRight()} AND
  1010.             locations._left > {$location->getLeft()}
  1011.             THEN locations.id
  1012.             ELSE NULL
  1013.             END AS children
  1014.         FROM locations
  1015.             WHERE (locations.root = {$location->getRoot()} AND
  1016.             locations._right >= {$location->getRight()} AND
  1017.             locations._left <= {$location->getLeft()}) OR
  1018.             (locations.root = {$location->getRoot()} AND
  1019.             locations._right < {$location->getRight()} AND
  1020.             locations._left > {$location->getLeft()});";
  1021.         $statement $this->getEntityManager()->getConnection()->prepare($statement);
  1022.         $statement->execute();
  1023.         return $statement->fetchAll();
  1024.     }
  1025.     /**
  1026.      * @return Query
  1027.      */
  1028.     public function getLocationsData(array $locations = [], array $selections = [], bool $translations false)
  1029.     {
  1030.         $queryBuilder $this->createQueryBuilder('location');
  1031.         $selectStatement '';
  1032.         foreach ($selections as $index => $selection) {
  1033.             $selectStatement .= "location.{$selection}";
  1034.             if ($index !== \count($selections) - 1) {
  1035.                 $selectStatement .= ', ';
  1036.             }
  1037.         }
  1038.         if ($translations) {
  1039.             $queryBuilder
  1040.                 ->join('location.translations''translations');
  1041.             $queryBuilder
  1042.                 ->andWhere($queryBuilder->expr()->eq('translations.field'':field'))
  1043.                 ->setParameter(':field''title')
  1044.                 ->andWhere($queryBuilder->expr()->eq('translations.locale'':locale'))
  1045.                 ->setParameter(':locale'Locales::EN);
  1046.             $selectStatement .= ', translations.content, translations.locale';
  1047.         }
  1048.         $queryBuilder->select($selectStatement);
  1049.         if (!empty($locations)) {
  1050.             $queryBuilder->andWhere($queryBuilder->expr()->in('location.id'':id'))
  1051.                 ->setParameter('id'$locations);
  1052.         }
  1053.         return $queryBuilder->getQuery();
  1054.     }
  1055.     /**
  1056.      * @param array $selections = []
  1057.      *
  1058.      * @return Query
  1059.      */
  1060.     public function getParent(int $locationId, array $selections = [], ?string $locale null)
  1061.     {
  1062.         $queryBuilder $this->createQueryBuilder('location');
  1063.         $selectStatement '';
  1064.         foreach ($selections as $index => $selection) {
  1065.             $selectStatement .= "location.{$selection}";
  1066.             if ($index !== \count($selections) - 1) {
  1067.                 $selectStatement .= ', ';
  1068.             }
  1069.         }
  1070.         $queryBuilder->select($selectStatement)
  1071.             ->andWhere($queryBuilder->expr()->eq('location.parent'':parent'))
  1072.             ->setParameter('id'$locationId);
  1073.         $query $queryBuilder->getQuery();
  1074.         if ($locale) {
  1075.             $query->setHint(
  1076.                 Query::HINT_CUSTOM_OUTPUT_WALKER,
  1077.                 'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker'
  1078.             );
  1079.             $query->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE$locale);
  1080.         }
  1081.         return $queryBuilder->getQuery();
  1082.     }
  1083.     public function getUserLiveLocationsWithParents(int $user)
  1084.     {
  1085.         $queryBuilder $this->createQueryBuilder('location');
  1086.         $queryBuilder->select('location.id as id, IDENTITY(location.parent) as parent, location.level as level');
  1087.         $queryBuilder->join('location.listings''listings'Expr\Join::WITH'location.id=listings.location');
  1088.         $queryBuilder->andWhere($queryBuilder->expr()->eq('listings.user'':user'))
  1089.             ->setParameter(':user'$user)
  1090.             ->andWhere($queryBuilder->expr()->eq('listings.status'':status'))
  1091.             ->setParameter(':status'ListingStatus::LIVE);
  1092.         return $queryBuilder->getQuery()->getResult();
  1093.     }
  1094.     /**
  1095.      * @return array
  1096.      */
  1097.     public function getChildrenIds($right$left$root)
  1098.     {
  1099.         $queryBuilder $this->createQueryBuilder('location');
  1100.         $queryBuilder->select('location.id');
  1101.         $queryBuilder->where($queryBuilder->expr()->lt('location.right'$right));
  1102.         $queryBuilder->andWhere($queryBuilder->expr()->gt('location.left'$left));
  1103.         $queryBuilder->andWhere($queryBuilder->expr()->eq('location.root'':rid'));
  1104.         $queryBuilder->setParameter('rid'$root);
  1105.         return $queryBuilder->getQuery()->getResult();
  1106.     }
  1107.     /**
  1108.      * @return Query
  1109.      */
  1110.     public function getChildrenObjects(Location $location$excludedLocations null)
  1111.     {
  1112.         $queryBuilder $this->createQueryBuilder('location');
  1113.         $queryBuilder->where($queryBuilder->expr()->lt('location.right'$location->getRight()));
  1114.         $queryBuilder->andWhere($queryBuilder->expr()->gt('location.left'$location->getLeft()));
  1115.         $queryBuilder->andWhere($queryBuilder->expr()->eq('location.root'':rid'));
  1116.         $queryBuilder->setParameter('rid'$location->getRoot());
  1117.         $queryBuilder->andWhere($queryBuilder->expr()->neq('location'':location'));
  1118.         $queryBuilder->setParameter('location'$location);
  1119.         $queryBuilder->andWhere($queryBuilder->expr()->notIn('location'$excludedLocations));
  1120.         return $queryBuilder->getQuery();
  1121.     }
  1122.     /**
  1123.      * @return QueryBuilder
  1124.      */
  1125.     public function getLocationsByLevel($criteria)
  1126.     {
  1127.         [
  1128.             'selectType' => $selectType,
  1129.             'lessThanOrEqualLevel' => $lessThanOrEqualLevel,
  1130.             'moreThanLevel' => $moreThanLevel,
  1131.         ] = array_merge([
  1132.             'selectType' => null,
  1133.             'lessThanOrEqualLevel' => null,
  1134.             'moreThanLevel' => null,
  1135.         ], $criteria);
  1136.         $queryBuilder $this->createQueryBuilder('locations');
  1137.         if ('count' === $selectType) {
  1138.             $queryBuilder->select('COUNT(locations.id)');
  1139.         }
  1140.         if ($lessThanOrEqualLevel) {
  1141.             $queryBuilder
  1142.                 ->andWhere($queryBuilder->expr()->lte('locations.level'':level'))
  1143.                 ->setParameter('level'$lessThanOrEqualLevel);
  1144.         } elseif ($moreThanLevel) {
  1145.             $queryBuilder
  1146.                 ->andWhere($queryBuilder->expr()->gt('locations.level'':level'))
  1147.                 ->setParameter('level'$moreThanLevel);
  1148.         }
  1149.         return $queryBuilder;
  1150.     }
  1151.     /**
  1152.      * Get all parents ids for location.
  1153.      *
  1154.      * @param int|Location $location
  1155.      */
  1156.     public function getAllLocationParentsIds($locationbool $withRoot true): array
  1157.     {
  1158.         $location = \is_int($location) ? $this->find($location) : $location;
  1159.         $queryBuilder $this->getPathQueryBuilder($location);
  1160.         $queryBuilder->select('node.id');
  1161.         $queryBuilder->andWhere($queryBuilder->expr()->neq('node.id'':location'));
  1162.         $queryBuilder->setParameter('location'$location->getId());
  1163.         if (false == $withRoot) {
  1164.             $queryBuilder->andWhere($queryBuilder->expr()->isNotNull('node.parent'));
  1165.         }
  1166.         return $queryBuilder->getQuery()->getResult();
  1167.     }
  1168.     /**
  1169.      * @return array
  1170.      */
  1171.     public function getMostLocationHasListingsForUser(User $user)
  1172.     {
  1173.         $queryBuilder $this->createQueryBuilder('location');
  1174.         $queryBuilder->join('location.listings''listing')->addSelect('listing');
  1175.         $queryBuilder->andWhere($queryBuilder->expr()->eq('listing.status'':status'));
  1176.         $queryBuilder->andWhere($queryBuilder->expr()->eq('listing.user'':user'));
  1177.         $queryBuilder->setParameter('status'ListingStatus::LIVE);
  1178.         $queryBuilder->setParameter('user'$user);
  1179.         $queryBuilder->addSelect('COUNT(listing.id) AS listing_count');
  1180.         $queryBuilder->groupBy('location.id');
  1181.         $queryBuilder->orderBy('listing_count''DESC');
  1182.         return $queryBuilder->setMaxResults(self::ONE_RESULT_NUMBER)->getQuery()->getOneOrNullResult();
  1183.     }
  1184.     /**
  1185.      * @return array
  1186.      */
  1187.     public function getLocationTranslations($entity)
  1188.     {
  1189.         $queryBuilder $this->createQueryBuilder('location');
  1190.         $queryBuilder->select('location.alias as aliasAr''location.title as titleAr''location.description as descriptionAr''translation.field''translation.content');
  1191.         $queryBuilder->join('location.translations''translation'Expr\Join::WITH'translation.object = location.id');
  1192.         $queryBuilder->andWhere($queryBuilder->expr()->eq('translation.locale'':locale'))->setParameter('locale''en');
  1193.         $queryBuilder->andWhere($queryBuilder->expr()->eq('location.id'':id'))->setParameter('id'$entity->getId());
  1194.         $results $queryBuilder->getQuery()->getArrayResult();
  1195.         $data = [];
  1196.         foreach ($results as $result) {
  1197.             $data['titleAr'] = $result['titleAr'];
  1198.             $data['aliasAr'] = $result['aliasAr'];
  1199.             $data['descriptionAr'] = $result['descriptionAr'];
  1200.             if ('title' == $result['field']) {
  1201.                 $data['titleEn'] = $result['content'];
  1202.             }
  1203.             if ('alias' == $result['field']) {
  1204.                 $data['aliasEn'] = $result['content'];
  1205.             }
  1206.             if ('description' == $result['field']) {
  1207.                 $data['descriptionEn'] = $result['content'];
  1208.             }
  1209.         }
  1210.         $data['titleAr'] ??= '';
  1211.         $data['titleEn'] ??= '';
  1212.         $data['aliasAr'] ??= '';
  1213.         $data['aliasEn'] ??= '';
  1214.         $data['descriptionAr'] ??= '';
  1215.         $data['descriptionEn'] ??= '';
  1216.         return $data;
  1217.     }
  1218.     /**
  1219.      * @return array
  1220.      */
  1221.     public function getCompoundLocations(array $criteria)
  1222.     {
  1223.         $queryBuilder $this->createQueryBuilder('location');
  1224.         $queryBuilder->select('location.id');
  1225.         if (isset($criteria['title'])) {
  1226.             $queryBuilder->andWhere($queryBuilder->expr()->like('location.title'':title'))
  1227.                 ->setParameter('title'"%{$criteria['title']}%");
  1228.         }
  1229.         return $queryBuilder->getQuery()->getResult();
  1230.     }
  1231.     /**
  1232.      * @return void
  1233.      */
  1234.     public function updateIsCompoundLocation(array $locationIDs)
  1235.     {
  1236.         $queryBuilder $this->createQueryBuilder('location');
  1237.         return $queryBuilder->update()
  1238.             ->set('location.isCompoundLocation'':status')
  1239.             ->setParameter('status'1)
  1240.             ->where($queryBuilder->expr()->in('location'':locations'))
  1241.             ->setParameter('locations'$locationIDs)
  1242.             ->getQuery()
  1243.             ->execute();
  1244.     }
  1245.     public function getLocationsBySlugs(array $locationSlugs): array
  1246.     {
  1247.         $queryBuilder $this->createQueryBuilder('l');
  1248.         $query $queryBuilder->select('l')
  1249.             ->where($queryBuilder->expr()->in('l.slug'':locationSlugs'))
  1250.             ->setParameter('locationSlugs'$locationSlugs)
  1251.             ->getQuery();
  1252.         return $query->getResult();
  1253.     }
  1254.     public function getHomeCompoundLocations(int $limit): array
  1255.     {
  1256.         $queryBuilder $this->createQueryBuilder('location');
  1257.         $query $queryBuilder
  1258.             ->where($queryBuilder->expr()->in('location.homeFilter'':homeFilter'))
  1259.             ->setParameter('homeFilter'true, \PDO::PARAM_BOOL)
  1260.             ->andWhere($queryBuilder->expr()->in('location.isCompoundLocation'':isCompoundLocation'))
  1261.             ->setParameter('isCompoundLocation'true, \PDO::PARAM_BOOL)
  1262.             ->andWhere($queryBuilder->expr()->isNotNull('location.listing'))
  1263.         ;
  1264.         $queryBuilder->setMaxResults($limit);
  1265.         return $query->getQuery()->enableResultCache(3600)->getResult();
  1266.     }
  1267.     /**
  1268.      * @throws NonUniqueResultException
  1269.      * @throws NoResultException
  1270.      */
  1271.     public function getListingsCount(Location $location): int
  1272.     {
  1273.         $queryBuilder $this->createQueryBuilder('location');
  1274.         $children $this->getLocationChildrenIds($location);
  1275.         $queryBuilder->select('COUNT(listing.id) as listingsCount')
  1276.             ->join('location.listings''listing')
  1277.             ->andWhere($queryBuilder->expr()->in('location.id'':locationId'))
  1278.             ->andWhere($queryBuilder->expr()->eq('listing.status'':status'))
  1279.             ->setParameters([
  1280.                 'locationId' => $children,
  1281.                 'status' => ListingStatus::LIVE,
  1282.             ]);
  1283.         return $queryBuilder->getQuery()->getSingleScalarResult();
  1284.     }
  1285.     /**
  1286.      * @return QueryBuilder
  1287.      */
  1288.     private function getParents(Location $location)
  1289.     {
  1290.         $queryBuilder $this->createQueryBuilder('location');
  1291.         $queryBuilder->where($queryBuilder->expr()->lt('location.left'':left'))
  1292.             ->andWhere($queryBuilder->expr()->gt('location.right'':right'))
  1293.             ->andWhere($queryBuilder->expr()->eq('location.root'':root'))
  1294.             ->setParameter('left'$location->getLeft())
  1295.             ->setParameter('right'$location->getRight())
  1296.             ->setParameter('root'$location->getRoot());
  1297.         return $queryBuilder;
  1298.     }
  1299. }