Merge branch '38-gestion-doublon' into 'master'

fix the doublons module

Closes #38

See merge request Chill-Projet/chill-bundles!577
This commit is contained in:
LenaertsJ 2023-09-14 14:08:51 +00:00
commit 0e47a1cf59
17 changed files with 673 additions and 47 deletions

View File

@ -0,0 +1,5 @@
kind: Fixed
body: reinstate the fusion of duplicate persons
time: 2023-07-12T11:12:06.673925762+02:00
custom:
Issue: "107"

View File

@ -0,0 +1,5 @@
kind: Fixed
body: Fix gestion doublon functionality to work with chill bundles v2
time: 2023-09-14T11:54:51.09060399+02:00
custom:
Issue: "107"

View File

@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
/*
* 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.
*/
namespace Chill\PersonBundle\Actions\Remove\Handler;
use Chill\PersonBundle\Actions\Remove\PersonMoveSqlHandlerInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
use Chill\PersonBundle\Entity\Person;
class PersonMoveAccompanyingPeriodParticipationHandler implements PersonMoveSqlHandlerInterface
{
public function supports(string $className, string $field): bool
{
return $className === AccompanyingPeriodParticipation::class;
}
public function getSqls(string $className, string $field, Person $from, Person $to): array
{
$insertSql = sprintf(<<<'SQL'
INSERT INTO chill_person_accompanying_period_participation (person_id, accompanyingperiod_id, id, startdate, enddate)
SELECT %d, accompanyingperiod_id, nextval('chill_person_accompanying_period_id_seq'), startdate, enddate
FROM chill_person_accompanying_period_participation cpapp
WHERE person_id = %d
AND NOT EXISTS (
SELECT 1 FROM chill_person_accompanying_period_participation cpapp2
WHERE
person_id = %d
AND (cpapp.startdate, COALESCE(cpapp.enddate, 'infinity'::date)) OVERLAPS (cpapp2.startdate, COALESCE(cpapp2.enddate, 'infinity'::date))
);
SQL, $to->getId(), $from->getId(), $to->getId());
$deleteSql = sprintf(<<<'SQL'
DELETE FROM chill_person_accompanying_period_participation WHERE person_id = %d;
SQL, $from->getId());
return [$insertSql, $deleteSql];
}
}

View File

@ -0,0 +1,73 @@
<?php
declare(strict_types=1);
/*
* 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.
*/
namespace Chill\PersonBundle\Actions\Remove\Handler;
use Chill\PersonBundle\Actions\Remove\PersonMoveSqlHandlerInterface;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Repository\Person\PersonCenterHistoryRepository;
class PersonMoveCenterHistoryHandler implements PersonMoveSqlHandlerInterface
{
public function __construct(
private PersonCenterHistoryRepository $centerHistoryRepository,
) {}
public function supports(string $className, string $field): bool
{
return $className === Person\PersonCenterHistory::class;
}
public function getSqls(string $className, string $field, Person $from, Person $to): array
{
$sqlStatements = [];
$oldestDateA = null;
$oldestDateB = null;
$oldestCenterHistoryB = null;
$oldestCenterHistoryA = null;
$centerHistoriesA = $this->centerHistoryRepository->findBy(['person' => $from]);
foreach ($centerHistoriesA as $ch) {
if ($oldestDateA === null || ($ch->getStartDate() < $oldestDateA)) {
$oldestDateA = $ch->getStartDate();
$oldestCenterHistoryA = $ch;
}
}
$centerHistoriesB = $this->centerHistoryRepository->findBy(['person' => $to]);
foreach ($centerHistoriesB as $ch) {
if ($oldestDateB === null || ($ch->getStartDate() < $oldestDateB)) {
$oldestDateB = $ch->getStartDate();
$oldestCenterHistoryB = $ch;
}
}
$sqlDelete = sprintf(<<<'SQL'
DELETE FROM chill_person_person_center_history WHERE person_id = %d;
SQL, $from->getId());
$sqlStatements = [$sqlDelete];
if ((null !== $oldestDateA && null !== $oldestDateB) && $oldestDateA <= $oldestDateB) {
$sqlInsert = sprintf(<<<'SQL'
UPDATE chill_person_person_center_history SET startDate = '%s' WHERE id = %d;
SQL, $oldestDateA->format('Y-m-d'), $oldestCenterHistoryB->getId());
$sqlStatements = [$sqlInsert, $sqlDelete];
}
return $sqlStatements;
}
}

View File

@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
/*
* 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.
*/
namespace Chill\PersonBundle\Actions\Remove\Handler;
use Chill\PersonBundle\Actions\Remove\PersonMoveSqlHandlerInterface;
use Chill\PersonBundle\Entity\Household\HouseholdMember;
use Chill\PersonBundle\Entity\Person;
class PersonMoveHouseholdHandler implements PersonMoveSqlHandlerInterface
{
public function supports(string $className, string $field): bool
{
return $className === HouseholdMember::class;
}
public function getSqls(string $className, string $field, Person $from, Person $to): array
{
$sqlInsert = sprintf(<<<'SQL'
INSERT INTO chill_person_household_members (id, person_id, household_id, startdate, enddate, comment, sharedhousehold, position_id, holder)
SELECT nextval('chill_person_household_members_id_seq'), %d, household_id, startdate, enddate, comment, sharedhousehold, position_id, holder
FROM chill_person_household_members cphm
WHERE person_id = %d
AND NOT EXISTS (
SELECT 1 FROM chill_person_household_members cphm_inner
WHERE
person_id = %d
AND daterange(cphm.startdate, cphm.enddate) && daterange(cphm_inner.startdate, cphm_inner.enddate)
);
SQL, $to->getId(), $from->getId(), $to->getId());
$deleteSql = sprintf(<<<'SQL'
DELETE FROM chill_person_household_members WHERE person_id = %d;
SQL, $from->getId());
return [$sqlInsert, $deleteSql];
}
}

View File

@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
/*
* 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.
*/
namespace Chill\PersonBundle\Actions\Remove\Handler;
use Chill\PersonBundle\Actions\Remove\PersonMoveSqlHandlerInterface;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Entity\Relationships\Relationship;
class PersonMoveRelationHandler implements PersonMoveSqlHandlerInterface
{
public function supports(string $className, string $field): bool
{
return $className === Relationship::class;
}
public function getSqls(string $className, string $field, Person $from, Person $to): array
{
$insertSql = sprintf(<<<'SQL'
INSERT INTO chill_person_relationships (id, relation_id, reverse, fromperson_id, toperson_id)
SELECT nextval('chill_person_relationships_id_seq'), relation_id, reverse, fromperson_id, toperson_id
FROM chill_person_relationships cpr
WHERE fromperson_id = %d OR toperson_id = %d
AND NOT EXISTS (
SELECT 1 FROM chill_person_relationships cpr2
WHERE
cpr2.fromperson_id = %d AND cpr2.toperson_id = %d
OR cpr2.fromperson_id = %d AND cpr2.toperson_id = %d
);
SQL, $from->getId(), $from->getId(), $to->getId(), $from->getId(), $from->getId(), $to->getId());
$deleteSql = [
sprintf("DELETE FROM chill_person_relationships WHERE fromperson_id = %d", $from->getId()),
sprintf("DELETE FROM chill_person_relationships WHERE toperson_id = %d", $from->getId())
];
return [$insertSql, ...$deleteSql];
}
}

View File

@ -35,23 +35,11 @@ use function in_array;
*/
class PersonMove
{
/**
* @var EntityManagerInterface
*/
protected $em;
/**
* @var EventDispatcherInterface
*/
protected $eventDispatcher;
public function __construct(
EntityManagerInterface $em,
EventDispatcherInterface $eventDispatcher
) {
$this->em = $em;
$this->eventDispatcher = $eventDispatcher;
}
private EntityManagerInterface $em,
private PersonMoveManager $personMoveManager,
private EventDispatcherInterface $eventDispatcher
) {}
/**
* Return the sql used to move or delete entities associated to a person to
@ -88,9 +76,16 @@ class PersonMove
}
foreach ($metadata->getAssociationMappings() as $field => $mapping) {
if ($this->personMoveManager->hasHandler($metadata->getName(), $field)) {
$sqls = array_merge($sqls, $this->personMoveManager->getSqls($metadata->getName(), $field, $from, $to));
continue;
}
if (in_array($mapping['sourceEntity'], $this->getIgnoredEntities(), true)) {
continue;
}
if (Person::class === $mapping['targetEntity'] and true === $mapping['isOwningSide']) {
if (in_array($mapping['sourceEntity'], $toDelete, true)) {
$sql = $this->createDeleteSQL($metadata, $from, $field);
@ -101,25 +96,17 @@ class PersonMove
['to' => $to->getId(), 'original_action' => 'move']
);
$this->eventDispatcher->dispatch(ActionEvent::DELETE, $event);
$sqls = array_merge($sqls, $event->getPreSql(), [$event->getSqlStatement()], $event->getPostSql());
} else {
$sql = $this->createMoveSQL($metadata, $from, $to, $field);
$event = new ActionEvent(
$from->getId(),
$metadata->getName(),
$sql,
['to' => $to->getId(), 'original_action' => 'move']
);
$this->eventDispatcher->dispatch(ActionEvent::MOVE, $event);
$sqls = array_merge($sqls, $this->createMoveSQLs($metadata, $from, $to, $field));
}
$sqls = array_merge($sqls, $event->getPreSql(), [$event->getSqlStatement()], $event->getPostSql());
}
}
}
$personMetadata = $this->em->getClassMetadata(Person::class);
$sqls[] = sprintf(
'DELETE FROM %s WHERE id = %d',
'DELETE FROM %s WHERE id = %d;',
$this->getTableName($personMetadata),
$from->getId()
);
@ -133,18 +120,24 @@ class PersonMove
$conditions = [];
foreach ($mapping['joinColumns'] as $columns) {
$conditions[] = sprintf('%s = %d', $columns['name'], $from->getId());
if (array_key_exists('joinTable', $mapping)) {
foreach ($mapping['joinTable']['joinColumns'] as $columns) {
$conditions[] = sprintf('%s = %d', $columns['referencedColumnName'], $from->getId());
}
} elseif (array_key_exists('joinColumns', $mapping)) {
foreach ($mapping['joinColumns'] as $columns) {
$conditions[] = sprintf('%s = %d', $columns['name'], $from->getId());
}
}
return sprintf(
'DELETE FROM %s WHERE %s',
'DELETE FROM %s WHERE %s;',
$this->getTableName($metadata),
implode(' AND ', $conditions)
);
}
private function createMoveSQL(ClassMetadata $metadata, Person $from, Person $to, $field): string
private function createMoveSQLs($metadata, Person $from, Person $to, $field): array
{
$mapping = $metadata->getAssociationMapping($field);
@ -154,9 +147,29 @@ class PersonMove
$tableName = '';
if (array_key_exists('joinTable', $mapping)) {
// there is a join_table: we have to find conflict
$tableName = (null !== ($mapping['joinTable']['schema'] ?? null) ? $mapping['joinTable']['schema'] . '.' : '')
. $mapping['joinTable']['name'];
$sqlInsert = sprintf(
"INSERT INTO %s (%s, %s) SELECT %d, %s FROM %s WHERE %s = %d ON CONFLICT DO NOTHING;",
$tableName,
$mapping['joinTable']['inverseJoinColumns'][0]['name'], // person_id
$mapping['joinTable']['joinColumns'][0]['name'], // something_else_id
$to->getId(),
$mapping['joinTable']['joinColumns'][0]['name'], // something_else_id
$tableName,
$mapping['joinTable']['inverseJoinColumns'][0]['name'], // person_id
$from->getId()
);
$deleteSql = sprintf(
"DELETE FROM %s WHERE %s = %d;",
$tableName,
$mapping['joinTable']['inverseJoinColumns'][0]['name'], // person_id
$from->getId()
);
foreach ($mapping['joinTable']['inverseJoinColumns'] as $columns) {
$sets[] = sprintf('%s = %d', $columns['name'], $to->getId());
}
@ -164,24 +177,29 @@ class PersonMove
foreach ($mapping['joinTable']['inverseJoinColumns'] as $columns) {
$conditions[] = sprintf('%s = %d', $columns['name'], $from->getId());
}
} elseif (array_key_exists('joinColumns', $mapping)) {
return [
$sqlInsert, $deleteSql
];
}
if (array_key_exists('joinColumns', $mapping)) {
$tableName = $this->getTableName($metadata);
foreach ($mapping['joinColumns'] as $columns) {
$sets[] = sprintf('%s = %d', $columns['name'], $to->getId());
}
foreach ($mapping['joinColumns'] as $columns) {
$conditions[] = sprintf('%s = %d', $columns['name'], $from->getId());
}
}
return sprintf(
'UPDATE %s SET %s WHERE %s',
return [sprintf(
'UPDATE %s SET %s WHERE %s;',
$tableName,
implode(' ', $sets),
implode(' AND ', $conditions)
);
)];
}
/**
@ -191,9 +209,6 @@ class PersonMove
private function getDeleteEntities(): array
{
return [
Person\PersonCenterHistory::class,
HouseholdMember::class,
AccompanyingPeriodParticipation::class,
AccompanyingPeriod\AccompanyingPeriodWork::class,
Relationship::class
];

View File

@ -0,0 +1,55 @@
<?php
declare(strict_types=1);
/*
* 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.
*/
namespace Chill\PersonBundle\Actions\Remove;
use Chill\PersonBundle\Entity\Person;
class PersonMoveManager
{
public function __construct(
/**
* @var iterable<PersonMoveSqlHandlerInterface>
*/
private iterable $handlers,
) {}
/**
* @param class-string $className
* @param string $field
* @return bool
*/
public function hasHandler(string $className, string $field): bool
{
foreach ($this->handlers as $handler) {
if ($handler->supports($className, $field)) {
return true;
}
}
return false;
}
/**
* @param class-string $className
* @return array<string>
*/
public function getSqls(string $className, string $field, Person $from, Person $to): array
{
foreach ($this->handlers as $handler) {
if ($handler->supports($className, $field)) {
return $handler->getSqls($className, $field, $from, $to);
}
}
return [];
}
}

View File

@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
/*
* 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.
*/
namespace Chill\PersonBundle\Actions\Remove;
use Chill\PersonBundle\Entity\Person;
interface PersonMoveSqlHandlerInterface
{
/**
* @param class-string $className
*/
public function supports(string $className, string $field): bool;
/**
* @param class-string $className
* @return array<string>
*/
public function getSqls(string $className, string $field, Person $from, Person $to): array;
}

View File

@ -11,6 +11,7 @@ declare(strict_types=1);
namespace Chill\PersonBundle;
use Chill\PersonBundle\Actions\Remove\PersonMoveSqlHandlerInterface;
use Chill\PersonBundle\DependencyInjection\CompilerPass\AccompanyingPeriodTimelineCompilerPass;
use Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoUnionQueryPartInterface;
use Chill\PersonBundle\Widget\PersonListWidgetFactory;
@ -29,5 +30,7 @@ class ChillPersonBundle extends Bundle
$container->addCompilerPass(new AccompanyingPeriodTimelineCompilerPass());
$container->registerForAutoconfiguration(AccompanyingPeriodInfoUnionQueryPartInterface::class)
->addTag('chill_person.accompanying_period_info_part');
$container->registerForAutoconfiguration(PersonMoveSqlHandlerInterface::class)
->addTag('chill_person.person_move_handler');
}
}

View File

@ -120,6 +120,7 @@ class PersonDuplicateController extends Controller
$connection->beginTransaction();
foreach ($sqls as $sql) {
dump($sql);
$connection->executeQuery($sql);
}
$connection->commit();

View File

@ -203,6 +203,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
/**
* @ORM\OneToMany(targetEntity=PersonCenterHistory::class, mappedBy="person", cascade={"persist"})
* @ORM\OrderBy({"startDate": "ASC", "id": "ASC"})
*
* @var Collection|PersonCenterHistory[]
*/
@ -1606,6 +1607,15 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
return $this;
}
public function addCenterHistory(PersonCenterHistory $newCenterHistory): self
{
if (!$this->centerHistory->contains($newCenterHistory)) {
$this->centerHistory[] = $newCenterHistory;
$newCenterHistory->setPerson($this);
}
return $this;
}
/**
* @return Person
*/

View File

@ -11,7 +11,7 @@ declare(strict_types=1);
namespace Chill\PersonBundle\Form;
use Chill\PersonBundle\Form\Type\PickPersonType;
use Chill\PersonBundle\Form\Type\PickPersonDynamicType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\FormBuilderInterface;
@ -21,7 +21,7 @@ class PersonFindManuallyDuplicateType extends AbstractType
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('person', PickPersonType::class, [
->add('person', PickPersonDynamicType::class, [
'label' => 'Find duplicate',
'mapped' => false,
])

View File

@ -4,7 +4,7 @@
<li><b>{{ 'gender'|trans }}</b>:
{{ person.gender|trans }}</li>
<li><b>{{ 'maritalStatus'|trans }}</b>:
{% if person.maritalStatus.name %}{{ person.maritalStatus.name|localize_translatable_string }}{% endif %}</li>
{% if person.maritalStatus %}{{ person.maritalStatus.name|localize_translatable_string }}{% endif %}</li>
<li><b>{{ 'birthdate'|trans }}</b>:
{% if person.birthdate is not null %}{{ person.birthdate|format_date('short') }}{% endif %}</li>
<li><b>{{ 'placeOfBirth'|trans }}</b>:

View File

@ -8,9 +8,9 @@
{% block content %}
<div class="person-duplicate">
<h1>{{ 'Désigner un dossier doublon'|trans }}</h1>
{{ form_start(form) }}
{{ form_rest(form) }}
@ -29,3 +29,11 @@
</div>
{% endblock %}
{% block js %}
{{ encore_entry_script_tags('mod_pickentity_type') }}
{% endblock %}
{% block css %}
{{ encore_entry_link_tags('mod_pickentity_type') }}
{% endblock %}

View File

@ -0,0 +1,275 @@
<?php
declare(strict_types=1);
/*
* 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.
*/
namespace Action\Remove;
use Chill\ActivityBundle\Entity\Activity;
use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Repository\CenterRepositoryInterface;
use Chill\PersonBundle\Actions\Remove\PersonMove;
use Chill\PersonBundle\Actions\Remove\PersonMoveManager;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
use Chill\PersonBundle\Entity\Household\Household;
use Chill\PersonBundle\Entity\Household\HouseholdMember;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Entity\Relationships\Relation;
use Chill\PersonBundle\Entity\Relationships\Relationship;
use Chill\PersonBundle\Repository\PersonRepository;
use Doctrine\DBAL\Connection;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/**
* @internal
* @coversNothing
*/
class PersonMoveTest extends KernelTestCase
{
private EntityManagerInterface $em;
private PersonMoveManager $personMoveManager;
private EventDispatcherInterface $eventDispatcher;
private CenterRepositoryInterface $centerRepository;
/**
* @var list<array{0: class-string, 1: int}>
*/
private static $entitiesToDelete = [];
public function setUp(): void
{
self::bootKernel();
$this->em = self::$container->get(EntityManagerInterface::class);
$this->personMoveManager = self::$container->get(PersonMoveManager::class);
$this->eventDispatcher = self::$container->get(EventDispatcherInterface::class);
$this->centerRepository = self::$container->get(CenterRepositoryInterface::class);
}
public static function tearDownAfterClass(): void
{
self::bootKernel();
$em = self::$container->get(EntityManagerInterface::class);
foreach (self::$entitiesToDelete as [$class, $id]) {
$entity = $em->find($class, $id);
if (null !== $entity) {
$em->remove($entity);
}
}
$em->flush();
}
/**
* @dataProvider dataProviderMovePerson
*/
public function testMovePersonSimple(Person $personA, Person $personB, string $message): void
{
$move = new PersonMove($this->em, $this->personMoveManager, $this->eventDispatcher);
$sqls = $move->getSQL($personA, $personB);
$this->em->getConnection()->transactional(function (Connection $conn) use ($personA, $personB, $sqls) {
foreach ($sqls as $sql) {
$conn->executeStatement($sql);
}
});
$personsByIdOfA = $this->em->createQuery("SELECT p FROM " . Person::class . " p WHERE p.id = :id")
->setParameter('id', $personA->getId())
->getResult();
$personB = $this->em->find(Person::class, $personB->getId());
self::assertCount(0, $personsByIdOfA);
self::assertNotNull($personB?->getId(), $message);
}
public function testMovePersonCenterHistory(): void
{
$personA = new Person();
$personB = new Person();
[$centerA, $centerB] = $this->centerRepository->findAll();
$this->em->persist($personA);
$this->em->persist($personB);
$personCenterHistoryAFirst = (new Person\PersonCenterHistory())->setCenter($centerA)
->setStartDate(new \DateTimeImmutable('2023-01-01'))
->setEndDate(new \DateTimeImmutable('2023-06-30'));
$personCenterHistoryASecond = (new Person\PersonCenterHistory())->setCenter($centerB)
->setStartDate(new \DateTimeImmutable('2023-06-30'))
->setEndDate(new \DateTimeImmutable('2023-09-30'));
$personCenterHistoryBFirst = (new Person\PersonCenterHistory())->setCenter($centerA)
->setStartDate(new \DateTimeImmutable('2023-03-01'))
->setEndDate(new \DateTimeImmutable('2023-07-15'));
$personCenterHistoryBSecond = (new Person\PersonCenterHistory())->setCenter($centerB)
->setStartDate(new \DateTimeImmutable('2023-07-15'))
->setEndDate(new \DateTimeImmutable('2023-09-30'));
$this->em->persist($personCenterHistoryAFirst);
$this->em->persist($personCenterHistoryASecond);
$this->em->persist($personCenterHistoryBFirst);
$this->em->persist($personCenterHistoryBSecond);
$personA->addCenterHistory($personCenterHistoryAFirst);
$personA->addCenterHistory($personCenterHistoryASecond);
$personB->addCenterHistory($personCenterHistoryBFirst);
$personB->addCenterHistory($personCenterHistoryBSecond);
$this->em->flush();
$this->em->clear();
$move = new PersonMove($this->em, $this->personMoveManager, $this->eventDispatcher);
$sqls = $move->getSQL($personA, $personB);
$this->em->getConnection()->transactional(function (Connection $conn) use ($personA, $personB, $sqls) {
foreach ($sqls as $sql) {
$conn->executeStatement($sql);
}
});
$personsByIdOfA = $this->em->createQuery("SELECT p FROM " . Person::class . " p WHERE p.id = :id")
->setParameter('id', $personA->getId())
->getResult();
/** @var Person $personB */
$personB = $this->em->find(Person::class, $personB->getId());
$message = 'Move persons with overlapping center histories';
$this->em->refresh($personB);
self::assertCount(0, $personsByIdOfA);
self::assertNotNull($personB?->getId(), $message);
$centerHistoriesB = $personB->getCenterHistory();
$oldestDate = new \DateTimeImmutable('2023-01-01');
$this->em->refresh($centerHistoriesB->first());
self::assertCount(2, $centerHistoriesB);
self::assertEquals($oldestDate, $centerHistoriesB->first()->getStartDate());
self::$entitiesToDelete[] = [Person::class, $personA];
self::$entitiesToDelete[] = [Person::class, $personB];
self::$entitiesToDelete[] = [Person\PersonCenterHistory::class, $personCenterHistoryAFirst];
self::$entitiesToDelete[] = [Person\PersonCenterHistory::class, $personCenterHistoryASecond];
self::$entitiesToDelete[] = [Person\PersonCenterHistory::class, $personCenterHistoryBFirst];
self::$entitiesToDelete[] = [Person\PersonCenterHistory::class, $personCenterHistoryBSecond];
}
public function dataProviderMovePerson(): iterable
{
$this->setUp();
$personA = new Person();
$personB = new Person();
$this->em->persist($personA);
$this->em->persist($personB);
self::$entitiesToDelete[] = [Person::class, $personA];
self::$entitiesToDelete[] = [Person::class, $personB];
yield [$personA, $personB, "move 2 people without any associated data"];
$personA = new Person();
$personB = new Person();
$activity = new Activity();
$activity->setDate(new \DateTime('today'));
$activity->addPerson($personA);
$activity->addPerson($personB);
$this->em->persist($personA);
$this->em->persist($personB);
$this->em->persist($activity);
self::$entitiesToDelete[] = [Person::class, $personA];
self::$entitiesToDelete[] = [Person::class, $personB];
self::$entitiesToDelete[] = [Activity::class, $activity];
yield [$personA, $personB, "move 2 people having an activity"];
$personA = new Person();
$personB = new Person();
$household = new Household();
$household->addMember(
$memberA = (new HouseholdMember())->setPerson($personA)->setShareHousehold(true)
->setStartDate(new \DateTimeImmutable('2023-01-01'))
);
$household->addMember(
$memberB = (new HouseholdMember())->setPerson($personB)->setShareHousehold(true)
->setStartDate(new \DateTimeImmutable('2023-01-01'))
);
$this->em->persist($personA);
$this->em->persist($personB);
$this->em->persist($household);
$this->em->persist($memberA);
$this->em->persist($memberB);
self::$entitiesToDelete[] = [Person::class, $personA];
self::$entitiesToDelete[] = [Person::class, $personB];
self::$entitiesToDelete[] = [HouseholdMember::class, $memberA];
self::$entitiesToDelete[] = [HouseholdMember::class, $memberB];
self::$entitiesToDelete[] = [Household::class, $household];
yield [$personA, $personB, "move 2 people having the same household at the same time"];
$personA = new Person();
$personB = new Person();
$parcours = new AccompanyingPeriod();
$parcours->addPerson($personA);
$parcours->addPerson($personB);
$this->em->persist($personA);
$this->em->persist($personB);
$this->em->persist($parcours);
self::$entitiesToDelete[] = [Person::class, $personA];
self::$entitiesToDelete[] = [Person::class, $personB];
self::$entitiesToDelete[] = [AccompanyingPeriod::class, $parcours];
yield [$personA, $personB, "move 2 people participating to the same parcours"];
$personA = new Person();
$personB = new Person();
$relationship = new Relationship();
$relation = new Relation();
$user = (new User())->setUsername(uniqid())->setEmail(uniqid() . '@foo.com');
$relationship->setRelation($relation);
$relationship->setToPerson($personA);
$relationship->setFromPerson($personB);
$relationship->setReverse(false);
$relationship->setCreatedBy($user);
$this->em->persist($personA);
$this->em->persist($personB);
$this->em->persist($relation);
$this->em->persist($user);
$this->em->persist($relationship);
self::$entitiesToDelete[] = [Person::class, $personA];
self::$entitiesToDelete[] = [Person::class, $personB];
self::$entitiesToDelete[] = [Relation::class, $relation];
self::$entitiesToDelete[] = [User::class, $user];
self::$entitiesToDelete[] = [Relationship::class, $relationship];
yield [$personA, $personB, "move 2 people with a relationship"];
$this->em->flush();
$this->em->clear();
}
}

View File

@ -1,5 +1,13 @@
services:
Chill\PersonBundle\Actions\Remove\PersonMove:
_defaults:
autowire: true
autoconfigure: true
Chill\PersonBundle\Actions\Remove\PersonMove: ~
Chill\PersonBundle\Actions\Remove\PersonMoveManager:
arguments:
$em: '@Doctrine\ORM\EntityManagerInterface'
$eventDispatcher: '@Symfony\Component\EventDispatcher\EventDispatcherInterface'
$handlers: !tagged_iterator chill_person.person_move_handler
Chill\PersonBundle\Actions\Remove\Handler\:
resource: '../../Actions/Remove/Handler'