extend search api to users

This commit is contained in:
Julien Fastré 2021-08-16 14:39:18 +02:00
parent 6b4e27a531
commit 54c4524b27
6 changed files with 140 additions and 42 deletions

View File

@ -22,7 +22,9 @@
namespace Chill\MainBundle\Controller;
use Chill\MainBundle\Search\SearchApiNoQueryException;
use Chill\MainBundle\Serializer\Model\Collection;
use GuzzleHttp\Psr7\Response;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Chill\MainBundle\Search\UnknowSearchDomainException;
@ -33,6 +35,7 @@ use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\HttpFoundation\JsonResponse;
use Chill\MainBundle\Search\SearchProvider;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Contracts\Translation\TranslatorInterface;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Search\SearchApi;
@ -159,9 +162,13 @@ class SearchController extends AbstractController
." one type");
}
try {
$collection = $this->searchApi->getResults($query, $types, []);
} catch (SearchApiNoQueryException $e) {
throw new BadRequestHttpException($e->getMessage(), $e);
}
return $this->json($collection);
return $this->json($collection, \Symfony\Component\HttpFoundation\Response::HTTP_OK, [], [ "groups" => ["read"]]);
}
public function advancedSearchListAction(Request $request)

View File

@ -0,0 +1,59 @@
<?php
namespace Chill\MainBundle\Search\Entity;
use Chill\MainBundle\Repository\UserRepository;
use Chill\MainBundle\Search\SearchApiInterface;
use Chill\MainBundle\Search\SearchApiQuery;
class SearchUserApiProvider implements SearchApiInterface
{
private UserRepository $userRepository;
/**
* @param UserRepository $userRepository
*/
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
public function provideQuery(string $pattern, array $parameters): SearchApiQuery
{
$query = new SearchApiQuery();
$query
->setSelectKey("user")
->setSelectJsonbMetadata("jsonb_build_object('id', u.id)")
->setSelectPertinence("GREATEST(SIMILARITY(LOWER(UNACCENT(?)), u.usernamecanonical),
SIMILARITY(LOWER(UNACCENT(?)), u.emailcanonical))", [ $pattern, $pattern ])
->setFromClause("users AS u")
->setWhereClause("SIMILARITY(LOWER(UNACCENT(?)), u.usernamecanonical) > 0.15
OR
SIMILARITY(LOWER(UNACCENT(?)), u.emailcanonical) > 0.15
", [ $pattern, $pattern ]);
return $query;
}
public function supportsTypes(string $pattern, array $types, array $parameters): bool
{
return \in_array('user', $types);
}
public function prepare(array $metadatas): void
{
$ids = \array_map(fn($m) => $m['id'], $metadatas);
$this->userRepository->findBy([ 'id' => $ids ]);
}
public function supportsResult(string $key, array $metadatas): bool
{
return $key === 'user';
}
public function getResult(string $key, array $metadata, float $pertinence)
{
return $this->userRepository->find($metadata['id']);
}
}

View File

@ -2,6 +2,7 @@
namespace Chill\MainBundle\Search;
use Chill\MainBundle\Search\Entity\SearchUserApiProvider;
use Chill\MainBundle\Serializer\Model\Collection;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\PersonBundle\Search\SearchPersonApiProvider;
@ -25,12 +26,14 @@ class SearchApi
EntityManagerInterface $em,
SearchPersonApiProvider $searchPerson,
ThirdPartyApiSearch $thirdPartyApiSearch,
SearchUserApiProvider $searchUser,
PaginatorFactory $paginator
)
{
$this->em = $em;
$this->providers[] = $searchPerson;
$this->providers[] = $thirdPartyApiSearch;
$this->providers[] = $searchUser;
$this->paginator = $paginator;
}
@ -41,6 +44,10 @@ class SearchApi
{
$queries = $this->findQueries($pattern, $types, $parameters);
if (0 === count($queries)) {
throw new SearchApiNoQueryException($pattern, $types, $parameters);
}
$total = $this->countItems($queries, $types, $parameters);
$paginator = $this->paginator->create($total);
@ -49,9 +56,7 @@ class SearchApi
$this->prepareProviders($rawResults);
$results = $this->buildResults($rawResults);
$collection = new Collection($results, $paginator);
return $collection;
return new Collection($results, $paginator);
}
private function findQueries($pattern, array $types, array $parameters): array

View File

@ -0,0 +1,23 @@
<?php
namespace Chill\MainBundle\Search;
use Throwable;
class SearchApiNoQueryException extends \RuntimeException
{
private string $pattern;
private array $types;
private array $parameters;
public function __construct(string $pattern = "", array $types = [], array $parameters = [], $code = 0, Throwable $previous = null)
{
$typesStr = \implode(", ", $types);
$message = "No query for this search: pattern : {$pattern}, types: {$typesStr}";
$this->pattern = $pattern;
$this->types = $types;
$this->parameters = $parameters;
parent::__construct($message, $code, $previous);
}
}

View File

@ -127,8 +127,6 @@ paths:
- person
- thirdparty
description: >
**Warning**: This is currently a stub (not really implemented
The search is performed across multiple entities. The entities must be listed into
`type` parameters.
@ -152,6 +150,7 @@ paths:
enum:
- person
- thirdparty
- user
responses:
200:
description: "OK"

View File

@ -7,3 +7,8 @@ services:
Chill\MainBundle\Search\SearchApi:
autowire: true
autoconfigure: true
Chill\MainBundle\Search\Entity\:
autowire: true
autoconfigure: true
resource: '../../Search/Entity'