Add search functionality for user groups

Implemented `SearchUserGroupApiProvider` to handle user group search requests. Added `UserGroupRepository` and its interface to support search queries. Updated API specs to include user group as a searchable type.
This commit is contained in:
Julien Fastré 2024-09-26 14:17:19 +02:00
parent b4fa478177
commit 9e69c97250
Signed by: julienfastre
GPG Key ID: BDE2190974723FCB
5 changed files with 205 additions and 0 deletions

View File

@ -0,0 +1,68 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Repository;
use Chill\MainBundle\Entity\UserGroup;
use Chill\MainBundle\Search\SearchApiQuery;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
final readonly class UserGroupRepository implements UserGroupRepositoryInterface
{
private EntityRepository $repository;
public function __construct(EntityManagerInterface $em)
{
$this->repository = $em->getRepository(UserGroup::class);
}
public function find($id): ?UserGroup
{
return $this->repository->find($id);
}
public function findAll(): array
{
return $this->repository->findAll();
}
public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array
{
return $this->repository->findBy($criteria, $orderBy, $limit, $offset);
}
public function findOneBy(array $criteria): ?UserGroup
{
return $this->repository->findOneBy($criteria);
}
public function getClassName(): string
{
return UserGroup::class;
}
public function provideSearchApiQuery(string $pattern, string $lang, string $selectKey = 'user-group'): SearchApiQuery
{
$query = new SearchApiQuery();
$query
->setSelectKey($selectKey)
->setSelectJsonbMetadata("jsonb_build_object('id', ug.id)")
->setSelectPertinence('3 + SIMILARITY(LOWER(UNACCENT(?)), ug.label->>?) + CASE WHEN (EXISTS(SELECT 1 FROM unnest(string_to_array(label->>?, \' \')) AS t WHERE LOWER(t) LIKE \'%\' || LOWER(UNACCENT(?)) || \'%\')) THEN 100 ELSE 0 END', [$pattern, $lang, $lang, $pattern])
->setFromClause('chill_main_user_group AS ug')
->setWhereClauses('
SIMILARITY(LOWER(UNACCENT(?)), ug.label->>?) > 0.15
OR ug.label->>? LIKE \'%\' || LOWER(UNACCENT(?)) || \'%\'
', [$pattern, $lang, $pattern, $lang]);
return $query;
}
}

View File

@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Repository;
use Chill\MainBundle\Entity\UserGroup;
use Chill\MainBundle\Search\SearchApiQuery;
use Doctrine\Persistence\ObjectRepository;
/**
* @template-extends ObjectRepository<UserGroup>
*/
interface UserGroupRepositoryInterface extends ObjectRepository
{
/**
* Provide a SearchApiQuery for searching amongst user groups.
*/
public function provideSearchApiQuery(string $pattern, string $lang, string $selectKey = 'user-group'): SearchApiQuery;
}

View File

@ -0,0 +1,59 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Search\Entity;
use Chill\MainBundle\Repository\UserGroupRepositoryInterface;
use Chill\MainBundle\Search\SearchApiInterface;
use Chill\MainBundle\Search\SearchApiQuery;
use Symfony\Contracts\Translation\LocaleAwareInterface;
/**
* Provide search api for user group.
*/
class SearchUserGroupApiProvider implements SearchApiInterface, LocaleAwareInterface
{
private string $locale;
public function __construct(private readonly UserGroupRepositoryInterface $userGroupRepository) {}
public function setLocale(string $locale): void
{
$this->locale = $locale;
}
public function getLocale(): string
{
return $this->locale;
}
public function getResult(string $key, array $metadata, float $pertinence)
{
return $this->userGroupRepository->find($metadata['id']);
}
public function prepare(array $metadatas): void {}
public function provideQuery(string $pattern, array $parameters): SearchApiQuery
{
return $this->userGroupRepository->provideSearchApiQuery($pattern, $this->getLocale(), 'user-group');
}
public function supportsResult(string $key, array $metadatas): bool
{
return 'user-group' === $key;
}
public function supportsTypes(string $pattern, array $types, array $parameters): bool
{
return in_array('user-group', $types, true);
}
}

View File

@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Tests\Repository;
use Chill\MainBundle\Repository\UserGroupRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
/**
* @internal
*
* @coversNothing
*/
class UserGroupRepositoryTest extends KernelTestCase
{
private EntityManagerInterface $entityManager;
protected function setUp(): void
{
self::bootKernel();
$this->entityManager = static::getContainer()->get(EntityManagerInterface::class);
}
public function testProvideSearchApiQuery(): void
{
$repository = new UserGroupRepository($this->entityManager);
$apiQuery = $repository->provideSearchApiQuery('trav', 'fr');
// test that the query does works
$sql = $apiQuery->buildQuery();
$params = $apiQuery->buildParameters();
$result = $this->entityManager->getConnection()->executeQuery($sql, $params);
$results = $result->fetchAllAssociative();
self::assertIsArray($results);
}
}

View File

@ -236,6 +236,7 @@ paths:
- thirdparty
- user
- household
- user-group
responses:
200:
description: "OK"