diff --git a/src/Repository/SearchIndexRepository.php b/src/Repository/SearchIndexRepository.php index a374e14..4b77da7 100644 --- a/src/Repository/SearchIndexRepository.php +++ b/src/Repository/SearchIndexRepository.php @@ -9,7 +9,7 @@ use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\ORM\Query; use Doctrine\Persistence\ManagerRegistry; -class SearchIndexRepository extends ServiceEntityRepository +final class SearchIndexRepository extends ServiceEntityRepository { /** * @param ManagerRegistry $registry @@ -19,99 +19,39 @@ class SearchIndexRepository extends ServiceEntityRepository parent::__construct($registry, SearchIndex::class); } - /** - * Saves a SearchIndex entity - * - * @param SearchIndex $entity - * @param boolean $flush - * @return void - */ - public function add(SearchIndex $entity, bool $flush = false): void - { - $this->getEntityManager()->persist($entity); - - if ($flush) { - $this->getEntityManager()->flush(); - } - } - - /** - * Removes a SearchIndex entity - * - * @param SearchIndex $entity - * @param boolean $flush - * @return void - */ - public function remove(SearchIndex $entity, bool $flush = false): void - { - $this->getEntityManager()->remove($entity); - - if ($flush) { - $this->getEntityManager()->flush(); - } - } - /** * Returns a Query object ready to be paginated or used to present results. - * - * @param string $query - * @param integer $minScore - * @return Query */ public function findAllPagination(string $query, int $minScore = 0): Query { - $qb = $this->createQueryBuilder('r') - ->addSelect('MATCH(r.data) AGAINST(:searchText boolean) AS score') - ->where( - sprintf( - 'MATCH(r.data) AGAINST(:searchText boolean) > %f', - $minScore - ) - )->orderBy('score', 'DESC') - ->setParameter( - 'searchText', - $this->convertSearchTerm($query) - ); - return $qb->getQuery(); + return $this->createQueryBuilder('r') + ->addSelect('MATCH(r.searchText) AGAINST(:searchText boolean) AS score') + ->where('MATCH(r.searchText) AGAINST(:searchText boolean) > :minScore') + ->orderBy('score', 'DESC') + ->setParameter('searchText', $this->convertSearchTerm($query)) + ->setParameter('minScore', $minScore) + ->getQuery(); } /** - * Takes a string $query and explodes into individual words. Each word - * is then prefixed with + and ends with *, making the full text search - * operate as wildcard on all words - * - * @param string $query - * @return string + * Splits the query into words and wraps each as `+WORD*`, so the fulltext + * search requires every word and matches as a wildcard on each word's start. */ private function convertSearchTerm(string $query): string { + $sanitised = preg_replace('/[^\w\d]/', ' ', $query) ?? ''; + $words = preg_split('/\s+/', $sanitised, -1, PREG_SPLIT_NO_EMPTY) ?: []; + $extractedWords = []; - $sanitisedString = preg_replace('/[^\w^\d]/', ' ', $query); - $words = mb_split('\s', preg_replace(['/([^\w+])/','/(\s+)/'], ' ', $sanitisedString)); - foreach ($words as $word) { - if (strlen($word)< 1) { - // - continue; - } - $word = strtoupper($word); - $extractedWords[$word] = $word; + $extractedWords[$word] = '+' . $word . '*'; } - array_walk( - $extractedWords, - function(&$word) { - // require every word but allow matching just the start - $word = '+' . $word . '*'; - } - ); - return implode(' ', $extractedWords); } /** * Clears the index table of all results - * @return void */ public function clearIndex(): void {