person: move similar person matcher to PersonACLEwareRepository

This commit is contained in:
nobohan 2022-02-17 11:33:06 +01:00
parent aebb21935b
commit a3ffd2709d
3 changed files with 99 additions and 12 deletions

View File

@ -16,8 +16,8 @@ use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Form\CreationPersonType; use Chill\PersonBundle\Form\CreationPersonType;
use Chill\PersonBundle\Form\PersonType; use Chill\PersonBundle\Form\PersonType;
use Chill\PersonBundle\Privacy\PrivacyEvent; use Chill\PersonBundle\Privacy\PrivacyEvent;
use Chill\PersonBundle\Repository\PersonACLAwareRepositoryInterface;
use Chill\PersonBundle\Repository\PersonRepository; use Chill\PersonBundle\Repository\PersonRepository;
use Chill\PersonBundle\Search\SimilarPersonMatcher;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
@ -56,11 +56,6 @@ final class PersonController extends AbstractController
*/ */
protected $personRepository; protected $personRepository;
/**
* @var SimilarPersonMatcher
*/
protected $similarPersonMatcher;
/** /**
* @var TranslatorInterface * @var TranslatorInterface
*/ */
@ -81,8 +76,9 @@ final class PersonController extends AbstractController
*/ */
private $validator; private $validator;
private PersonACLAwareRepositoryInterface $personACLAwareRepository;
public function __construct( public function __construct(
SimilarPersonMatcher $similarPersonMatcher,
TranslatorInterface $translator, TranslatorInterface $translator,
EventDispatcherInterface $eventDispatcher, EventDispatcherInterface $eventDispatcher,
PersonRepository $personRepository, PersonRepository $personRepository,
@ -90,9 +86,9 @@ final class PersonController extends AbstractController
LoggerInterface $logger, LoggerInterface $logger,
ValidatorInterface $validator, ValidatorInterface $validator,
EntityManagerInterface $em, EntityManagerInterface $em,
Security $security Security $security,
PersonACLAwareRepositoryInterface $personACLAwareRepository
) { ) {
$this->similarPersonMatcher = $similarPersonMatcher;
$this->translator = $translator; $this->translator = $translator;
$this->eventDispatcher = $eventDispatcher; $this->eventDispatcher = $eventDispatcher;
$this->configPersonAltNameHelper = $configPersonAltNameHelper; $this->configPersonAltNameHelper = $configPersonAltNameHelper;
@ -101,6 +97,7 @@ final class PersonController extends AbstractController
$this->validator = $validator; $this->validator = $validator;
$this->em = $em; $this->em = $em;
$this->security = $security; $this->security = $security;
$this->personACLAwareRepository = $personACLAwareRepository;
} }
public function editAction($person_id, Request $request) public function editAction($person_id, Request $request)
@ -236,8 +233,8 @@ final class PersonController extends AbstractController
$request->getMethod() === Request::METHOD_POST $request->getMethod() === Request::METHOD_POST
&& $form->isValid() && $form->isValid()
) { ) {
$alternatePersons = $this->similarPersonMatcher $alternatePersons = $this->personACLAwareRepository
->matchPerson($person); ->findMatchingPersons($person);
if ( if (
false === $this->isLastPostDataChanges($form, $request, true) false === $this->isLastPostDataChanges($form, $request, true)

View File

@ -14,10 +14,13 @@ namespace Chill\PersonBundle\Repository;
use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Repository\CountryRepository; use Chill\MainBundle\Repository\CountryRepository;
use Chill\MainBundle\Search\ParsingException; use Chill\MainBundle\Search\ParsingException;
use Chill\MainBundle\Search\SearchApi;
use Chill\MainBundle\Search\SearchApiQuery; use Chill\MainBundle\Search\SearchApiQuery;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Security\Authorization\PersonVoter; use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Chill\PersonBundle\Templating\Entity\PersonRender;
use Chill\PersonBundle\Repository\PersonNotDuplicateRepository;
use DateTimeInterface; use DateTimeInterface;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\NonUniqueResultException; use Doctrine\ORM\NonUniqueResultException;
@ -42,16 +45,24 @@ final class PersonACLAwareRepository implements PersonACLAwareRepositoryInterfac
private Security $security; private Security $security;
private PersonRender $personRender;
private PersonNotDuplicateRepository $personNotDuplicateRepository;
public function __construct( public function __construct(
Security $security, Security $security,
EntityManagerInterface $em, EntityManagerInterface $em,
CountryRepository $countryRepository, CountryRepository $countryRepository,
AuthorizationHelper $authorizationHelper AuthorizationHelper $authorizationHelper,
PersonRender $personRender,
PersonNotDuplicateRepository $personNotDuplicateRepository
) { ) {
$this->security = $security; $this->security = $security;
$this->em = $em; $this->em = $em;
$this->countryRepository = $countryRepository; $this->countryRepository = $countryRepository;
$this->authorizationHelper = $authorizationHelper; $this->authorizationHelper = $authorizationHelper;
$this->personRender = $personRender;
$this->personNotDuplicateRepository = $personNotDuplicateRepository;
} }
public function buildAuthorizedQuery( public function buildAuthorizedQuery(
@ -322,4 +333,70 @@ final class PersonACLAwareRepository implements PersonACLAwareRepositoryInterfac
}, $authorizedCenters) }, $authorizedCenters)
); );
} }
/**
* @throws NonUniqueResultException
* @throws ParsingException
*
* @return array|Person[]
*/
public function findMatchingPersons(
Person $person,
float $precision = 0.15,
string $orderBy = self::SIMILAR_SEARCH_ORDER_BY_SIMILARITY
): array {
$query = $this->matchPerson($person, $precision, $orderBy);
$authorizedQuery = $this->addAuthorizations($query);
return $this->fetchQueryPerson($authorizedQuery);
}
public function matchPerson(
Person $person,
float $precision = 0.15,
string $orderBy = self::SIMILAR_SEARCH_ORDER_BY_SIMILARITY
): SearchApiQuery {
$fullName = $this->personRender->renderString($person, []);
$query = new SearchApiQuery();
$query->setFromClause('chill_person_person AS person');
$query->andWhereClause(
"SIMILARITY(person.fullnameCanonical, UNACCENT(LOWER(?))) >= ?",
[$fullName, $precision]
);
if (null !== $person->getId()) {
$query->andWhereClause(
"person.id != ?",
[$person->getId()]
);
$notDuplicatePersons = $this->personNotDuplicateRepository->findNotDuplicatePerson($person);
if (count($notDuplicatePersons)) {
$query->andWhereClause(
"person.id NOT IN (?)",
[$notDuplicatePersons]
);
}
}
switch ($orderBy) {
case self::SIMILAR_SEARCH_ORDER_BY_ALPHABETICAL:
$query->setSelectPertinence('person.fullnameCanonical');
break;
case self::SIMILAR_SEARCH_ORDER_BY_SIMILARITY:
default:
$query->setSelectPertinence(
'SIMILARITY(person.fullnameCanonical, UNACCENT(LOWER(?)))',
[$fullName]
);
}
return $query;
}
} }

View File

@ -17,6 +17,10 @@ use DateTimeInterface;
interface PersonACLAwareRepositoryInterface interface PersonACLAwareRepositoryInterface
{ {
public const SIMILAR_SEARCH_ORDER_BY_ALPHABETICAL = 'alphabetical';
public const SIMILAR_SEARCH_ORDER_BY_SIMILARITY = 'similarity';
public function buildAuthorizedQuery( public function buildAuthorizedQuery(
?string $default = null, ?string $default = null,
?string $firstname = null, ?string $firstname = null,
@ -61,4 +65,13 @@ interface PersonACLAwareRepositoryInterface
?string $phonenumber = null, ?string $phonenumber = null,
?string $city = null ?string $city = null
): array; ): array;
/**
* @return array|Person[]
*/
public function findMatchingPersons(
Person $person,
float $precision = 0.15,
string $orderBy = self::SIMILAR_SEARCH_ORDER_BY_SIMILARITY
): array;
} }