src/Aqarmap/Bundle/ListingBundle/Repository/LocationRepository.php line 30
<?phpnamespace Aqarmap\Bundle\ListingBundle\Repository;use Aqarmap\Bundle\ListingBundle\Constant\ListingCategories;use Aqarmap\Bundle\ListingBundle\Constant\ListingStatus;use Aqarmap\Bundle\ListingBundle\Entity\Location;use Aqarmap\Bundle\ListingBundle\Entity\PropertyType;use Aqarmap\Bundle\MainBundle\Constant\Locales;use Aqarmap\Bundle\SearchBundle\Entity\SearchResultCombinations;use Aqarmap\Bundle\UserBundle\Entity\User;use Doctrine\ORM\EntityManagerInterface;use Doctrine\ORM\Event\LifecycleEventArgs;use Doctrine\ORM\Events;use Doctrine\ORM\Internal\Hydration\IterableResult;use Doctrine\ORM\NonUniqueResultException;use Doctrine\ORM\NoResultException;use Doctrine\ORM\Query;use Doctrine\ORM\Query\Expr;use Doctrine\ORM\QueryBuilder;use Gedmo\Translatable\Query\TreeWalker\TranslationWalker;use Gedmo\Translatable\TranslatableListener;use Gedmo\Tree\Entity\Repository\NestedTreeRepository;class LocationRepository extends NestedTreeRepository{public const RECENT_SEARCHED_LOCATIONS_COUNT = 16;public const ONE_RESULT_NUMBER = 1;public function __construct(EntityManagerInterface $manager){parent::__construct($manager, $manager->getClassMetadata(Location::class));}public function search(array $criteria){$QueryBuilder = $this->createQueryBuilder('lo');if (isset($criteria['is_disabled'])) {$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lo.disabled', ':disabled'))->setParameter('disabled', $criteria['is_disabled']);}if (isset($criteria['level'])) {$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lo.level', ':level'))->setParameter('level', $criteria['level']);}// Searchif (!empty($criteria['search']) && !empty($criteria['q'])) {$criteria['q'] = trim((string) $criteria['q']);switch ($criteria['search']) {case 'location_id':$QueryBuilder->andWhere($QueryBuilder->expr()->in('lo.id', ':location_id'))->setParameter('location_id', $criteria['q']);break;case 'parent_id':$QueryBuilder->andWhere($QueryBuilder->expr()->in('lo.parent', ':parent_id'))->setParameter('parent_id', $criteria['q']);break;case 'title':$QueryBuilder->join('lo.translations', 'lot', Expr\Join::WITH, 'lot.field = :title_field')->andWhere($QueryBuilder->expr()->orX($QueryBuilder->expr()->like('lot.content', ':title'),$QueryBuilder->expr()->like('lo.title', ':title')))->setParameter('title_field', 'title')->setParameter('title', "{$criteria['q']}%");break;}}return $QueryBuilder;}/*** @param bool $searchableOnly** @internal param null $locale** @return array*/public function getLocationsList($searchableOnly = false, $estimatable = false){$QueryBuilder = $this->createQueryBuilder('lo');$QueryBuilder->andWhere($QueryBuilder->expr()->isNull('lo.parent'));$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lo.disabled', ':disabled'))->setParameter('disabled', false, \PDO::PARAM_BOOL);if ($searchableOnly) {$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lo.searchable', ':is_searchable'))->setParameter('is_searchable', true, \PDO::PARAM_BOOL);}if ($estimatable) {$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lo.estimate', ':is_estimatable'))->setParameter('is_estimatable', true, \PDO::PARAM_BOOL);}$query = $QueryBuilder->getQuery();$query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, TranslationWalker::class);return $query;}public function getLocationFlat($criteria){$criteria = array_merge(['searchable' => null,'estimatable' => null,'level' => null,], $criteria);$QueryBuilder = $this->createQueryBuilder('lo');$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lo.disabled', ':disabled'))->setParameter('disabled', false, \PDO::PARAM_BOOL);if ((int) $criteria['searchable']) {$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lo.searchable', ':is_searchable'))->setParameter('is_searchable', true, \PDO::PARAM_BOOL);}if ((int) $criteria['estimatable']) {$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lo.estimate', ':is_estimatable'))->setParameter('is_estimatable', true, \PDO::PARAM_BOOL);}if (null !== $criteria['level']) {$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lo.level', ':level'))->setParameter('level', $criteria['level']);}$query = $QueryBuilder->getQuery();$query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, TranslationWalker::class);return $query;}/*** Get location children flat.** @return Location|array*/public function getLocationChildrenFlat(Location $location){$QueryBuilder = $this->createQueryBuilder('lo');$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lo.parent', ':parent_id'))->setParameter('parent_id', $location);return $QueryBuilder->getQuery();}/*** Get location children flat Array of Results.** @param string $locale** @return Location|array*/public function getLocationChildrenFlatResults(Location $location, $locale = null){$QueryBuilder = $this->createQueryBuilder('lo');$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lo.parent', ':parent_id'))->setParameter('parent_id', $location);$query = $QueryBuilder->getQuery()->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, TranslationWalker::class);if ($locale) {$query->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE, $locale);}return $query->getArrayResult();}/*** @internal param null $locale** @return Query** @internal param User $user* @internal param bool $iteration*/public function getSectionLocationsWithLiveListings(Section $section){$QueryBuilder = $this->createQueryBuilder('lo');$QueryBuilder->leftJoin('lo.listings', 'lol');$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lo.disabled', ':disabled'))->setParameter('disabled', false, \PDO::PARAM_BOOL);if ($section) {$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lol.section', ':section'))->setParameter('section', $section);}$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lol.status', ':status'))->setParameter('status', ListingStatus::LIVE);$query = $QueryBuilder->getQuery();$query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, TranslationWalker::class);return $query->getResult();}/*** @return array** @internal param int $level* @internal param bool $searchableOnly* @internal param null $locale*/public function getLeveledLocations(array $criteria){$QueryBuilder = $this->createQueryBuilder('lo');$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lo.disabled', ':disabled'))->setParameter('disabled', false, \PDO::PARAM_BOOL);if (!empty($criteria['parent'])) {if ('no-parent' == $criteria['parent']) {$QueryBuilder->andWhere($QueryBuilder->expr()->isNull('lo.parent'));} else {$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lo.parent', ':parent'))->setParameter('parent', $criteria['parent']);}}if (isset($criteria['level'])) {$QueryBuilder->andWhere($QueryBuilder->expr()->lte('lo.level', ':level'))->setParameter('level', $criteria['level']);}$QueryBuilder->orderBy('lo.listingsCounter', 'desc');$query = $QueryBuilder->getQuery();$query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, TranslationWalker::class);return $query->getResult();}public function getLeveledLocationsArray(array $criteria){$queryBuilder = $this->createQueryBuilder('location');$queryBuilder->select('location.id as id, COALESCE(translation.content, location.title) as title, location.slug as slug')->leftJoin('location.translations','translation',Expr\Join::WITH,'translation.locale = :locale and translation.field = :title and translation.object = location.id')->andWhere($queryBuilder->expr()->eq('location.disabled', ':disabled'))->setParameter('locale', $criteria['locale'])->setParameter('title', 'title')->setParameter('disabled', false, \PDO::PARAM_BOOL);if (!empty($criteria['parent'])) {if ('no-parent' == $criteria['parent']) {$queryBuilder->andWhere($queryBuilder->expr()->isNull('location.parent'));} else {$queryBuilder->andWhere($queryBuilder->expr()->eq('location.parent', ':parent'))->setParameter('parent', $criteria['parent']);}}if (!empty($criteria['level'])) {$queryBuilder->andWhere($queryBuilder->expr()->lte('location.level', ':level'))->setParameter('level', $criteria['level']);}if (!empty($criteria['searchResultsCombinationMinimumCount'])) {$queryBuilder->join(SearchResultCombinations::class,'searchResultCombinations',Expr\Join::WITH,'searchResultCombinations.location = location.id')->andWhere($queryBuilder->expr()->gte('searchResultCombinations.searchResultCount', ':searchResultCount'))->setParameter('searchResultCount', $criteria['searchResultsCombinationMinimumCount']);if (isset($criteria['propertyType'])) {$queryBuilder->andWhere($queryBuilder->expr()->eq('searchResultCombinations.propertyType', ':propertyType'))->setParameter('propertyType', $criteria['propertyType']);}if (isset($criteria['section'])) {$queryBuilder->andWhere($queryBuilder->expr()->eq('searchResultCombinations.section', ':section'))->setParameter('section', $criteria['section']);}if (!empty($criteria['searchResultsCombinationMax'])) {$queryBuilder->addSelect('MAX(searchResultCombinations.searchResultCount) as searchResultCount');} else {$queryBuilder->addSelect('searchResultCombinations.searchResultCount as searchResultCount');}$queryBuilder->orderBy('searchResultCombinations.searchResultCount', 'desc');} else {$queryBuilder->orderBy('location.listingsCounter', 'desc');}return $queryBuilder;}/*** @return Location*/public function getSearchableOrNeighbourhoodNearestParent(Location $location){$QueryBuilder = $this->createQueryBuilder('lo');$QueryBuilder->andWhere('lo.root = :root')->andWhere('lo.left <= :left')->andWhere('lo.right >= :right')->setParameter('left', $location->getLeft())->setParameter('right', $location->getRight())->setParameter('root', $location->getRoot());$QueryBuilder->andWhere('lo.neighborhoodFilter = :is_neighbourhood OR lo.searchable = :is_searchable')->setParameter('is_neighbourhood', true, \PDO::PARAM_BOOL)->setParameter('is_searchable', true, \PDO::PARAM_BOOL);$QueryBuilder->orderBy('lo.level', 'DESC')->setMaxResults(1);$query = $QueryBuilder->getQuery();$query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, TranslationWalker::class);return $query->getOneOrNullResult();}// --------------------------------------------------------------------/*** Get location children.** @return Location|array*/public function getLocationChildren(Location $location){$locationChildren = $this->children($location);$location = array_merge([$location], $locationChildren);return $location;}/*** @return array*/public function getLocationChildrenIds(Location $location){$locationChildrenIds = $this->childrenIds($location);$location = array_merge([$location->getId()], array_column(array_values($locationChildrenIds), 'id'));return $location;}/*** @return array*/public function childrenIds(Location $location){$queryBuilder = $this->createQueryBuilder('location');$queryBuilder->select('location.id');$queryBuilder->where($queryBuilder->expr()->lt('location.right', $location->getRight()));$queryBuilder->andWhere($queryBuilder->expr()->gt('location.left', $location->getLeft()));$queryBuilder->andWhere($queryBuilder->expr()->eq('location.root', ':rid'));$queryBuilder->setParameter('rid', $location->getRoot());return $queryBuilder->getQuery()->enableResultCache(1800, sprintf('location_children_ids_%d_%d', $location->getRight(), $location->getLeft()))->getResult();}// --------------------------------------------------------------------/*** Get neighbourhood locations.** @return Location|array*/public function getNeighbourhoodLocations($criteria = []){$QueryBuilder = $this->createQueryBuilder('lo');$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lo.neighborhoodFilter', ':is_true'))->setParameter('is_true', true, \PDO::PARAM_BOOL);$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lo.disabled', ':disabled'))->setParameter('disabled', false, \PDO::PARAM_BOOL);if (isset($criteria['level'])) {$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lo.level', ':level'))->setParameter('level', $criteria['level']);}if (isset($criteria['maxLevel'])) {$QueryBuilder->andWhere($QueryBuilder->expr()->lte('lo.level', ':maxLevel'))->setParameter('maxLevel', $criteria['maxLevel']);}$query = $QueryBuilder->getQuery();return $query->getResult();}/*** Get neighbourhood sub-locations.** @return Location|array*/public function getNeighbourhoodSubLocations(Location $location, PropertyType $propertyType){$QueryBuilder = $this->createQueryBuilder('lo')->join('lo.locationStatistics', 'location_statistics', Expr\Join::LEFT_JOIN);$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lo.parent', ':location'))->setParameter('location', $location);$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lo.disabled', ':disabled'))->setParameter('disabled', false, \PDO::PARAM_BOOL);$QueryBuilder->andWhere($QueryBuilder->expr()->eq('location_statistics.propertyType', ':property_type'))->setParameter('property_type', $propertyType);$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lo.neighborhoodFilter', ':is_true'))->setParameter('is_true', true, \PDO::PARAM_BOOL);$QueryBuilder->andWhere($QueryBuilder->expr()->isNotNull('location_statistics.avgPrice'));$QueryBuilder->andWhere($QueryBuilder->expr()->neq('location_statistics.avgPrice', 0));$QueryBuilder->orderBy('location_statistics.avgPrice', 'DESC');$query = $QueryBuilder->getQuery();return $query->getResult();}/*** Get neighbourhood Compounds.** @return Location|array*/public function getNeighbourhoodCompounds($locations = null, $state = null){$QueryBuilder = $this->createQueryBuilder('lo')->join('lo.locationCompound', 'lc', Expr\Join::INNER_JOIN);$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lo.compoundFilter', ':is_true'))->setParameter('is_true', true, \PDO::PARAM_BOOL);if ($locations) {$QueryBuilder->andWhere($QueryBuilder->expr()->orX($QueryBuilder->expr()->in('lo.parent', ':locations')))->setParameter('locations', $locations);}if ($state) {$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lc.state', ':state'))->setParameter('state', $state);}$query = $QueryBuilder->getQuery();return $query->getResult();}/*** @return array*/public function generateNearestLocations(Location $location, $distance){$QueryBuilder = $this->createQueryBuilder('lo');$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lo.disabled', ':disabled'))->setParameter('disabled', false, \PDO::PARAM_BOOL);$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lo.level', ':level'))->setParameter('level', $location->getLevel());$QueryBuilder->andWhere($QueryBuilder->expr()->neq('lo', ':location'))->setParameter('location', $location);if ($location->getParent()) {$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lo.parent', ':parent'))->setParameter('parent', $location->getParent());}$QueryBuilder = $this->getNearestLocationsFormulaQuery($QueryBuilder, $location, $distance);$query = $QueryBuilder->getQuery();return $query->getResult();}/*** @return Query*/public function generateNearestLocationsQuery(array $criteria){/** @var Location $location */$location = $criteria['location'];$listingQueryBuilder = $this->_em->createQueryBuilder();$listingQueryBuilder = $listingQueryBuilder->select('MAX(li.id)')->from(Listing::class, 'li')->andWhere($listingQueryBuilder->expr()->eq('li.status', ListingStatus::LIVE))->andWhere($listingQueryBuilder->expr()->neq('li.category', ListingCategories::PROJECTS));if (isset($criteria['propertyType']) && $criteria['propertyType']) {$listingQueryBuilder->andWhere($listingQueryBuilder->expr()->in('li.propertyType', $criteria['propertyType']));}if (isset($criteria['section']) && $criteria['section']) {$listingQueryBuilder->andWhere($listingQueryBuilder->expr()->eq('li.section', $criteria['section']));}$queryBuilder = $this->createQueryBuilder('lo');$queryBuilder->addSelect('ST_Distance_Sphere( Point(:longitude, :latitude), Point(lo.lon, lo.lat)) AS distance');$queryBuilder->andWhere($queryBuilder->expr()->eq('lo.disabled', ':disabled'))->setParameter('disabled', false, \PDO::PARAM_BOOL);$queryBuilder->innerJoin('lo.listings','listings',Expr\Join::WITH,$queryBuilder->expr()->eq('listings.id',sprintf('(%s)', $listingQueryBuilder->andWhere($listingQueryBuilder->expr()->eq('li.location', 'lo.id'))->setMaxResults(1)->getQuery()->getDQL())));$queryBuilder->andWhere($queryBuilder->expr()->neq('lo', ':location'))->setParameter('location', $location);if (isset($criteria['excludedSubLocations']) && $criteria['excludedSubLocations']) {$queryBuilder->andWhere($queryBuilder->expr()->notIn('lo', ':subLocations'))->setParameter('subLocations', $this->getLocationChildrenIds($location));}$queryBuilder->andWhere($queryBuilder->expr()->neq('lo.listingsCounter', 0));$queryBuilder->andWhere($queryBuilder->expr()->lt('ABS(lo.lat)', 90));$queryBuilder->andWhere($queryBuilder->expr()->lt('ABS(lo.lon)', 180));$queryBuilder->andWhere($queryBuilder->expr()->isNotNull('lo.lat'));$queryBuilder->andWhere($queryBuilder->expr()->isNotNull('lo.lon'));$queryBuilder->having('distance <= :maxDistance')->setParameter('maxDistance', $criteria['maxDistance'] * 1000)->setParameter('latitude', $location->getCenterLat())->setParameter('longitude', $location->getCenterLng());$queryBuilder->orderBy('distance');return $queryBuilder->getQuery();}public function getNearestLocationsFormulaQuery(QueryBuilder $queryBuilder, Location $location, $distance): QueryBuilder{return $queryBuilder->having('( 3959 * acos(cos(radians(:latitude))'.'* cos( radians( lo.lat ) )'.'* cos( radians( lo.lon )'.'- radians(:longitude) )'.'+ sin( radians(:latitude) )'.'* sin( radians( lo.lat ) ) ) ) < :distance')->setParameter('distance', $distance)->setParameter('latitude', $location->getCenterLat())->setParameter('longitude', $location->getCenterLng());}/*** Get Nearest Compounds.** @return Location|array*/public function getNearestLocations(array $locations = [], bool $limit = true, int $max = 3){$QueryBuilder = $this->createQueryBuilder('lo')->join('lo.nearestLocations', 'nearest_locations', Expr\Join::INNER_JOIN);$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lo.searchable', ':is_searchable'))->setParameter('is_searchable', true, \PDO::PARAM_BOOL);$QueryBuilder->andWhere($QueryBuilder->expr()->in('nearest_locations.id', ':locations'))->setParameter('locations', $locations);if ($limit) {$QueryBuilder->setMaxResults($max);}return $QueryBuilder->getQuery()->enableResultCache()->getResult();}/*** @internal param null $locale** @param string $locale** @return array*/public function getAllSearchableLocationsList($levelLimit = null, $locale = null){$QueryBuilder = $this->createQueryBuilder('lo');$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lo.disabled', ':disabled'))->setParameter('disabled', false, \PDO::PARAM_BOOL);if ($levelLimit) {$QueryBuilder->andWhere($QueryBuilder->expr()->lt('lo.level', ':level'))->setParameter('level', $levelLimit);}$query = $QueryBuilder->getQuery()->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, TranslationWalker::class);if ($locale) {$query->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE, $locale);}return $query->getResult();}/*** @return array*/public function getAllLocationsCount(){$QueryBuilder = $this->createQueryBuilder('lo')->select('count(lo.id)');$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lo.disabled', ':disabled'))->setParameter('disabled', false, \PDO::PARAM_BOOL);return $QueryBuilder->getQuery()->getSingleScalarResult();}/*** Get Nearest Neighbourhoods or Compounds.** @return Location|array*/public function getNearestNeighbourhoods(Location $location){$QueryBuilder = $this->createQueryBuilder('lo')->join('lo.nearestLocations', 'nearest_locations', Expr\Join::INNER_JOIN);if ($location->getCompoundFilter()) {$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lo.compoundFilter', ':is_true'))->setParameter('is_true', true, \PDO::PARAM_BOOL);}if ($location->getNeighborhoodFilter()) {$QueryBuilder->andWhere($QueryBuilder->expr()->eq('lo.neighborhoodFilter', ':is_true'))->setParameter('is_true', true, \PDO::PARAM_BOOL);}$QueryBuilder->andWhere($QueryBuilder->expr()->eq('nearest_locations.id', ':location'))->setParameter('location', $location);$QueryBuilder->setMaxResults(3);$query = $QueryBuilder->getQuery();return $query->getResult();}/*** @param bool $forceLocale** @return Location*/public function getLocationLike($location, $forceLocale = true){$queryBuilder = $this->createQueryBuilder('p')->where('p.title LIKE :location')->setParameter('location', '%'.$location.'%')->getQuery()->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, TranslationWalker::class);if ($forceLocale) {$queryBuilder->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE, 'en');}return $queryBuilder->setMaxResults(1)->getOneOrNullResult();}/*** Get locations by synonym.** @return Query*/public function getLocationBySynonym(?string $synonym = null){return $this->createQueryBuilder('l')->select('l')->where('FIND_IN_SET(:synonym, l.synonyms) > 0')->setParameter('synonym', $synonym)->getQuery();}public function getWhereHasBumpableListings(){$queryBuilder = $this->createQueryBuilder('l');return $queryBuilder->select('l, li, lf')->join('l.listings', 'li', Expr\Join::WITH, 'l.id=li.location')->join('li.listingFeatures', 'lf', Expr\Join::WITH, 'li.id=lf.listing')->where($queryBuilder->expr()->eq('li.isBumped', ':isBumped'))->setParameter(':isBumped', true, \PDO::PARAM_BOOL)->andWhere($queryBuilder->expr()->isNull('lf.expiresAt'))->andWhere('lf.bumpsCount < lf.bumpUpOccurrences')->orWhere($queryBuilder->expr()->isNull('lf.bumpsCount'))->andWhere($queryBuilder->expr()->lte('lf.nextBumpDate', ':nextBumpDate'))->setParameter(':nextBumpDate', (new \DateTime())->setTime(0, 0, 0))->orderBy('lf.nextBumpDate', 'DESC')->addOrderBy('lf.id', 'DESC')->addOrderBy('lf.listing', 'DESC')->setMaxResults(100)->getQuery()->getResult();}/*** @param bool $status** @throws \Doctrine\ORM\OptimisticLockException*/public function changeStatus(Location $location, $status = true){$queryBuilder = $this->createQueryBuilder('location');$locations = $this->getChildren($location);$locations[] = $location;$locationsIds = [];foreach ($locations as $childLocation) {$locationsIds[] = $childLocation->getId();}$disableStatus = $queryBuilder->set('location.disabled', (int) $status)->update()->where($queryBuilder->expr()->in('location.id', $locationsIds))->getQuery()->execute();$em = $this->getEntityManager();foreach ($locations as $childLocation) {$childLocation->setDisabled((bool) $status);$em->getEventManager()->dispatchEvent(Events::postUpdate,new LifecycleEventArgs($childLocation, $em));}$em->flush();return $disableStatus;}/*** Get Location full path.** @param string $locale* @param string $separator** @return string*/public function getLocationFullPath(Location $location, $locale, $separator = ' / '){$nodes = $this->getPathQueryBuilder($location)->getQuery()->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER,TranslationWalker::class)->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE,$locale)->getArrayResult();$locationFullPath = $this->buildTree($nodes, ['decorate' => true,'rootOpen' => '','rootClose' => '','childOpen' => function($node) use ($nodes, $separator) {if ($node['id'] === $nodes[0]['id']) {return '';}return $separator;},'childClose' => '',]);return implode($separator, array_reverse(explode($separator, $locationFullPath)));}/*** Get Path of Location.** @param string $locale** @return array*/public function getLocationPathNodes(Location $location, $locale = null){return $this->getPathQueryBuilder($location)->getQuery()->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, TranslationWalker::class)->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE, $locale)->getArrayResult();}public function getLocationPathNodesResult(Location $location, $locale = null){return $this->getPathQueryBuilder($location)->getQuery()->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, TranslationWalker::class)->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE, $locale)->getResult();}public function getSameLevelLocations(Location $location, ?int $limit = null, array $excluded = []){$queryBuilder = $this->createQueryBuilder('lo');$queryBuilder->where($queryBuilder->expr()->eq('lo.level', ':level'))->setParameter('level', $location->getLevel())->andWhere($queryBuilder->expr()->notIn('lo.id', ':excluded'))->setParameter('excluded', array_merge($excluded, [$location]));if ($limit) {$queryBuilder->setMaxResults($limit);}return $queryBuilder->getQuery()->getResult();}/*** Find locations by slug indexed by id.** @return array*/public function getBySlugs(array $slugs = []){if (empty($slugs)) {return [];}$queryBuilder = $this->createQueryBuilder('location', 'location.id');return $queryBuilder->andWhere($queryBuilder->expr()->in('location.slug', $slugs))->getQuery()->getResult();}/*** @param string $locale** @return string*/public function getRootLocation(Location $location, $locale = 'en'){$queryBuilder = $this->getPathQueryBuilder($location);$queryBuilder = $queryBuilder->setMaxResults(self::ONE_RESULT_NUMBER);$rootLocationQuery = $queryBuilder->getQuery()->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER,TranslationWalker::class)->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE,$locale);return $rootLocationQuery->getOneOrNullResult();}/*** @param int|string $idOrSlug** @throws NonUniqueResultException*/public function findOneByIdOrSlug($idOrSlug){$queryBuilder = $this->createQueryBuilder('l');return $queryBuilder->andWhere($queryBuilder->expr()->eq('l.slug', ':slug'))->setParameter('slug', (string) $idOrSlug)->orWhere($queryBuilder->expr()->eq('l.id', ':id'))->setParameter('id', $idOrSlug)->getQuery()->getOneOrNullResult();}/*** @param int $limit** @return array*/public function getMostSearched($limit = self::RECENT_SEARCHED_LOCATIONS_COUNT){$queryBuilder = $this->createQueryBuilder('l');return $queryBuilder->addSelect('l')->groupBy('l.id')->orderBy('l.listingsCounter', 'desc')->setMaxResults($limit)->getQuery()->getResult();}/*** Get locations count by synonym.** @return Query*/public function getLocationCountBySynonym(?string $synonym = null){return $this->createQueryBuilder('l')->select('COUNT(l.id)')->where('FIND_IN_SET(:synonym, l.synonyms) > 0')->setParameter('synonym', $synonym)->getQuery()->setMaxResults(1);}/*** Get locations title by ids.** @return Query*/public function findTitleById(array $ids, string $locale = 'en'){$queryBuilder = $this->createQueryBuilder('l');return $queryBuilder->select('l.id, l.title')->where($queryBuilder->expr()->in('l.id', ':ids'))->setParameter('ids', $ids)->getQuery()->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, TranslationWalker::class)->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE, $locale);}public function getParentLocationByLevel(Location $location, int $level = 1, string $locale = 'en'){return $this->getPathQueryBuilder($location)->setFirstResult($level)->setMaxResults(1)->getQuery()->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER,TranslationWalker::class)->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE, $locale)->getArrayResult();}/*** @return Query*/public function getParentsIds(Location $location){$queryBuilder = $this->getParents($location);$queryBuilder->select('location.id');return $queryBuilder->getQuery();}/*** @return Query*/public function getParentsBreadCrumbData(Location $location, string $locale = Locales::AR){$queryBuilder = $this->getParents($location);$queryBuilder->select('location.id, location.title, location.slug');return $queryBuilder->getQuery()->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, TranslationWalker::class)->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE, $locale);}/*** @return Location|null** @throws NonUniqueResultException*/public function getFirstRoot(){$queryBuilder = $this->createQueryBuilder('location');return $queryBuilder->setMaxResults(1)->getQuery()->getOneOrNullResult();}/*** @return int|mixed|string*/public function getPathNodeByLevel(Location $location, int $level = 1){$queryBuilder = $this->getPathQueryBuilder($location);$queryBuilder->andWhere($queryBuilder->expr()->eq('node.level', ':level'))->setParameter('level', $level);return $queryBuilder->getQuery()->getResult();}/*** @return array*/public function getLevelOneLocations(){$queryBuilder = $this->getEntityManager()->createQueryBuilder();$queryBuilder->addSelect('l.id');$queryBuilder->addSelect('l.title');$queryBuilder->from(Location::class, 'l');$queryBuilder->andWhere($queryBuilder->expr()->eq('l.level', ':level'))->setParameter('level', 1);$queryBuilder->andWhere($queryBuilder->expr()->eq('l.disabled', ':disabled'))->setParameter('disabled', 0);$query = $queryBuilder->getQuery()->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, TranslationWalker::class)->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE, 'en');return $query->getArrayResult();}/*** @return QueryBuilder*/public function getLevelOneLocationsQuery(){$locationQueryBuilder = $this->getEntityManager()->createQueryBuilder();$locationQueryBuilder->addSelect('locations.title AS locationTitle')->from(Location::class, 'locations');$locationQueryBuilder->andWhere($locationQueryBuilder->expr()->eq('locations.disabled', ':disabled'))->setParameter('disabled', false);$locationQueryBuilder->andWhere($locationQueryBuilder->expr()->eq('locations.level', ':level'))->setParameter('level', 1);return $locationQueryBuilder;}/*** @return array*/public function getLocationChildrenDQL(array $aliases){$leftAlias = $aliases['leftAlias'];$rightAlias = $aliases['rightAlias'];$rootAlias = $aliases['rootAlias'];$leftLocationDQL = $this->getEntityManager()->createQueryBuilder()->select("$leftAlias.left")->from(Location::class, "$leftAlias");$leftLocationDQL->where($leftLocationDQL->expr()->eq("$leftAlias.id", 'locations.id'))->getDQL();$rightLocationDQL = $this->getEntityManager()->createQueryBuilder()->select("$rightAlias.right")->from(Location::class, "$rightAlias");$rightLocationDQL->where($rightLocationDQL->expr()->eq("$rightAlias.id", 'locations.id'))->getDQL();$rootLocationDQL = $this->getEntityManager()->createQueryBuilder()->select("$rootAlias.root")->from(Location::class, "$rootAlias");$rootLocationDQL->where($rootLocationDQL->expr()->eq("$rootAlias.id", 'locations.id'))->getDQL();return ['leftLocationDQL' => $leftLocationDQL,'rightLocationDQL' => $rightLocationDQL,'rootLocationDQL' => $rootLocationDQL,];}public function getIterableLocations(): IterableResult{$qb = $this->createQueryBuilder('location');return $qb->select('location')->where($qb->expr()->isNotNull('location.parent'))->getQuery()->iterate();}/*** @return mixed[]** @throws \Doctrine\DBAL\DBALException*/public function getLocationParentsAndChildrenIds(Location $location){$statement = "SELECTCASE WHEN locations.root = {$location->getRoot()} ANDlocations._right > {$location->getRight()} ANDlocations._left < {$location->getLeft()}THEN locations.idELSE NULLEND AS parents,CASE WHEN locations.root = {$location->getRoot()} ANDlocations._right < {$location->getRight()} ANDlocations._left > {$location->getLeft()}THEN locations.idELSE NULLEND AS childrenFROM locationsWHERE (locations.root = {$location->getRoot()} ANDlocations._right >= {$location->getRight()} ANDlocations._left <= {$location->getLeft()}) OR(locations.root = {$location->getRoot()} ANDlocations._right < {$location->getRight()} ANDlocations._left > {$location->getLeft()});";$statement = $this->getEntityManager()->getConnection()->prepare($statement);$statement->executeStatement();return $statement->fetchAllAssociative();}/*** @return Query*/public function getLocationsData(array $locations = [], array $selections = [], bool $translations = false){$queryBuilder = $this->createQueryBuilder('location');$selectStatement = '';foreach ($selections as $index => $selection) {$selectStatement .= "location.{$selection}";if ($index !== \count($selections) - 1) {$selectStatement .= ', ';}}if ($translations) {$queryBuilder->join('location.translations', 'translations');$queryBuilder->andWhere($queryBuilder->expr()->eq('translations.field', ':field'))->setParameter(':field', 'title')->andWhere($queryBuilder->expr()->eq('translations.locale', ':locale'))->setParameter(':locale', Locales::EN);$selectStatement .= ', translations.content, translations.locale';}$queryBuilder->select($selectStatement);if (!empty($locations)) {$queryBuilder->andWhere($queryBuilder->expr()->in('location.id', ':id'))->setParameter('id', $locations);}return $queryBuilder->getQuery();}/*** @param array $selections = []** @return Query*/public function getParent(int $locationId, array $selections = [], ?string $locale = null){$queryBuilder = $this->createQueryBuilder('location');$selectStatement = '';foreach ($selections as $index => $selection) {$selectStatement .= "location.{$selection}";if ($index !== \count($selections) - 1) {$selectStatement .= ', ';}}$queryBuilder->select($selectStatement)->andWhere($queryBuilder->expr()->eq('location.parent', ':parent'))->setParameter('id', $locationId);$query = $queryBuilder->getQuery();if ($locale) {$query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER,TranslationWalker::class);$query->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE, $locale);}return $queryBuilder->getQuery();}public function getUserLiveLocationsWithParents(int $user){$queryBuilder = $this->createQueryBuilder('location');$queryBuilder->select('location.id as id, IDENTITY(location.parent) as parent, location.level as level');$queryBuilder->join('location.listings', 'listings', Expr\Join::WITH, 'location.id=listings.location');$queryBuilder->andWhere($queryBuilder->expr()->eq('listings.user', ':user'))->setParameter(':user', $user)->andWhere($queryBuilder->expr()->eq('listings.status', ':status'))->setParameter(':status', ListingStatus::LIVE);return $queryBuilder->getQuery()->getResult();}/*** @return array*/public function getChildrenIds($right, $left, $root){$queryBuilder = $this->createQueryBuilder('location');$queryBuilder->select('location.id');$queryBuilder->where($queryBuilder->expr()->lt('location.right', $right));$queryBuilder->andWhere($queryBuilder->expr()->gt('location.left', $left));$queryBuilder->andWhere($queryBuilder->expr()->eq('location.root', ':rid'));$queryBuilder->setParameter('rid', $root);return $queryBuilder->getQuery()->getResult();}/*** @return Query*/public function getChildrenObjects(Location $location, $excludedLocations = null){$queryBuilder = $this->createQueryBuilder('location');$queryBuilder->where($queryBuilder->expr()->lt('location.right', $location->getRight()));$queryBuilder->andWhere($queryBuilder->expr()->gt('location.left', $location->getLeft()));$queryBuilder->andWhere($queryBuilder->expr()->eq('location.root', ':rid'));$queryBuilder->setParameter('rid', $location->getRoot());$queryBuilder->andWhere($queryBuilder->expr()->neq('location', ':location'));$queryBuilder->setParameter('location', $location);$queryBuilder->andWhere($queryBuilder->expr()->notIn('location', $excludedLocations));return $queryBuilder->getQuery();}/*** @return QueryBuilder*/public function getLocationsByLevel($criteria){['selectType' => $selectType,'lessThanOrEqualLevel' => $lessThanOrEqualLevel,'moreThanLevel' => $moreThanLevel,] = array_merge(['selectType' => null,'lessThanOrEqualLevel' => null,'moreThanLevel' => null,], $criteria);$queryBuilder = $this->createQueryBuilder('locations');if ('count' === $selectType) {$queryBuilder->select('COUNT(locations.id)');}if ($lessThanOrEqualLevel) {$queryBuilder->andWhere($queryBuilder->expr()->lte('locations.level', ':level'))->setParameter('level', $lessThanOrEqualLevel);} elseif ($moreThanLevel) {$queryBuilder->andWhere($queryBuilder->expr()->gt('locations.level', ':level'))->setParameter('level', $moreThanLevel);}return $queryBuilder;}/*** Get all parents ids for location.** @param int|Location $location*/public function getAllLocationParentsIds($location, bool $withRoot = true): array{$location = \is_int($location) ? $this->find($location) : $location;$queryBuilder = $this->getPathQueryBuilder($location);$queryBuilder->select('node.id');$queryBuilder->andWhere($queryBuilder->expr()->neq('node.id', ':location'));$queryBuilder->setParameter('location', $location->getId());if (false == $withRoot) {$queryBuilder->andWhere($queryBuilder->expr()->isNotNull('node.parent'));}return $queryBuilder->getQuery()->getResult();}/*** @return array*/public function getMostLocationHasListingsForUser(User $user){$queryBuilder = $this->createQueryBuilder('location');$queryBuilder->join('location.listings', 'listing')->addSelect('listing');$queryBuilder->andWhere($queryBuilder->expr()->eq('listing.status', ':status'));$queryBuilder->andWhere($queryBuilder->expr()->eq('listing.user', ':user'));$queryBuilder->setParameter('status', ListingStatus::LIVE);$queryBuilder->setParameter('user', $user);$queryBuilder->addSelect('COUNT(listing.id) AS listing_count');$queryBuilder->groupBy('location.id');$queryBuilder->orderBy('listing_count', 'DESC');return $queryBuilder->setMaxResults(self::ONE_RESULT_NUMBER)->getQuery()->getOneOrNullResult();}/*** @return array*/public function getLocationTranslations($entity){$queryBuilder = $this->createQueryBuilder('location');$queryBuilder->select('location.alias as aliasAr', 'location.title as titleAr', 'location.description as descriptionAr', 'translation.field', 'translation.content');$queryBuilder->join('location.translations', 'translation', Expr\Join::WITH, 'translation.object = location.id');$queryBuilder->andWhere($queryBuilder->expr()->eq('translation.locale', ':locale'))->setParameter('locale', 'en');$queryBuilder->andWhere($queryBuilder->expr()->eq('location.id', ':id'))->setParameter('id', $entity->getId());$results = $queryBuilder->getQuery()->getArrayResult();$data = [];foreach ($results as $result) {$data['titleAr'] = $result['titleAr'];$data['aliasAr'] = $result['aliasAr'];$data['descriptionAr'] = $result['descriptionAr'];if ('title' == $result['field']) {$data['titleEn'] = $result['content'];}if ('alias' == $result['field']) {$data['aliasEn'] = $result['content'];}if ('description' == $result['field']) {$data['descriptionEn'] = $result['content'];}}$data['titleAr'] ??= '';$data['titleEn'] ??= '';$data['aliasAr'] ??= '';$data['aliasEn'] ??= '';$data['descriptionAr'] ??= '';$data['descriptionEn'] ??= '';return $data;}/*** @return array*/public function getCompoundLocations(array $criteria){$queryBuilder = $this->createQueryBuilder('location');$queryBuilder->select('location.id');if (isset($criteria['title'])) {$queryBuilder->andWhere($queryBuilder->expr()->like('location.title', ':title'))->setParameter('title', "%{$criteria['title']}%");}return $queryBuilder->getQuery()->getResult();}/*** @return void*/public function updateIsCompoundLocation(array $locationIDs){$queryBuilder = $this->createQueryBuilder('location');return $queryBuilder->update()->set('location.isCompoundLocation', ':status')->setParameter('status', 1)->where($queryBuilder->expr()->in('location', ':locations'))->setParameter('locations', $locationIDs)->getQuery()->execute();}public function getLocationsBySlugs(array $locationSlugs): array{$queryBuilder = $this->createQueryBuilder('l');$query = $queryBuilder->select('l')->where($queryBuilder->expr()->in('l.slug', ':locationSlugs'))->setParameter('locationSlugs', $locationSlugs)->getQuery();return $query->getResult();}public function getHomeCompoundLocations(int $limit): array{$queryBuilder = $this->createQueryBuilder('location');$query = $queryBuilder->where($queryBuilder->expr()->in('location.homeFilter', ':homeFilter'))->setParameter('homeFilter', true, \PDO::PARAM_BOOL)->andWhere($queryBuilder->expr()->in('location.isCompoundLocation', ':isCompoundLocation'))->setParameter('isCompoundLocation', true, \PDO::PARAM_BOOL)->andWhere($queryBuilder->expr()->isNotNull('location.listing'));$queryBuilder->setMaxResults($limit);return $query->getQuery()->enableResultCache(3600)->getResult();}/*** @throws NonUniqueResultException* @throws NoResultException*/public function getListingsCount(Location $location): int{$queryBuilder = $this->createQueryBuilder('location');$children = $this->getLocationChildrenIds($location);$queryBuilder->select('COUNT(listing.id) as listingsCount')->join('location.listings', 'listing')->andWhere($queryBuilder->expr()->in('location.id', ':locationId'))->andWhere($queryBuilder->expr()->eq('listing.status', ':status'))->setParameters(['locationId' => $children,'status' => ListingStatus::LIVE,]);return $queryBuilder->getQuery()->getSingleScalarResult();}/*** @return QueryBuilder*/private function getParents(Location $location){$queryBuilder = $this->createQueryBuilder('location');$queryBuilder->where($queryBuilder->expr()->lt('location.left', ':left'))->andWhere($queryBuilder->expr()->gt('location.right', ':right'))->andWhere($queryBuilder->expr()->eq('location.root', ':root'))->setParameter('left', $location->getLeft())->setParameter('right', $location->getRight())->setParameter('root', $location->getRoot());return $queryBuilder;}/*** Get seller listing locations filtered by nearest parent type.*/public function getSellerLocationsIDsByType(User $user, string $locationType): array{$queryBuilder = $this->createQueryBuilder('location');$queryBuilder->distinct()->join('location.listings', 'l')->where('l.user = :user')->setParameter('user', $user);$locations = $queryBuilder->getQuery()->getResult();$results = [];foreach ($locations as $location) {if (!$location instanceof Location) {continue;}$parent = $location->getParentByType($locationType);if ($parent) {$results[$parent->getId()] = $parent;}}return array_values($results);}public function getIdToNameMap(): array{$locations = $this->createQueryBuilder('l')->select('l.id, l.title')->orderBy('l.title', 'ASC')->getQuery()->getArrayResult();return array_column($locations, 'title', 'id');}public function findNamesByIds(array $ids): array{if (empty($ids)) {return [];}$rows = $this->createQueryBuilder('l')->select('l.id, l.title')->where('l.id IN (:ids)')->setParameter('ids', $ids)->getQuery()->getArrayResult();return array_column($rows, 'title', 'id');}public function getLocationIdsAsArray(array $criteria): array{$qb = $this->search($criteria);return $qb->select('DISTINCT lo.id')->getQuery()->getSingleColumnResult();}}