chill-bundles/src/Bundle/ChillPersonBundle/Search/SimilarPersonMatcher.php

113 lines
3.5 KiB
PHP

<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\PersonBundle\Search;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Repository\PersonNotDuplicateRepository;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Chill\PersonBundle\Templating\Entity\PersonRenderInterface;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use function count;
class SimilarPersonMatcher
{
public const SIMILAR_SEARCH_ORDER_BY_ALPHABETICAL = 'alphabetical';
public const SIMILAR_SEARCH_ORDER_BY_SIMILARITY = 'similarity';
/**
* @var AuthorizationHelper
*/
protected $authorizationHelper;
/**
* @var EntityManagerInterface
*/
protected $em;
protected PersonNotDuplicateRepository $personNotDuplicateRepository;
protected PersonRenderInterface $personRender;
/**
* @var TokenStorageInterface
*/
protected $tokenStorage;
public function __construct(
EntityManagerInterface $em,
AuthorizationHelper $authorizationHelper,
TokenStorageInterface $tokenStorage,
PersonNotDuplicateRepository $personNotDuplicateRepository,
PersonRenderInterface $personRender
) {
$this->em = $em;
$this->authorizationHelper = $authorizationHelper;
$this->tokenStorage = $tokenStorage;
$this->personNotDuplicateRepository = $personNotDuplicateRepository;
$this->personRender = $personRender;
}
public function matchPerson(
Person $person,
float $precision = 0.15,
string $orderBy = self::SIMILAR_SEARCH_ORDER_BY_SIMILARITY,
bool $addYearComparison = false
) {
$centers = $this->authorizationHelper->getReachableCenters(
$this->tokenStorage->getToken()->getUser(),
PersonVoter::SEE
);
$query = $this->em->createQuery();
$dql = 'SELECT p from ChillPersonBundle:Person p '
. ' WHERE ('
. ' SIMILARITY(p.fullnameCanonical, UNACCENT(LOWER(:fullName))) >= :precision '
. ' ) '
. ' AND p.center IN (:centers)';
if ($person->getId() !== null) {
$dql .= ' AND p.id != :personId ';
$notDuplicatePersons = $this->personNotDuplicateRepository->findNotDuplicatePerson($person);
$query->setParameter('personId', $person->getId());
if (count($notDuplicatePersons)) {
$dql .= ' AND p.id not in (:notDuplicatePersons)';
$query->setParameter('notDuplicatePersons', $notDuplicatePersons);
}
}
switch ($orderBy) {
case self::SIMILAR_SEARCH_ORDER_BY_ALPHABETICAL:
$dql .= ' ORDER BY p.fullnameCanonical ASC ';
break;
case self::SIMILAR_SEARCH_ORDER_BY_SIMILARITY:
default:
$dql .= ' ORDER BY SIMILARITY(p.fullnameCanonical, UNACCENT(LOWER(:fullName))) DESC ';
}
$query = $query
->setDQL($dql)
->setParameter('fullName', $this->personRender->renderString($person, []))
->setParameter('centers', $centers)
->setParameter('precision', $precision);
return $query->getResult();
}
}