mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
Duplicate module
Signed-off-by: Mathieu Jaumotte <mathieu.jaumotte@champs-libres.coop>
This commit is contained in:
parent
728ea73bdf
commit
0149457fba
@ -94,7 +94,6 @@ class PersonMove
|
|||||||
|
|
||||||
foreach ($metadata->getAssociationMappings() as $field => $mapping) {
|
foreach ($metadata->getAssociationMappings() as $field => $mapping) {
|
||||||
if ($mapping['targetEntity'] === Person::class) {
|
if ($mapping['targetEntity'] === Person::class) {
|
||||||
|
|
||||||
if (\in_array($metadata->getName(), $toDelete)) {
|
if (\in_array($metadata->getName(), $toDelete)) {
|
||||||
$sql = $this->createDeleteSQL($metadata, $from, $field);
|
$sql = $this->createDeleteSQL($metadata, $from, $field);
|
||||||
$event = new ActionEvent($from->getId(), $metadata->getName(), $sql,
|
$event = new ActionEvent($from->getId(), $metadata->getName(), $sql,
|
||||||
|
@ -2,13 +2,17 @@
|
|||||||
|
|
||||||
namespace Chill\PersonBundle\Controller;
|
namespace Chill\PersonBundle\Controller;
|
||||||
|
|
||||||
|
use Chill\PersonBundle\Actions\Remove\PersonMove;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
use Chill\PersonBundle\Entity\Person;
|
use Chill\PersonBundle\Entity\Person;
|
||||||
use Chill\PersonBundle\Entity\PersonNotDuplicate;
|
use Chill\PersonBundle\Entity\PersonNotDuplicate;
|
||||||
use Chill\PersonBundle\Form\PersonConfimDuplicateType;
|
use Chill\PersonBundle\Form\PersonConfimDuplicateType;
|
||||||
|
use Chill\PersonBundle\Privacy\PrivacyEvent;
|
||||||
use Chill\PersonBundle\Repository\PersonRepository;
|
use Chill\PersonBundle\Repository\PersonRepository;
|
||||||
use Chill\PersonBundle\Search\SimilarPersonMatcher;
|
use Chill\PersonBundle\Search\SimilarPersonMatcher;
|
||||||
use http\Exception\InvalidArgumentException;
|
use http\Exception\InvalidArgumentException;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||||
|
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\Translation\TranslatorInterface;
|
use Symfony\Component\Translation\TranslatorInterface;
|
||||||
|
|
||||||
@ -29,14 +33,28 @@ class PersonDuplicateController extends Controller
|
|||||||
*/
|
*/
|
||||||
private $personRepository;
|
private $personRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Chill\PersonBundle\Actions\Remove\PersonMove
|
||||||
|
*/
|
||||||
|
private $personMove;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
|
||||||
|
*/
|
||||||
|
private $eventDispatcher;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
SimilarPersonMatcher $similarPersonMatcher,
|
SimilarPersonMatcher $similarPersonMatcher,
|
||||||
TranslatorInterface $translator,
|
TranslatorInterface $translator,
|
||||||
PersonRepository $personRepository
|
PersonRepository $personRepository,
|
||||||
|
PersonMove $personMove,
|
||||||
|
EventDispatcherInterface $eventDispatcher
|
||||||
) {
|
) {
|
||||||
$this->similarPersonMatcher = $similarPersonMatcher;
|
$this->similarPersonMatcher = $similarPersonMatcher;
|
||||||
$this->translator = $translator;
|
$this->translator = $translator;
|
||||||
$this->personRepository = $personRepository;
|
$this->personRepository = $personRepository;
|
||||||
|
$this->personMove = $personMove;
|
||||||
|
$this->eventDispatcher = $eventDispatcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function viewAction($person_id)
|
public function viewAction($person_id)
|
||||||
@ -47,88 +65,88 @@ class PersonDuplicateController extends Controller
|
|||||||
. " found on this server");
|
. " found on this server");
|
||||||
}
|
}
|
||||||
|
|
||||||
$duplicatePersons = $this->similarPersonMatcher->matchPerson($person, 0.5);
|
$duplicatePersons = $this->similarPersonMatcher->
|
||||||
|
matchPerson($person, 0.5, SimilarPersonMatcher::SIMILAR_SEARCH_ORDER_BY_ALPHABETICAL);
|
||||||
|
|
||||||
|
$notDuplicatePersons = $this->getDoctrine()->getRepository(PersonNotDuplicate::class)
|
||||||
|
->findNotDuplicatePerson($person);
|
||||||
|
|
||||||
return $this->render('ChillPersonBundle:PersonDuplicate:view.html.twig', [
|
return $this->render('ChillPersonBundle:PersonDuplicate:view.html.twig', [
|
||||||
"person" => $person,
|
'person' => $person,
|
||||||
'duplicatePersons' => $duplicatePersons
|
'duplicatePersons' => $duplicatePersons,
|
||||||
|
'notDuplicatePersons' => $notDuplicatePersons,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function confirmAction($person_id, $person2_id, Request $request)
|
public function confirmAction($person1_id, $person2_id, Request $request)
|
||||||
{
|
{
|
||||||
if ($person_id === $person2_id) {
|
[$person1, $person2] = $this->_getPersonsByPriority($person1_id, $person2_id);
|
||||||
throw new InvalidArgumentException('Can not merge same person');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($person_id > $person2_id) {
|
|
||||||
$tmpId = $person2_id;
|
|
||||||
$person2_id = $person_id;
|
|
||||||
$person_id = $tmpId;
|
|
||||||
unset($tmpId);
|
|
||||||
}
|
|
||||||
|
|
||||||
$person = $this->_getPerson($person_id);
|
|
||||||
if ($person === null) {
|
|
||||||
throw $this->createNotFoundException("Person with id $person_id not"
|
|
||||||
. " found on this server");
|
|
||||||
}
|
|
||||||
|
|
||||||
$person2 = $this->_getPerson($person2_id);
|
|
||||||
if ($person2 === null) {
|
|
||||||
throw $this->createNotFoundException("Person with id $person2_id not"
|
|
||||||
. " found on this server");
|
|
||||||
}
|
|
||||||
|
|
||||||
$form = $this->createForm(PersonConfimDuplicateType::class);
|
$form = $this->createForm(PersonConfimDuplicateType::class);
|
||||||
|
|
||||||
$form->handleRequest($request);
|
$form->handleRequest($request);
|
||||||
|
|
||||||
if ($form->isSubmitted() && $form->isValid()) {
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
dd('todo');
|
$event = new PrivacyEvent($person1, array(
|
||||||
|
'element_class' => Person::class,
|
||||||
|
'action' => 'move'
|
||||||
|
));
|
||||||
|
$event->addPerson($person2);
|
||||||
|
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
|
||||||
|
|
||||||
|
$sqls = $this->personMove->getSQL($person2, $person1);
|
||||||
|
|
||||||
|
$connection = $this->getDoctrine()->getConnection();
|
||||||
|
|
||||||
|
$connection->beginTransaction();
|
||||||
|
foreach($sqls as $sql) {
|
||||||
|
$connection->executeQuery($sql);
|
||||||
|
}
|
||||||
|
$connection->commit();
|
||||||
|
|
||||||
|
return $this->redirectToRoute('chill_person_duplicate_view', ['person_id' => $person1->getId()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->render('ChillPersonBundle:PersonDuplicate:confirm.html.twig', [
|
return $this->render('ChillPersonBundle:PersonDuplicate:confirm.html.twig', [
|
||||||
'person' => $person,
|
'person' => $person1,
|
||||||
'person2' => $person2,
|
'person2' => $person2,
|
||||||
'form' => $form->createView(),
|
'form' => $form->createView(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function notDuplicateAction($person_id, $person2_id)
|
public function notDuplicateAction($person1_id, $person2_id)
|
||||||
{
|
{
|
||||||
if ($person_id === $person2_id) {
|
[$person1, $person2] = $this->_getPersonsByPriority($person1_id, $person2_id);
|
||||||
throw new InvalidArgumentException('Can not merge same person');
|
|
||||||
|
$personNotDuplicate = $this->getDoctrine()->getRepository(PersonNotDuplicate::class)
|
||||||
|
->findOneBy(['person1' => $person1, 'person2' => $person2]);
|
||||||
|
|
||||||
|
if (!$personNotDuplicate instanceof PersonNotDuplicate) {
|
||||||
|
$personNotDuplicate = new PersonNotDuplicate();
|
||||||
|
$personNotDuplicate->setPerson1($person1);
|
||||||
|
$personNotDuplicate->setPerson2($person2);
|
||||||
|
$personNotDuplicate->setUser($this->getUser());
|
||||||
|
|
||||||
|
$this->getDoctrine()->getManager()->persist($personNotDuplicate);
|
||||||
|
$this->getDoctrine()->getManager()->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($person_id > $person2_id) {
|
return $this->redirectToRoute('chill_person_duplicate_view', ['person_id' => $person1->getId()]);
|
||||||
$tmpId = $person2_id;
|
}
|
||||||
$person2_id = $person_id;
|
|
||||||
$person_id = $tmpId;
|
public function removeNotDuplicateAction($person1_id, $person2_id)
|
||||||
unset($tmpId);
|
{
|
||||||
|
[$person1, $person2] = $this->_getPersonsByPriority($person1_id, $person2_id);
|
||||||
|
|
||||||
|
$personNotDuplicate = $this->getDoctrine()->getRepository(PersonNotDuplicate::class)
|
||||||
|
->findOneBy(['person1' => $person1, 'person2' => $person2]);
|
||||||
|
|
||||||
|
if ($personNotDuplicate instanceof PersonNotDuplicate) {
|
||||||
|
$this->getDoctrine()->getManager()->remove($personNotDuplicate);
|
||||||
|
$this->getDoctrine()->getManager()->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
$person = $this->_getPerson($person_id);
|
return $this->redirectToRoute('chill_person_duplicate_view', ['person_id' => $person1->getId()]);
|
||||||
if ($person === null) {
|
|
||||||
throw $this->createNotFoundException("Person with id $person_id not"
|
|
||||||
. " found on this server");
|
|
||||||
}
|
|
||||||
|
|
||||||
$person2 = $this->_getPerson($person2_id);
|
|
||||||
if ($person2 === null) {
|
|
||||||
throw $this->createNotFoundException("Person with id $person2_id not"
|
|
||||||
. " found on this server");
|
|
||||||
}
|
|
||||||
|
|
||||||
$personNotDuplicate = new PersonNotDuplicate();
|
|
||||||
$personNotDuplicate->setPerson1($person);
|
|
||||||
$personNotDuplicate->setPerson2($person2);
|
|
||||||
$personNotDuplicate->setUser($this->getUser());
|
|
||||||
|
|
||||||
$this->getDoctrine()->getManager()->persist($personNotDuplicate);
|
|
||||||
$this->getDoctrine()->getManager()->flush();
|
|
||||||
|
|
||||||
return $this->redirectToRoute('chill_person_duplicate_view', ['person_id' => $person->getId()]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -138,4 +156,31 @@ class PersonDuplicateController extends Controller
|
|||||||
{
|
{
|
||||||
return $this->personRepository->find($id);
|
return $this->personRepository->find($id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function _getPersonsByPriority($person1_id, $person2_id)
|
||||||
|
{
|
||||||
|
if ($person1_id === $person2_id) {
|
||||||
|
throw new InvalidArgumentException('Can not merge same person');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($person1_id > $person2_id) {
|
||||||
|
$person1 = $this->_getPerson($person2_id);
|
||||||
|
$person2 = $this->_getPerson($person1_id);
|
||||||
|
} else {
|
||||||
|
$person1 = $this->_getPerson($person1_id);
|
||||||
|
$person2 = $this->_getPerson($person2_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($person1 === null) {
|
||||||
|
throw $this->createNotFoundException("Person with id $person1_id not"
|
||||||
|
. " found on this server");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($person2 === null) {
|
||||||
|
throw $this->createNotFoundException("Person with id $person2_id not"
|
||||||
|
. " found on this server");
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$person1, $person2];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ use Chill\MainBundle\Entity\User;
|
|||||||
* PersonNotDuplicate
|
* PersonNotDuplicate
|
||||||
*
|
*
|
||||||
* @ORM\Table(name="chill_person_not_duplicate")
|
* @ORM\Table(name="chill_person_not_duplicate")
|
||||||
* @ORM\Entity()
|
* @ORM\Entity(repositoryClass="Chill\PersonBundle\Repository\PersonNotDuplicateRepository")
|
||||||
*/
|
*/
|
||||||
class PersonNotDuplicate
|
class PersonNotDuplicate
|
||||||
{
|
{
|
||||||
|
@ -16,7 +16,7 @@ class PersonConfimDuplicateType extends AbstractType
|
|||||||
{
|
{
|
||||||
$builder
|
$builder
|
||||||
->add('confirm', CheckboxType::class, [
|
->add('confirm', CheckboxType::class, [
|
||||||
'label' => 'Je confirme la fusion de ces 2 personnes',
|
'label' => 'I confirm the merger of these 2 people',
|
||||||
'mapped' => false,
|
'mapped' => false,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\PersonBundle\Repository;
|
||||||
|
|
||||||
|
use Chill\PersonBundle\Entity\Person;
|
||||||
|
use Chill\PersonBundle\Entity\PersonNotDuplicate;
|
||||||
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class PersonNotDuplicateRepository
|
||||||
|
*
|
||||||
|
* @package Chill\PersonBundle\Repository
|
||||||
|
*/
|
||||||
|
class PersonNotDuplicateRepository extends EntityRepository
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param \Chill\PersonBundle\Entity\Person $person
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function findNotDuplicatePerson(Person $person)
|
||||||
|
{
|
||||||
|
$qb = $this->createQueryBuilder('pnd');
|
||||||
|
$qb->select('pnd')
|
||||||
|
->where('pnd.person1 = :person OR pnd.person2 = :person')
|
||||||
|
;
|
||||||
|
$qb->setParameter('person', $person);
|
||||||
|
$result = $qb->getQuery()->getResult();
|
||||||
|
|
||||||
|
$persons = [];
|
||||||
|
foreach ($result as $row) {
|
||||||
|
if ($row->getPerson1() === $person) {
|
||||||
|
$persons[] = $row->getPerson2();
|
||||||
|
} elseif ($row->getPerson2() === $person) {
|
||||||
|
$persons[] = $row->getPerson1();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $persons;
|
||||||
|
}
|
||||||
|
}
|
@ -6,12 +6,12 @@
|
|||||||
' ' ~ person.lastName }}{% endblock %}
|
' ' ~ person.lastName }}{% endblock %}
|
||||||
|
|
||||||
{% block personcontent %}
|
{% block personcontent %}
|
||||||
<h2>Ancien dossier</h2>
|
<h2>{{ 'Old person'|trans }}</h2>
|
||||||
{{ person2 }}
|
{{ person2 }}
|
||||||
<a class="sc-button bt-show" target="_blank" href="{{ path('chill_person_view', { person_id : person2.id }) }}"></a>
|
<a class="sc-button bt-show" target="_blank" href="{{ path('chill_person_view', { person_id : person2.id }) }}"></a>
|
||||||
|
|
||||||
|
|
||||||
<h2>Nouveau Dossier</h2>
|
<h2>{{ 'New person'|trans }}</h2>
|
||||||
{{ person }}
|
{{ person }}
|
||||||
<a class="sc-button bt-show" target="_blank" href="{{ path('chill_person_view', { person_id : person.id }) }}"></a>
|
<a class="sc-button bt-show" target="_blank" href="{{ path('chill_person_view', { person_id : person.id }) }}"></a>
|
||||||
|
|
||||||
|
@ -8,9 +8,12 @@
|
|||||||
|
|
||||||
{% block personcontent %}
|
{% block personcontent %}
|
||||||
|
|
||||||
<h2>{{ title|default('Person duplicate')|trans }}</h2>
|
|
||||||
|
|
||||||
<table>
|
|
||||||
|
{% if duplicatePersons|length > 0 %}
|
||||||
|
<h2>{{ title|default('Person duplicate')|trans }}</h2>
|
||||||
|
|
||||||
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="chill-red">{% trans %}Name{% endtrans %}</th>
|
<th class="chill-red">{% trans %}Name{% endtrans %}</th>
|
||||||
@ -20,46 +23,104 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
{% for duplicatePerson in duplicatePersons %}
|
{% for duplicatePerson in duplicatePersons %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
{% set is_open = duplicatePerson.isOpen() %}
|
{% set is_open = duplicatePerson.isOpen() %}
|
||||||
<a href="{{ path('chill_person_view', { person_id : duplicatePerson.getId }) }}" {% if chill_person.fields.accompanying_period == 'visible' %}{% if is_open %} alt="{{ 'An accompanying period is open'|trans|e('html_attr') }}"{% else %} alt="{{ 'Any accompanying periods are open'|trans|e('html_attr') }}" {% endif %}{% endif %}>
|
<a href="{{ path('chill_person_view', { person_id : duplicatePerson.getId }) }}" {% if chill_person.fields.accompanying_period == 'visible' %}{% if is_open %} alt="{{ 'An accompanying period is open'|trans|e('html_attr') }}"{% else %} alt="{{ 'Any accompanying periods are open'|trans|e('html_attr') }}" {% endif %}{% endif %}>
|
||||||
{{ duplicatePerson|chill_entity_render_box }}
|
{{ duplicatePerson|chill_entity_render_box }}
|
||||||
{% apply spaceless %}
|
{% apply spaceless %}
|
||||||
{% if chill_person.fields.accompanying_period == 'visible' %}
|
{% if chill_person.fields.accompanying_period == 'visible' %}
|
||||||
{% if is_open == false %}
|
{% if is_open == false %}
|
||||||
<i class="fa fa-lock" ></i>
|
<i class="fa fa-lock" ></i>
|
||||||
{% else %}
|
{% else %}
|
||||||
<i class="fa fa-unlock" ></i>
|
<i class="fa fa-unlock" ></i>
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endapply %}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% if duplicatePerson.birthdate is not null %}
|
||||||
|
{{ duplicatePerson.birthdate|format_date('long') }}
|
||||||
|
{% else %}
|
||||||
|
{{ 'Unknown date of birth'|trans }}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% if duplicatePerson.nationality is not null %}
|
||||||
|
{{ duplicatePerson.nationality.name|localize_translatable_string }}
|
||||||
|
{% else %}
|
||||||
|
{{ 'Without nationality'|trans }}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li><a class="sc-button bt-show" target="_blank" href="{{ path('chill_person_view', { person_id : duplicatePerson.id }) }}"></a></li>
|
||||||
|
<li><a class="sc-button bt-duplicate" href="{{ path('chill_person_duplicate_confirm', { person1_id : person.id, person2_id : duplicatePerson.id }) }}"></a></li>
|
||||||
|
<li><a class="sc-button bt-not-duplicate" href="{{ path('chill_person_duplicate_not_duplicate', {person1_id : person.id, person2_id : duplicatePerson.id}) }}"></a></li>
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% if notDuplicatePersons|length > 0 %}
|
||||||
|
<h2>{{ 'Person flaged as duplicate' | trans }}</h2>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="chill-red">{% trans %}Name{% endtrans %}</th>
|
||||||
|
<th class="chill-green">{% trans %}Date of birth{% endtrans %}</th>
|
||||||
|
<th class="chill-orange">{% trans %}Nationality{% endtrans %}</th>
|
||||||
|
<th> </th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
{% for notDuplicatePerson in notDuplicatePersons %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
{% set is_open = notDuplicatePerson.isOpen() %}
|
||||||
|
<a href="{{ path('chill_person_view', { person_id : notDuplicatePerson.getId }) }}" {% if chill_person.fields.accompanying_period == 'visible' %}{% if is_open %} alt="{{ 'An accompanying period is open'|trans|e('html_attr') }}"{% else %} alt="{{ 'Any accompanying periods are open'|trans|e('html_attr') }}" {% endif %}{% endif %}>
|
||||||
|
{{ notDuplicatePerson|chill_entity_render_box }}
|
||||||
|
{% apply spaceless %}
|
||||||
|
{% if chill_person.fields.accompanying_period == 'visible' %}
|
||||||
|
{% if is_open == false %}
|
||||||
|
<i class="fa fa-lock" ></i>
|
||||||
|
{% else %}
|
||||||
|
<i class="fa fa-unlock" ></i>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endapply %}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% if notDuplicatePerson.birthdate is not null %}
|
||||||
|
{{ notDuplicatePerson.birthdate|format_date('long') }}
|
||||||
|
{% else %}
|
||||||
|
{{ 'Unknown date of birth'|trans }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endapply %}
|
</td>
|
||||||
</a>
|
<td>
|
||||||
</td>
|
{% if notDuplicatePerson.nationality is not null %}
|
||||||
<td>
|
{{ notDuplicatePerson.nationality.name|localize_translatable_string }}
|
||||||
{% if duplicatePerson.birthdate is not null %}
|
{% else %}
|
||||||
{{ duplicatePerson.birthdate|format_date('long') }}
|
{{ 'Without nationality'|trans }}
|
||||||
{% else %}
|
{% endif %}
|
||||||
{{ 'Unknown date of birth'|trans }}
|
</td>
|
||||||
{% endif %}
|
<td>
|
||||||
</td>
|
<ul class="record_actions">
|
||||||
<td>
|
<li><a class="sc-button bt-show" target="_blank" href="{{ path('chill_person_view', { person_id : notDuplicatePerson.id }) }}"></a></li>
|
||||||
{% if duplicatePerson.nationality is not null %}
|
<li><a class="sc-button bt-not-duplicate" href="{{ path('chill_person_remove_duplicate_not_duplicate', {person1_id : person.id, person2_id : notDuplicatePerson.id}) }}"></a></li>
|
||||||
{{ duplicatePerson.nationality.name|localize_translatable_string }}
|
</ul>
|
||||||
{% else %}
|
</td>
|
||||||
{{ 'Without nationality'|trans }}
|
</tr>
|
||||||
{% endif %}
|
{% endfor %}
|
||||||
</td>
|
</table>
|
||||||
<td>
|
{% endif %}
|
||||||
<ul class="record_actions">
|
|
||||||
<li><a class="sc-button bt-show" target="_blank" href="{{ path('chill_person_view', { person_id : duplicatePerson.id }) }}"></a></li>
|
|
||||||
<li><a class="sc-button bt-duplicate" href="{{ path('chill_person_duplicate_confirm', { person_id : person.id, person2_id : duplicatePerson.id }) }}"></a></li>
|
|
||||||
<li><a class="sc-button bt-not-duplicate" href="{{ path('chill_person_duplicate_not_duplicate', {person_id : person.id, person2_id : duplicatePerson.id}) }}"></a></li>
|
|
||||||
</ul>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
namespace Chill\PersonBundle\Search;
|
namespace Chill\PersonBundle\Search;
|
||||||
|
|
||||||
|
use Chill\PersonBundle\Entity\PersonNotDuplicate;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Chill\PersonBundle\Entity\Person;
|
use Chill\PersonBundle\Entity\Person;
|
||||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
|
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
|
||||||
@ -32,6 +33,10 @@ use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
|||||||
*/
|
*/
|
||||||
class SimilarPersonMatcher
|
class SimilarPersonMatcher
|
||||||
{
|
{
|
||||||
|
CONST SIMILAR_SEARCH_ORDER_BY_ALPHABETICAL = 'alphabetical';
|
||||||
|
|
||||||
|
CONST SIMILAR_SEARCH_ORDER_BY_SIMILARITY = 'similarity';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @var EntityManagerInterface
|
* @var EntityManagerInterface
|
||||||
@ -61,32 +66,50 @@ class SimilarPersonMatcher
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function matchPerson(Person $person, $precision = 0.15)
|
public function matchPerson(Person $person, $precision = 0.15, $orderBy = self::SIMILAR_SEARCH_ORDER_BY_SIMILARITY)
|
||||||
{
|
{
|
||||||
$centers = $this->authorizationHelper->getReachableCenters(
|
$centers = $this->authorizationHelper->getReachableCenters(
|
||||||
$this->tokenStorage->getToken()->getUser(),
|
$this->tokenStorage->getToken()->getUser(),
|
||||||
new Role(PersonVoter::SEE)
|
new Role(PersonVoter::SEE)
|
||||||
);
|
);
|
||||||
|
|
||||||
$dql = 'SELECT p from ChillPersonBundle:Person p '
|
$dql = 'SELECT p from ChillPersonBundle:Person p '
|
||||||
. ' WHERE ('
|
. ' WHERE ('
|
||||||
. ' SIMILARITY(p.fullnameCanonical, UNACCENT(LOWER(:fullName))) >= :precision '
|
. ' SIMILARITY(p.fullnameCanonical, UNACCENT(LOWER(:fullName))) >= :precision '
|
||||||
. ' OR SIMILARITY(p.fullnameCanonical, UNACCENT(LOWER(:fullNameInverted))) >= :precision '
|
|
||||||
. ' ) '
|
. ' ) '
|
||||||
. ' AND p.center IN (:centers)'
|
. ' AND p.center IN (:centers)'
|
||||||
. ' AND p.id != :personId'
|
. ' AND p.id != :personId '
|
||||||
. ' ORDER BY SIMILARITY(p.fullnameCanonical, UNACCENT(LOWER(:fullName))) DESC '
|
|
||||||
;
|
;
|
||||||
|
|
||||||
|
$notDuplicatePersons = $this->em->getRepository(PersonNotDuplicate::class)
|
||||||
|
->findNotDuplicatePerson($person);
|
||||||
|
|
||||||
|
if (count($notDuplicatePersons)) {
|
||||||
|
$dql .= ' AND p.id not in (: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 = $this->em
|
$query = $this->em
|
||||||
->createQuery($dql)
|
->createQuery($dql)
|
||||||
->setParameter('fullName', $person->getFirstName() . ' ' . $person->getLastName())
|
->setParameter('fullName', $person->getFirstName() . ' ' . $person->getLastName())
|
||||||
->setParameter('fullNameInverted', $person->getLastName() . ' ' . $person->getFirstName())
|
|
||||||
->setParameter('centers', $centers)
|
->setParameter('centers', $centers)
|
||||||
->setParameter('personId', $person->getId())
|
->setParameter('personId', $person->getId())
|
||||||
->setParameter('precision', $precision)
|
->setParameter('precision', $precision)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
if (count($notDuplicatePersons)) {
|
||||||
|
$query->setParameter('notDuplicatePersons', $notDuplicatePersons);
|
||||||
|
}
|
||||||
|
|
||||||
return $query->getResult();
|
return $query->getResult();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,7 +112,7 @@ chill_person_closingmotive_admin:
|
|||||||
label: 'person_admin.closing motives'
|
label: 'person_admin.closing motives'
|
||||||
|
|
||||||
chill_person_duplicate_confirm:
|
chill_person_duplicate_confirm:
|
||||||
path: /{_locale}/person/{person_id}/duplicate/{person2_id}/confirm
|
path: /{_locale}/person/{person1_id}/duplicate/{person2_id}/confirm
|
||||||
controller: Chill\PersonBundle\Controller\PersonDuplicateController::confirmAction
|
controller: Chill\PersonBundle\Controller\PersonDuplicateController::confirmAction
|
||||||
|
|
||||||
chill_person_maritalstatus_admin:
|
chill_person_maritalstatus_admin:
|
||||||
@ -125,5 +125,9 @@ chill_person_maritalstatus_admin:
|
|||||||
label: 'person_admin.marital status'
|
label: 'person_admin.marital status'
|
||||||
|
|
||||||
chill_person_duplicate_not_duplicate:
|
chill_person_duplicate_not_duplicate:
|
||||||
path: /{_locale}/person/{person_id}/duplicate/{person2_id}/not-duplicate
|
path: /{_locale}/person/{person1_id}/duplicate/{person2_id}/not-duplicate
|
||||||
controller: Chill\PersonBundle\Controller\PersonDuplicateController::notDuplicateAction
|
controller: Chill\PersonBundle\Controller\PersonDuplicateController::notDuplicateAction
|
||||||
|
|
||||||
|
chill_person_remove_duplicate_not_duplicate:
|
||||||
|
path: /{_locale}/person/{person1_id}/duplicate/{person2_id}/remove-not-duplicate
|
||||||
|
controller: Chill\PersonBundle\Controller\PersonDuplicateController::removeNotDuplicateAction
|
||||||
|
@ -28,4 +28,6 @@ services:
|
|||||||
$similarPersonMatcher: '@Chill\PersonBundle\Search\SimilarPersonMatcher'
|
$similarPersonMatcher: '@Chill\PersonBundle\Search\SimilarPersonMatcher'
|
||||||
$translator: '@Symfony\Component\Translation\TranslatorInterface'
|
$translator: '@Symfony\Component\Translation\TranslatorInterface'
|
||||||
$personRepository: '@Chill\PersonBundle\Repository\PersonRepository'
|
$personRepository: '@Chill\PersonBundle\Repository\PersonRepository'
|
||||||
|
$personMove: '@Chill\PersonBundle\Actions\Remove\PersonMove'
|
||||||
|
$eventDispatcher: '@Symfony\Component\EventDispatcher\EventDispatcherInterface'
|
||||||
tags: ['controller.service_arguments']
|
tags: ['controller.service_arguments']
|
||||||
|
@ -67,6 +67,8 @@ Reset: 'Remise à zéro'
|
|||||||
'Closing motive': 'Motif de clôture'
|
'Closing motive': 'Motif de clôture'
|
||||||
'Person details': 'Détails de la personne'
|
'Person details': 'Détails de la personne'
|
||||||
'Person duplicate': 'Find duplicate'
|
'Person duplicate': 'Find duplicate'
|
||||||
|
Old person: Old person
|
||||||
|
New person: New person
|
||||||
|
|
||||||
Create an accompanying period: Create an accompanying period
|
Create an accompanying period: Create an accompanying period
|
||||||
'Create': Create
|
'Create': Create
|
||||||
|
@ -66,6 +66,10 @@ Married: Marié(e)
|
|||||||
'Contact information': 'Informations de contact'
|
'Contact information': 'Informations de contact'
|
||||||
'Administrative information': Administratif
|
'Administrative information': Administratif
|
||||||
File number: Dossier n°
|
File number: Dossier n°
|
||||||
|
Old person: Ancien dossier
|
||||||
|
New person: Nouveau dossier
|
||||||
|
I confirm the merger of these 2 people : Je confime la fusion de ces 2 dossiers
|
||||||
|
Person flaged as duplicate: Dossiers marqués comme faux-positif
|
||||||
|
|
||||||
# addresses part
|
# addresses part
|
||||||
address_street_address_1: Adresse ligne 1
|
address_street_address_1: Adresse ligne 1
|
||||||
|
Loading…
x
Reference in New Issue
Block a user