repository = $entityManager->getRepository(AddressReference::class); $this->entityManager = $entityManager; } public function countAll(): int { $qb = $this->repository->createQueryBuilder('ar'); $qb->select('count(ar.id)'); return $qb->getQuery()->getSingleScalarResult(); } public function countByPostalCodePattern(PostalCode $postalCode, string $pattern): int { $query = $this->buildQueryByPostalCodePattern($postalCode, $pattern); $sql = $query->buildQuery(true); $rsm = new ResultSetMapping(); $rsm->addScalarResult('c', 'c'); $nq = $this->entityManager->createNativeQuery($sql, $rsm)->setParameters($query->buildParameters(true)); return (int) $nq->getSingleResult()['c']; } public function find($id, $lockMode = null, $lockVersion = null): ?AddressReference { return $this->repository->find($id, $lockMode, $lockVersion); } /** * @return AddressReference[] */ public function findAll(): array { return $this->repository->findAll(); } /** * @param mixed|null $limit * @param mixed|null $offset * * @return AddressReference[] */ public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array { return $this->repository->findBy($criteria, $orderBy, $limit, $offset); } /** * @return AddressReference[]|array */ public function findByPostalCodePattern(PostalCode $postalCode, string $pattern, bool $simplify = false, int $start = 0, int $limit = 50): array { $query = $this->buildQueryByPostalCodePattern($postalCode, $pattern); if (!$simplify) { $rsm = new ResultSetMappingBuilder($this->entityManager); $rsm->addRootEntityFromClassMetadata(AddressReference::class, 'cma'); $query->addSelectClause($rsm->generateSelectClause()); } else { throw new RuntimeException('not implemented'); } $sql = strtr( $query->buildQuery() . 'ORDER BY pertinence DESC, lpad(streetnumber, 10, \'0\') ASC OFFSET ? LIMIT ? ', // little hack for adding sql method to point ['cma.point AS point' => 'ST_AsGeojson(cma.point) AS point'] ); $parameters = [...$query->buildParameters(), $start, $limit]; return $this->entityManager->createNativeQuery($sql, $rsm) ->setParameters($parameters) ->getResult(); } public function findOneBy(array $criteria, ?array $orderBy = null): ?AddressReference { return $this->repository->findOneBy($criteria, $orderBy); } public function getClassName() { return AddressReference::class; } private function buildQueryByPostalCodePattern(PostalCode $postalCode, string $pattern): SearchApiQuery { $pattern = trim($pattern); if ('' === $pattern) { throw new RuntimeException('the search pattern must not be empty'); } $query = new SearchApiQuery(); $query ->setFromClause('chill_main_address_reference cma') ->andWhereClause('postcode_id = ?', [$postalCode->getId()]); $pertinenceClause = ['STRICT_WORD_SIMILARITY(addresscanonical, UNACCENT(?))']; $pertinenceArgs = [$pattern]; $orWhere = ['addresscanonical %>> UNACCENT(?)']; $orWhereArgs = [$pattern]; foreach (explode(' ', $pattern) as $part) { $part = trim($part); if ('' === $part) { continue; } $orWhere[] = "addresscanonical LIKE '%' || UNACCENT(LOWER(?)) || '%'"; $orWhereArgs[] = $part; $pertinenceClause[] = "(EXISTS (SELECT 1 FROM unnest(string_to_array(addresscanonical, ' ')) AS t WHERE starts_with(t, UNACCENT(LOWER(?)))))::int"; $pertinenceClause[] = '(addresscanonical LIKE UNACCENT(LOWER(?)))::int'; array_push($pertinenceArgs, $part, $part); } $query ->setSelectPertinence(implode(' + ', $pertinenceClause), $pertinenceArgs) ->andWhereClause(implode(' OR ', $orWhere), $orWhereArgs); return $query; } }