mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-07-03 15:36:14 +00:00
add similarity results for persons search
This commit is contained in:
parent
9d8d330eb3
commit
7be2d408f9
@ -11,6 +11,17 @@ services:
|
||||
tags:
|
||||
- { name: chill.search, alias: 'person_regular' }
|
||||
|
||||
Chill\PersonBundle\Search\SimilarityPersonSearch:
|
||||
arguments:
|
||||
- "@doctrine.orm.entity_manager"
|
||||
- "@security.token_storage"
|
||||
- "@chill.main.security.authorization.helper"
|
||||
- "@chill_main.paginator_factory"
|
||||
calls:
|
||||
- ['setContainer', ["@service_container"]]
|
||||
tags:
|
||||
- { name: chill.search, alias: 'person_similarity' }
|
||||
|
||||
Chill\PersonBundle\Search\SimilarPersonMatcher:
|
||||
arguments:
|
||||
$em: '@Doctrine\ORM\EntityManagerInterface'
|
||||
|
@ -68,4 +68,5 @@ Reset: 'Remise à zéro'
|
||||
'Person details': 'Détails de la personne'
|
||||
|
||||
Create an accompanying period: Create an accompanying period
|
||||
'Create': Create
|
||||
'Create': Create
|
||||
Similar persons: Similar persons
|
||||
|
@ -201,3 +201,4 @@ Aggregate by age: Aggréger par âge
|
||||
Calculate age in relation to this date: Calculer l'âge par rapport à cette date
|
||||
|
||||
Group people by country of birth: Aggréger les personnes par pays de naissance
|
||||
Similar persons: Personnes similaires
|
||||
|
@ -14,7 +14,7 @@
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#}
|
||||
<h2>{{ 'Person search results'|trans }}</h2>
|
||||
<h2>{{ title|default('Person search results')|trans }}</h2>
|
||||
|
||||
<p>
|
||||
{{ '%total% persons matching the search pattern:'|transchoice( total, { '%total%' : total}) }}
|
||||
|
237
Search/SimilarityPersonSearch.php
Normal file
237
Search/SimilarityPersonSearch.php
Normal file
@ -0,0 +1,237 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\PersonBundle\Search;
|
||||
|
||||
|
||||
use Chill\MainBundle\Pagination\PaginatorFactory;
|
||||
use Chill\MainBundle\Search\AbstractSearch;
|
||||
use Chill\MainBundle\Search\SearchInterface;
|
||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
|
||||
use Symfony\Component\Security\Core\Role\Role;
|
||||
|
||||
/**
|
||||
* Class SimilarityPersonSearch
|
||||
*
|
||||
* @package Chill\PersonBundle\Search
|
||||
*/
|
||||
class SimilarityPersonSearch extends AbstractSearch
|
||||
{
|
||||
|
||||
use ContainerAwareTrait;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var EntityManagerInterface
|
||||
*/
|
||||
private $em;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var \Chill\MainBundle\Entity\User
|
||||
*/
|
||||
private $user;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var AuthorizationHelper
|
||||
*/
|
||||
private $helper;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var PaginatorFactory
|
||||
*/
|
||||
protected $paginatorFactory;
|
||||
|
||||
const NAME = "person_similarity";
|
||||
|
||||
|
||||
/**
|
||||
* SimilarityPersonSearch constructor.
|
||||
*
|
||||
* @param EntityManagerInterface $em
|
||||
* @param TokenStorage $tokenStorage
|
||||
* @param AuthorizationHelper $helper
|
||||
* @param PaginatorFactory $paginatorFactory
|
||||
*/
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
TokenStorage $tokenStorage,
|
||||
AuthorizationHelper $helper,
|
||||
PaginatorFactory $paginatorFactory)
|
||||
{
|
||||
$this->em = $em;
|
||||
$this->user = $tokenStorage->getToken()->getUser();
|
||||
$this->helper = $helper;
|
||||
$this->paginatorFactory = $paginatorFactory;
|
||||
|
||||
// throw an error if user is not a valid user
|
||||
if (!$this->user instanceof \Chill\MainBundle\Entity\User) {
|
||||
throw new \LogicException('The user provided must be an instance'
|
||||
. ' of Chill\MainBundle\Entity\User');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-PHPdoc)
|
||||
* @see \Chill\MainBundle\Search\SearchInterface::getOrder()
|
||||
*/
|
||||
public function getOrder()
|
||||
{
|
||||
return 200;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-PHPdoc)
|
||||
* @see \Chill\MainBundle\Search\SearchInterface::isActiveByDefault()
|
||||
*/
|
||||
public function isActiveByDefault()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function supports($domain, $format)
|
||||
{
|
||||
return 'person' === $domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $terms
|
||||
* @param int $start
|
||||
* @param int $limit
|
||||
* @param array $options
|
||||
* @param string $format
|
||||
* @return array
|
||||
*/
|
||||
public function renderResult(array $terms, $start = 0, $limit = 50, array $options = array(), $format = 'html')
|
||||
{
|
||||
$total = $this->count($terms);
|
||||
$paginator = $this->paginatorFactory->create($total);
|
||||
|
||||
if ($format === 'html') {
|
||||
return $this->container->get('templating')->render('ChillPersonBundle:Person:list.html.twig',
|
||||
array(
|
||||
'persons' => $this->search($terms, $start, $limit, $options),
|
||||
'pattern' => $this->recomposePattern($terms, array('nationality',
|
||||
'firstname', 'lastname', 'birthdate', 'gender',
|
||||
'birthdate-before','birthdate-after'), $terms['_domain']),
|
||||
'total' => $total,
|
||||
'start' => $start,
|
||||
'search_name' => self::NAME,
|
||||
'preview' => $options[SearchInterface::SEARCH_PREVIEW_OPTION],
|
||||
'paginator' => $paginator,
|
||||
'title' => "Similar persons"
|
||||
));
|
||||
} elseif ($format === 'json') {
|
||||
return [
|
||||
'results' => $this->search($terms, $start, $limit, \array_merge($options, [ 'simplify' => true ])),
|
||||
'pagination' => [
|
||||
'more' => $paginator->hasNextPage()
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string $pattern
|
||||
* @param int $start
|
||||
* @param int $limit
|
||||
* @param array $options
|
||||
* @return Person[]
|
||||
*/
|
||||
protected function search(array $terms, $start, $limit, array $options = array())
|
||||
{
|
||||
$qb = $this->createQuery($terms, 'search');
|
||||
|
||||
if ($options['simplify'] ?? false) {
|
||||
$qb->select(
|
||||
'p.id',
|
||||
$qb->expr()->concat(
|
||||
'p.firstName',
|
||||
$qb->expr()->literal(' '),
|
||||
'p.lastName'
|
||||
).'AS text'
|
||||
);
|
||||
} else {
|
||||
$qb->select('p');
|
||||
}
|
||||
|
||||
$qb
|
||||
->setMaxResults($limit)
|
||||
->setFirstResult($start);
|
||||
|
||||
//order by firstname, lastname
|
||||
|
||||
$qb
|
||||
->orderBy('p.firstName')
|
||||
->addOrderBy('p.lastName');
|
||||
|
||||
if ($options['simplify'] ?? false) {
|
||||
return $qb->getQuery()->getResult(Query::HYDRATE_ARRAY);
|
||||
} else {
|
||||
return $qb->getQuery()->getResult();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected function count(array $terms)
|
||||
{
|
||||
$qb = $this->createQuery($terms);
|
||||
|
||||
|
||||
$qb->select('COUNT(p.id)');
|
||||
|
||||
return $qb->getQuery()->getSingleScalarResult();
|
||||
}
|
||||
|
||||
|
||||
private $_cacheQuery = array();
|
||||
|
||||
/**
|
||||
*
|
||||
* @param array $terms
|
||||
* @return \Doctrine\ORM\QueryBuilder
|
||||
*/
|
||||
protected function createQuery(array $terms)
|
||||
{
|
||||
//get from cache
|
||||
$cacheKey = md5(serialize($terms));
|
||||
if (array_key_exists($cacheKey, $this->_cacheQuery)) {
|
||||
return clone $this->_cacheQuery[$cacheKey];
|
||||
}
|
||||
|
||||
$qb = $this->em->createQueryBuilder();
|
||||
|
||||
$qb->from('ChillPersonBundle:Person', 'p');
|
||||
|
||||
if ($terms['_default'] !== '') {
|
||||
$grams = explode(' ', $terms['_default']);
|
||||
|
||||
foreach($grams as $key => $gram) {
|
||||
$qb->andWhere(
|
||||
'SIMILARITY(p.fullnameCanonical, UNACCENT(LOWER(:default_'.$key.'))) >= 0.15')
|
||||
->setParameter('default_'.$key, '%'.$gram.'%');
|
||||
}
|
||||
}
|
||||
|
||||
//restraint center for security
|
||||
$reachableCenters = $this->helper->getReachableCenters($this->user,
|
||||
new Role('CHILL_PERSON_SEE'));
|
||||
$qb->andWhere($qb->expr()
|
||||
->in('p.center', ':centers'))
|
||||
->setParameter('centers', $reachableCenters)
|
||||
;
|
||||
|
||||
$this->_cacheQuery[$cacheKey] = $qb;
|
||||
|
||||
return clone $qb;
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user