createSearchQuery( $default, $firstname, $lastname, $birthdate, $birthdateBefore, $birthdateAfter, $gender, $countryCode, $phonenumber, $city ); return $this->addAuthorizations($query); } public function countBySearchCriteria( ?string $default = null, ?string $firstname = null, ?string $lastname = null, ?\DateTimeInterface $birthdate = null, ?\DateTimeInterface $birthdateBefore = null, ?\DateTimeInterface $birthdateAfter = null, ?string $gender = null, ?string $countryCode = null, ?string $phonenumber = null, ?string $city = null ): int { $query = $this->buildAuthorizedQuery( $default, $firstname, $lastname, $birthdate, $birthdateBefore, $birthdateAfter, $gender, $countryCode, $phonenumber, $city ); return $this->fetchQueryCount($query); } /** * Create a search query without ACL. * * @throws NonUniqueResultException * @throws ParsingException */ public function createSearchQuery( ?string $default = null, ?string $firstname = null, ?string $lastname = null, ?\DateTimeInterface $birthdate = null, ?\DateTimeInterface $birthdateBefore = null, ?\DateTimeInterface $birthdateAfter = null, ?string $gender = null, ?string $countryCode = null, ?string $phonenumber = null, ?string $city = null ): SearchApiQuery { $query = new SearchApiQuery(); $query ->setFromClause('chill_person_person AS person'); $pertinence = []; $pertinenceArgs = []; $andWhereSearchClause = []; $andWhereSearchClauseArgs = []; if ('' !== trim((string) $default)) { foreach (\explode(' ', (string) $default) as $str) { if ('' === trim($str)) { continue; } $pertinence[] = 'STRICT_WORD_SIMILARITY(LOWER(UNACCENT(?)), person.fullnamecanonical) + '. "(person.fullnamecanonical LIKE '%' || LOWER(UNACCENT(?)) || '%')::int + ". "(EXISTS (SELECT 1 FROM unnest(string_to_array(fullnamecanonical, ' ')) AS t WHERE starts_with(t, UNACCENT(LOWER(?)))))::int + ". '(starts_with(LOWER(UNACCENT(lastname)), UNACCENT(LOWER(?))))::int'; \array_push($pertinenceArgs, $str, $str, $str, $str); $andWhereSearchClause[] = '(LOWER(UNACCENT(?)) <<% person.fullnamecanonical OR '. "person.fullnamecanonical LIKE '%' || LOWER(UNACCENT(?)) || '%' )"; \array_push($andWhereSearchClauseArgs, $str, $str); } $query->andWhereClause( \implode(' AND ', $andWhereSearchClause), $andWhereSearchClauseArgs ); } else { $pertinence = ['1']; $pertinenceArgs = []; } $query ->setSelectPertinence(\implode(' + ', $pertinence), $pertinenceArgs); if (null !== $birthdate) { $query->andWhereClause( 'person.birthdate = ?::date', [$birthdate->format('Y-m-d')] ); } if (null !== $firstname) { $query->andWhereClause( "UNACCENT(LOWER(person.firstname)) LIKE '%' || UNACCENT(LOWER(?)) || '%'", [$firstname] ); } if (null !== $lastname) { $query->andWhereClause( "UNACCENT(LOWER(person.lastname)) LIKE '%' || UNACCENT(LOWER(?)) || '%'", [$lastname] ); } if (null !== $birthdateBefore) { $query->andWhereClause( 'person.birthdate <= ?::date', [$birthdateBefore->format('Y-m-d')] ); } if (null !== $birthdateAfter) { $query->andWhereClause( 'person.birthdate >= ?::date', [$birthdateAfter->format('Y-m-d')] ); } if (null !== $phonenumber) { $query->andWhereClause( "person.phonenumber LIKE '%' || ? || '%' OR person.mobilenumber LIKE '%' || ? || '%' OR pp.phonenumber LIKE '%' || ? || '%'", [$phonenumber, $phonenumber, $phonenumber] ); $query->setFromClause($query->getFromClause().' LEFT JOIN chill_person_phone pp ON pp.person_id = person.id'); } if (null !== $city) { $query->setFromClause($query->getFromClause().' '. 'JOIN view_chill_person_current_address vcpca ON vcpca.person_id = person.id '. 'JOIN chill_main_address cma ON vcpca.address_id = cma.id '. 'JOIN chill_main_postal_code cmpc ON cma.postcode_id = cmpc.id'); foreach (\explode(' ', $city) as $cityStr) { $query->andWhereClause( "(UNACCENT(LOWER(cmpc.label)) LIKE '%' || UNACCENT(LOWER(?)) || '%' OR cmpc.code LIKE '%' || UNACCENT(LOWER(?)) || '%')", [$cityStr, $city] ); } } if (null !== $countryCode) { $query->setFromClause($query->getFromClause().' JOIN country ON person.nationality_id = country.id'); $query->andWhereClause('country.countrycode = UPPER(?)', [$countryCode]); } if (null !== $gender) { $query->andWhereClause('person.gender = ?', [$gender]); } return $query; } public function fetchQueryCount(SearchApiQuery $query): int { $rsm = new Query\ResultSetMapping(); $rsm->addScalarResult('c', 'c'); $nql = $this->em->createNativeQuery($query->buildQuery(true), $rsm); $nql->setParameters($query->buildParameters(true)); return $nql->getSingleScalarResult(); } /** * @return array|Person[] */ public function fetchQueryPerson(SearchApiQuery $query, ?int $start = 0, ?int $limit = 50): array { $rsm = new Query\ResultSetMappingBuilder($this->em); $rsm->addRootEntityFromClassMetadata(Person::class, 'person'); $query->addSelectClause($rsm->generateSelectClause()); $nql = $this->em->createNativeQuery( $query->buildQuery().' ORDER BY pertinence DESC OFFSET ? LIMIT ?', $rsm )->setParameters(\array_merge($query->buildParameters(), [$start, $limit])); return $nql->getResult(); } /** * @return array|Person[] * * @throws NonUniqueResultException * @throws ParsingException */ public function findBySearchCriteria( int $start, int $limit, bool $simplify = false, ?string $default = null, ?string $firstname = null, ?string $lastname = null, ?\DateTimeInterface $birthdate = null, ?\DateTimeInterface $birthdateBefore = null, ?\DateTimeInterface $birthdateAfter = null, ?string $gender = null, ?string $countryCode = null, ?string $phonenumber = null, ?string $city = null ): array { $query = $this->buildAuthorizedQuery( $default, $firstname, $lastname, $birthdate, $birthdateBefore, $birthdateAfter, $gender, $countryCode, $phonenumber, $city ); return $this->fetchQueryPerson($query); } private function addAuthorizations(SearchApiQuery $query): SearchApiQuery { $authorizedCenters = $this->authorizationHelper ->getReachableCenters($this->security->getUser(), PersonVoter::SEE); if ([] === $authorizedCenters) { return $query->andWhereClause('FALSE = TRUE', []); } return $query ->setFromClause($query->getFromClause().' JOIN view_chill_person_person_center_history_current vcppchc ON vcppchc.person_id = person.id', $query->getFromParams()) ->andWhereClause( strtr( 'vcppchc.center_id IN ({{ center_ids }})', [ '{{ center_ids }}' => \implode( ', ', \array_fill(0, \count($authorizedCenters), '?') ), ] ), \array_map(static fn (Center $c) => $c->getId(), $authorizedCenters) ); } }