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(
  724.             array_reverse(
  725.                 explode($separator$locationFullPath)
  726.             ),
  727.             $separator
  728.         );
  729.     }
  730.     /**
  731.      * Get Path of Location.
  732.      *
  733.      * @param string $locale
  734.      *
  735.      * @return array
  736.      */
  737.     public function getLocationPathNodes(Location $location$locale null)
  738.     {
  739.         return $this->getPathQueryBuilder($location)
  740.             ->getQuery()
  741.             ->setHint(Query::HINT_CUSTOM_OUTPUT_WALKERTranslationWalker::class)
  742.             ->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE$locale)
  743.             ->getArrayResult();
  744.     }
  745.     /**
  746.      * @param null $locale
  747.      */
  748.     public function getLocationPathNodesResult(Location $location$locale null)
  749.     {
  750.         return $this
  751.             ->getPathQueryBuilder($location)
  752.             ->getQuery()
  753.             ->setHint(Query::HINT_CUSTOM_OUTPUT_WALKERTranslationWalker::class)
  754.             ->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE$locale)
  755.             ->getResult();
  756.     }
  757.     public function getSameLevelLocations(Location $location, ?int $limit null, array $excluded = [])
  758.     {
  759.         $queryBuilder $this->createQueryBuilder('lo');
  760.         $queryBuilder
  761.             ->where($queryBuilder->expr()->eq('lo.level'':level'))
  762.             ->setParameter('level'$location->getLevel())
  763.             ->andWhere($queryBuilder->expr()->notIn('lo.id'':excluded'))
  764.             ->setParameter('excluded'array_merge($excluded, [$location]));
  765.         if ($limit) {
  766.             $queryBuilder->setMaxResults($limit);
  767.         }
  768.         return $queryBuilder->getQuery()->getResult();
  769.     }
  770.     /**
  771.      * Find locations by slug indexed by id.
  772.      *
  773.      * @return array
  774.      */
  775.     public function getBySlugs(array $slugs = [])
  776.     {
  777.         if (empty($slugs)) {
  778.             return [];
  779.         }
  780.         $queryBuilder $this->createQueryBuilder('location''location.id');
  781.         return $queryBuilder
  782.             ->andWhere($queryBuilder->expr()->in('location.slug'$slugs))
  783.             ->getQuery()
  784.             ->getResult();
  785.     }
  786.     /**
  787.      * @param string $locale
  788.      *
  789.      * @return string
  790.      */
  791.     public function getRootLocation(Location $location$locale 'en')
  792.     {
  793.         $queryBuilder $this->getPathQueryBuilder($location);
  794.         $queryBuilder $queryBuilder->setMaxResults(self::ONE_RESULT_NUMBER);
  795.         $rootLocationQuery $queryBuilder->getQuery()->setHint(
  796.             Query::HINT_CUSTOM_OUTPUT_WALKER,
  797.             TranslationWalker::class
  798.         )->setHint(
  799.             TranslatableListener::HINT_TRANSLATABLE_LOCALE,
  800.             $locale
  801.         );
  802.         return $rootLocationQuery->getOneOrNullResult();
  803.     }
  804.     /**
  805.      * @param int|string $idOrSlug
  806.      *
  807.      * @throws NonUniqueResultException
  808.      */
  809.     public function findOneByIdOrSlug($idOrSlug)
  810.     {
  811.         $queryBuilder $this->createQueryBuilder('l');
  812.         return $queryBuilder
  813.             ->andWhere($queryBuilder->expr()->eq('l.slug'':slug'))
  814.             ->setParameter('slug', (string) $idOrSlug)
  815.             ->orWhere($queryBuilder->expr()->eq('l.id'':id'))
  816.             ->setParameter('id'$idOrSlug)
  817.             ->getQuery()
  818.             ->getOneOrNullResult();
  819.     }
  820.     /**
  821.      * @param int $limit
  822.      *
  823.      * @return array
  824.      */
  825.     public function getMostSearched($limit self::RECENT_SEARCHED_LOCATIONS_COUNT)
  826.     {
  827.         $queryBuilder $this->createQueryBuilder('l');
  828.         return $queryBuilder
  829.             ->addSelect('l')
  830.             ->groupBy('l.id')
  831.             ->orderBy('l.listingsCounter''desc')
  832.             ->setMaxResults($limit)
  833.             ->getQuery()
  834.             ->getResult();
  835.     }
  836.     /**
  837.      * Get locations count by keyword.
  838.      *
  839.      * @return Query
  840.      */
  841.     public function getLocationCountByKeyword(?string $keyword null)
  842.     {
  843.         return $this->createQueryBuilder('l')
  844.             ->select('COUNT(l.id)')
  845.             ->where('FIND_IN_SET(:keyword, l.keyword) > 0')
  846.             ->setParameter('keyword'$keyword)
  847.             ->getQuery()
  848.             ->setMaxResults(1);
  849.     }
  850.     /**
  851.      * Get locations title by ids.
  852.      *
  853.      * @return Query
  854.      */
  855.     public function findTitleById(array $idsstring $locale 'en')
  856.     {
  857.         $queryBuilder $this->createQueryBuilder('l');
  858.         return $queryBuilder->select('l.id, l.title')
  859.             ->where($queryBuilder->expr()->in('l.id'':ids'))
  860.             ->setParameter('ids'$ids)
  861.             ->getQuery()
  862.             ->setHint(Query::HINT_CUSTOM_OUTPUT_WALKERTranslationWalker::class)
  863.             ->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE$locale);
  864.     }
  865.     public function getParentLocationByLevel(Location $locationint $level 1string $locale 'en')
  866.     {
  867.         return $this
  868.             ->getPathQueryBuilder($location)
  869.             ->setFirstResult($level)
  870.             ->setMaxResults(1)
  871.             ->getQuery()
  872.             ->setHint(
  873.                 Query::HINT_CUSTOM_OUTPUT_WALKER,
  874.                 TranslationWalker::class
  875.             )
  876.             ->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE$locale)
  877.             ->getArrayResult();
  878.     }
  879.     /**
  880.      * @return Query
  881.      */
  882.     public function getParentsIds(Location $location)
  883.     {
  884.         $queryBuilder $this->createQueryBuilder('location');
  885.         $queryBuilder->select('location.id');
  886.         $queryBuilder->where($queryBuilder->expr()->lt('location.left'$location->getLeft()));
  887.         $queryBuilder->andWhere($queryBuilder->expr()->gt('location.right'$location->getRight()));
  888.         $queryBuilder->andWhere($queryBuilder->expr()->eq('location.root'':rid'));
  889.         $queryBuilder->setParameter('rid'$location->getRoot());
  890.         return $queryBuilder->getQuery();
  891.     }
  892.     /**
  893.      * @return Location|null
  894.      *
  895.      * @throws NonUniqueResultException
  896.      */
  897.     public function getFirstRoot()
  898.     {
  899.         $queryBuilder $this->createQueryBuilder('location');
  900.         return $queryBuilder
  901.             ->setMaxResults(1)
  902.             ->getQuery()
  903.             ->getOneOrNullResult();
  904.     }
  905.     /**
  906.      * @return int|mixed|string
  907.      */
  908.     public function getPathNodeByLevel(Location $locationint $level 1)
  909.     {
  910.         $queryBuilder $this->getPathQueryBuilder($location);
  911.         $queryBuilder->andWhere($queryBuilder->expr()->eq('node.level'':level'))
  912.             ->setParameter('level'$level);
  913.         return $queryBuilder->getQuery()->getResult();
  914.     }
  915.     /**
  916.      * @return array
  917.      */
  918.     public function getLevelOneLocations()
  919.     {
  920.         $queryBuilder $this->getEntityManager()->createQueryBuilder();
  921.         $queryBuilder->addSelect('l.id');
  922.         $queryBuilder->addSelect('l.title');
  923.         $queryBuilder->from('AqarmapListingBundle:Location''l');
  924.         $queryBuilder->andWhere($queryBuilder->expr()->eq('l.level'':level'))
  925.             ->setParameter('level'1);
  926.         $queryBuilder->andWhere($queryBuilder->expr()->eq('l.disabled'':disabled'))
  927.             ->setParameter('disabled'0);
  928.         $query $queryBuilder
  929.             ->getQuery()
  930.             ->setHint(Query::HINT_CUSTOM_OUTPUT_WALKERTranslationWalker::class)
  931.             ->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE'en');
  932.         return $query->getArrayResult();
  933.     }
  934.     /**
  935.      * @return QueryBuilder
  936.      */
  937.     public function getLevelOneLocationsQuery()
  938.     {
  939.         $locationQueryBuilder $this->getEntityManager()->createQueryBuilder();
  940.         $locationQueryBuilder
  941.             ->addSelect('locations.title AS locationTitle')
  942.             ->from('AqarmapListingBundle:Location''locations');
  943.         $locationQueryBuilder
  944.             ->andWhere($locationQueryBuilder->expr()->eq('locations.disabled'':disabled'))
  945.             ->setParameter('disabled'false);
  946.         $locationQueryBuilder
  947.             ->andWhere($locationQueryBuilder->expr()->eq('locations.level'':level'))
  948.             ->setParameter('level'1);
  949.         return $locationQueryBuilder;
  950.     }
  951.     /**
  952.      * @return array
  953.      */
  954.     public function getLocationChildrenDQL(array $aliases)
  955.     {
  956.         $leftAlias $aliases['leftAlias'];
  957.         $rightAlias $aliases['rightAlias'];
  958.         $rootAlias $aliases['rootAlias'];
  959.         $leftLocationDQL $this->getEntityManager()->createQueryBuilder()
  960.             ->select("$leftAlias.left")
  961.             ->from('AqarmapListingBundle:Location'"$leftAlias");
  962.         $leftLocationDQL
  963.             ->where($leftLocationDQL->expr()->eq("$leftAlias.id"'locations.id'))
  964.             ->getDQL();
  965.         $rightLocationDQL $this->getEntityManager()->createQueryBuilder()
  966.             ->select("$rightAlias.right")
  967.             ->from('AqarmapListingBundle:Location'"$rightAlias");
  968.         $rightLocationDQL
  969.             ->where($rightLocationDQL->expr()->eq("$rightAlias.id"'locations.id'))
  970.             ->getDQL();
  971.         $rootLocationDQL $this->getEntityManager()->createQueryBuilder()
  972.             ->select("$rootAlias.root")
  973.             ->from('AqarmapListingBundle:Location'"$rootAlias");
  974.         $rootLocationDQL
  975.             ->where($rootLocationDQL->expr()->eq("$rootAlias.id"'locations.id'))
  976.             ->getDQL();
  977.         return [
  978.             'leftLocationDQL' => $leftLocationDQL,
  979.             'rightLocationDQL' => $rightLocationDQL,
  980.             'rootLocationDQL' => $rootLocationDQL,
  981.         ];
  982.     }
  983.     public function getIterableLocations(): IterableResult
  984.     {
  985.         $qb $this->createQueryBuilder('location');
  986.         return $qb->select('location')
  987.             ->where($qb->expr()->isNotNull('location.parent'))
  988.             ->getQuery()->iterate();
  989.     }
  990.     /**
  991.      * @return mixed[]
  992.      *
  993.      * @throws \Doctrine\DBAL\DBALException
  994.      */
  995.     public function getLocationParentsAndChildrenIds(Location $location)
  996.     {
  997.         $statement "
  998.         SELECT
  999.             CASE WHEN locations.root = {$location->getRoot()} AND
  1000.             locations._right > {$location->getRight()} AND
  1001.             locations._left < {$location->getLeft()}
  1002.             THEN locations.id
  1003.             ELSE NULL
  1004.             END AS parents,
  1005.             CASE WHEN locations.root = {$location->getRoot()} AND
  1006.             locations._right < {$location->getRight()} AND
  1007.             locations._left > {$location->getLeft()}
  1008.             THEN locations.id
  1009.             ELSE NULL
  1010.             END AS children
  1011.         FROM locations
  1012.             WHERE (locations.root = {$location->getRoot()} AND
  1013.             locations._right >= {$location->getRight()} AND
  1014.             locations._left <= {$location->getLeft()}) OR
  1015.             (locations.root = {$location->getRoot()} AND
  1016.             locations._right < {$location->getRight()} AND
  1017.             locations._left > {$location->getLeft()});";
  1018.         $statement $this->getEntityManager()->getConnection()->prepare($statement);
  1019.         $statement->execute();
  1020.         return $statement->fetchAll();
  1021.     }
  1022.     /**
  1023.      * @return Query
  1024.      */
  1025.     public function getLocationsData(array $locations = [], array $selections = [], bool $translations false)
  1026.     {
  1027.         $queryBuilder $this->createQueryBuilder('location');
  1028.         $selectStatement '';
  1029.         foreach ($selections as $index => $selection) {
  1030.             $selectStatement .= "location.{$selection}";
  1031.             if ($index !== \count($selections) - 1) {
  1032.                 $selectStatement .= ', ';
  1033.             }
  1034.         }
  1035.         if ($translations) {
  1036.             $queryBuilder
  1037.                 ->join('location.translations''translations');
  1038.             $queryBuilder
  1039.                 ->andWhere($queryBuilder->expr()->eq('translations.field'':field'))
  1040.                 ->setParameter(':field''title')
  1041.                 ->andWhere($queryBuilder->expr()->eq('translations.locale'':locale'))
  1042.                 ->setParameter(':locale'Locales::EN);
  1043.             $selectStatement .= ', translations.content, translations.locale';
  1044.         }
  1045.         $queryBuilder->select($selectStatement);
  1046.         if (!empty($locations)) {
  1047.             $queryBuilder->andWhere($queryBuilder->expr()->in('location.id'':id'))
  1048.                 ->setParameter('id'$locations);
  1049.         }
  1050.         return $queryBuilder->getQuery();
  1051.     }
  1052.     /**
  1053.      * @param array $selections = []
  1054.      *
  1055.      * @return Query
  1056.      */
  1057.     public function getParent(int $locationId, array $selections = [], ?string $locale null)
  1058.     {
  1059.         $queryBuilder $this->createQueryBuilder('location');
  1060.         $selectStatement '';
  1061.         foreach ($selections as $index => $selection) {
  1062.             $selectStatement .= "location.{$selection}";
  1063.             if ($index !== \count($selections) - 1) {
  1064.                 $selectStatement .= ', ';
  1065.             }
  1066.         }
  1067.         $queryBuilder->select($selectStatement)
  1068.             ->andWhere($queryBuilder->expr()->eq('location.parent'':parent'))
  1069.             ->setParameter('id'$locationId);
  1070.         $query $queryBuilder->getQuery();
  1071.         if ($locale) {
  1072.             $query->setHint(
  1073.                 Query::HINT_CUSTOM_OUTPUT_WALKER,
  1074.                 'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker'
  1075.             );
  1076.             $query->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE$locale);
  1077.         }
  1078.         return $queryBuilder->getQuery();
  1079.     }
  1080.     public function getUserLiveLocationsWithParents(int $user)
  1081.     {
  1082.         $queryBuilder $this->createQueryBuilder('location');
  1083.         $queryBuilder->select('location.id as id, IDENTITY(location.parent) as parent, location.level as level');
  1084.         $queryBuilder->join('location.listings''listings'Expr\Join::WITH'location.id=listings.location');
  1085.         $queryBuilder->andWhere($queryBuilder->expr()->eq('listings.user'':user'))
  1086.             ->setParameter(':user'$user)
  1087.             ->andWhere($queryBuilder->expr()->eq('listings.status'':status'))
  1088.             ->setParameter(':status'ListingStatus::LIVE);
  1089.         return $queryBuilder->getQuery()->getResult();
  1090.     }
  1091.     /**
  1092.      * @return array
  1093.      */
  1094.     public function getChildrenIds($right$left$root)
  1095.     {
  1096.         $queryBuilder $this->createQueryBuilder('location');
  1097.         $queryBuilder->select('location.id');
  1098.         $queryBuilder->where($queryBuilder->expr()->lt('location.right'$right));
  1099.         $queryBuilder->andWhere($queryBuilder->expr()->gt('location.left'$left));
  1100.         $queryBuilder->andWhere($queryBuilder->expr()->eq('location.root'':rid'));
  1101.         $queryBuilder->setParameter('rid'$root);
  1102.         return $queryBuilder->getQuery()->getResult();
  1103.     }
  1104.     /**
  1105.      * @return Query
  1106.      */
  1107.     public function getChildrenObjects(Location $location$excludedLocations null)
  1108.     {
  1109.         $queryBuilder $this->createQueryBuilder('location');
  1110.         $queryBuilder->where($queryBuilder->expr()->lt('location.right'$location->getRight()));
  1111.         $queryBuilder->andWhere($queryBuilder->expr()->gt('location.left'$location->getLeft()));
  1112.         $queryBuilder->andWhere($queryBuilder->expr()->eq('location.root'':rid'));
  1113.         $queryBuilder->setParameter('rid'$location->getRoot());
  1114.         $queryBuilder->andWhere($queryBuilder->expr()->neq('location'':location'));
  1115.         $queryBuilder->setParameter('location'$location);
  1116.         $queryBuilder->andWhere($queryBuilder->expr()->notIn('location'$excludedLocations));
  1117.         return $queryBuilder->getQuery();
  1118.     }
  1119.     /**
  1120.      * @return QueryBuilder
  1121.      */
  1122.     public function getLocationsByLevel($criteria)
  1123.     {
  1124.         [
  1125.             'selectType' => $selectType,
  1126.             'lessThanOrEqualLevel' => $lessThanOrEqualLevel,
  1127.             'moreThanLevel' => $moreThanLevel,
  1128.         ] = array_merge([
  1129.             'selectType' => null,
  1130.             'lessThanOrEqualLevel' => null,
  1131.             'moreThanLevel' => null,
  1132.         ], $criteria);
  1133.         $queryBuilder $this->createQueryBuilder('locations');
  1134.         if ('count' === $selectType) {
  1135.             $queryBuilder->select('COUNT(locations.id)');
  1136.         }
  1137.         if ($lessThanOrEqualLevel) {
  1138.             $queryBuilder
  1139.                 ->andWhere($queryBuilder->expr()->lte('locations.level'':level'))
  1140.                 ->setParameter('level'$lessThanOrEqualLevel);
  1141.         } elseif ($moreThanLevel) {
  1142.             $queryBuilder
  1143.                 ->andWhere($queryBuilder->expr()->gt('locations.level'':level'))
  1144.                 ->setParameter('level'$moreThanLevel);
  1145.         }
  1146.         return $queryBuilder;
  1147.     }
  1148.     /**
  1149.      * Get all parents ids for location.
  1150.      *
  1151.      * @param int|Location $location
  1152.      */
  1153.     public function getAllLocationParentsIds($locationbool $withRoot true): array
  1154.     {
  1155.         $location = \is_int($location) ? $this->find($location) : $location;
  1156.         $queryBuilder $this->getPathQueryBuilder($location);
  1157.         $queryBuilder->select('node.id');
  1158.         $queryBuilder->andWhere($queryBuilder->expr()->neq('node.id'':location'));
  1159.         $queryBuilder->setParameter('location'$location->getId());
  1160.         if (false == $withRoot) {
  1161.             $queryBuilder->andWhere($queryBuilder->expr()->isNotNull('node.parent'));
  1162.         }
  1163.         return $queryBuilder->getQuery()->getResult();
  1164.     }
  1165.     /**
  1166.      * @return array
  1167.      */
  1168.     public function getMostLocationHasListingsForUser(User $user)
  1169.     {
  1170.         $queryBuilder $this->createQueryBuilder('location');
  1171.         $queryBuilder->join('location.listings''listing')->addSelect('listing');
  1172.         $queryBuilder->andWhere($queryBuilder->expr()->eq('listing.status'':status'));
  1173.         $queryBuilder->andWhere($queryBuilder->expr()->eq('listing.user'':user'));
  1174.         $queryBuilder->setParameter('status'ListingStatus::LIVE);
  1175.         $queryBuilder->setParameter('user'$user);
  1176.         $queryBuilder->addSelect('COUNT(listing.id) AS listing_count');
  1177.         $queryBuilder->groupBy('location.id');
  1178.         $queryBuilder->orderBy('listing_count''DESC');
  1179.         return $queryBuilder->setMaxResults(self::ONE_RESULT_NUMBER)->getQuery()->getOneOrNullResult();
  1180.     }
  1181.     /**
  1182.      * @return array
  1183.      */
  1184.     public function getLocationTranslations($entity)
  1185.     {
  1186.         $queryBuilder $this->createQueryBuilder('location');
  1187.         $queryBuilder->select('location.alias as aliasAr''location.title as titleAr''location.description as descriptionAr''translation.field''translation.content');
  1188.         $queryBuilder->join('location.translations''translation'Expr\Join::WITH'translation.object = location.id');
  1189.         $queryBuilder->andWhere($queryBuilder->expr()->eq('translation.locale'':locale'))->setParameter('locale''en');
  1190.         $queryBuilder->andWhere($queryBuilder->expr()->eq('location.id'':id'))->setParameter('id'$entity->getId());
  1191.         $results $queryBuilder->getQuery()->getArrayResult();
  1192.         $data = [];
  1193.         foreach ($results as $result) {
  1194.             $data['titleAr'] = $result['titleAr'];
  1195.             $data['aliasAr'] = $result['aliasAr'];
  1196.             $data['descriptionAr'] = $result['descriptionAr'];
  1197.             if ('title' == $result['field']) {
  1198.                 $data['titleEn'] = $result['content'];
  1199.             }
  1200.             if ('alias' == $result['field']) {
  1201.                 $data['aliasEn'] = $result['content'];
  1202.             }
  1203.             if ('description' == $result['field']) {
  1204.                 $data['descriptionEn'] = $result['content'];
  1205.             }
  1206.         }
  1207.         $data['titleAr'] ??= '';
  1208.         $data['titleEn'] ??= '';
  1209.         $data['aliasAr'] ??= '';
  1210.         $data['aliasEn'] ??= '';
  1211.         $data['descriptionAr'] ??= '';
  1212.         $data['descriptionEn'] ??= '';
  1213.         return $data;
  1214.     }
  1215.     /**
  1216.      * @return array
  1217.      */
  1218.     public function getCompoundLocations(array $criteria)
  1219.     {
  1220.         $queryBuilder $this->createQueryBuilder('location');
  1221.         $queryBuilder->select('location.id');
  1222.         if (isset($criteria['title'])) {
  1223.             $queryBuilder->andWhere($queryBuilder->expr()->like('location.title'':title'))
  1224.                 ->setParameter('title'"%{$criteria['title']}%");
  1225.         }
  1226.         return $queryBuilder->getQuery()->getResult();
  1227.     }
  1228.     /**
  1229.      * @return void
  1230.      */
  1231.     public function updateIsCompoundLocation(array $locationIDs)
  1232.     {
  1233.         $queryBuilder $this->createQueryBuilder('location');
  1234.         return $queryBuilder->update()
  1235.             ->set('location.isCompoundLocation'':status')
  1236.             ->setParameter('status'1)
  1237.             ->where($queryBuilder->expr()->in('location'':locations'))
  1238.             ->setParameter('locations'$locationIDs)
  1239.             ->getQuery()
  1240.             ->execute();
  1241.     }
  1242.     public function getLocationsBySlugs(array $locationSlugs): array
  1243.     {
  1244.         $queryBuilder $this->createQueryBuilder('l');
  1245.         $query $queryBuilder->select('l')
  1246.             ->where($queryBuilder->expr()->in('l.slug'':locationSlugs'))
  1247.             ->setParameter('locationSlugs'$locationSlugs)
  1248.             ->getQuery();
  1249.         return $query->getResult();
  1250.     }
  1251.     public function getHomeCompoundLocations($limit): array
  1252.     {
  1253.         $queryBuilder $this->createQueryBuilder('location');
  1254.         $query $queryBuilder
  1255.             ->where($queryBuilder->expr()->in('location.homeFilter'':homeFilter'))
  1256.             ->setParameter('homeFilter'true, \PDO::PARAM_BOOL)
  1257.             ->andWhere($queryBuilder->expr()->in('location.isCompoundLocation'':isCompoundLocation'))
  1258.             ->setParameter('isCompoundLocation'true, \PDO::PARAM_BOOL)
  1259.             ->andWhere($queryBuilder->expr()->isNotNull('location.listing'))
  1260.         ;
  1261.         if ($limit) {
  1262.             $queryBuilder->setMaxResults($limit);
  1263.         }
  1264.         return $query->getQuery()->getResult();
  1265.     }
  1266.     /**
  1267.      * @throws NonUniqueResultException
  1268.      * @throws NoResultException
  1269.      */
  1270.     public function getListingsCount(Location $location): int
  1271.     {
  1272.         $queryBuilder $this->createQueryBuilder('location');
  1273.         $children $this->getLocationChildrenIds($location);
  1274.         $queryBuilder->select('COUNT(listing.id) as listingsCount')
  1275.             ->join('location.listings''listing')
  1276.             ->andWhere($queryBuilder->expr()->in('location.id'':locationId'))
  1277.             ->andWhere($queryBuilder->expr()->eq('listing.status'':status'))
  1278.             ->setParameters([
  1279.                 'locationId' => $children,
  1280.                 'status' => ListingStatus::LIVE,
  1281.             ]);
  1282.         return $queryBuilder->getQuery()->getSingleScalarResult();
  1283.     }
  1284. }