mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
216 lines
7.5 KiB
PHP
216 lines
7.5 KiB
PHP
<?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\Household;
|
|
|
|
use Chill\PersonBundle\Entity\Household\Household;
|
|
use Chill\PersonBundle\Entity\Household\HouseholdMember;
|
|
use Chill\PersonBundle\Entity\Household\Position;
|
|
use Chill\PersonBundle\Entity\Person;
|
|
use Chill\PersonBundle\Event\Person\PersonAddressMoveEvent;
|
|
use DateTimeImmutable;
|
|
use Doctrine\Common\Collections\Criteria;
|
|
use LogicException;
|
|
use Symfony\Component\Validator\ConstraintViolationList;
|
|
use Symfony\Component\Validator\ConstraintViolationListInterface;
|
|
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
|
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
|
use function in_array;
|
|
use function spl_object_hash;
|
|
|
|
class MembersEditor
|
|
{
|
|
public const VALIDATION_GROUP_AFFECTED = 'household_memberships';
|
|
|
|
public const VALIDATION_GROUP_COMPOSITION = 'household_composition';
|
|
|
|
public const VALIDATION_GROUP_CREATED = 'household_memberships_created';
|
|
|
|
private EventDispatcherInterface $eventDispatcher;
|
|
|
|
private array $events = [];
|
|
|
|
private ?Household $household = null;
|
|
|
|
private array $membershipsAffected = [];
|
|
|
|
private array $oldMembershipsHashes = [];
|
|
|
|
private array $persistables = [];
|
|
|
|
private ValidatorInterface $validator;
|
|
|
|
public function __construct(ValidatorInterface $validator, ?Household $household, EventDispatcherInterface $eventDispatcher)
|
|
{
|
|
$this->validator = $validator;
|
|
$this->household = $household;
|
|
$this->eventDispatcher = $eventDispatcher;
|
|
}
|
|
|
|
public function addMovement(DateTimeImmutable $date, Person $person, ?Position $position, ?bool $holder = false, ?string $comment = null): self
|
|
{
|
|
if (null === $this->household) {
|
|
throw new LogicException('You must define a household first');
|
|
}
|
|
|
|
$membership = (new HouseholdMember())
|
|
->setStartDate($date)
|
|
->setPerson($person)
|
|
->setPosition($position)
|
|
->setHolder($holder)
|
|
->setComment($comment);
|
|
$this->household->addMember($membership);
|
|
|
|
if (null !== $position) {
|
|
if ($position->getShareHousehold()) {
|
|
// launch event only if moving to a "share household" position,
|
|
// and if the destination household is different than the previous one
|
|
$event = new PersonAddressMoveEvent($person);
|
|
$event->setNextMembership($membership);
|
|
|
|
$counter = 0;
|
|
|
|
foreach ($person->getHouseholdParticipationsShareHousehold() as $participation) {
|
|
if ($participation === $membership) {
|
|
continue;
|
|
}
|
|
|
|
if ($participation->getStartDate() > $membership->getStartDate()) {
|
|
continue;
|
|
}
|
|
|
|
++$counter;
|
|
|
|
if ($participation->getEndDate() === null || $participation->getEndDate() > $date) {
|
|
$participation->setEndDate($date);
|
|
$this->membershipsAffected[] = $participation;
|
|
$this->oldMembershipsHashes[] = spl_object_hash($participation);
|
|
|
|
if ($participation->getHousehold() !== $this->household) {
|
|
$event->setPreviousMembership($participation);
|
|
$this->events[] = $event;
|
|
}
|
|
}
|
|
}
|
|
|
|
// send also the event if there was no participation before
|
|
if (0 === $counter) {
|
|
$this->events[] = $event;
|
|
}
|
|
|
|
foreach ($person->getHouseholdParticipationsNotShareHousehold() as $participation) {
|
|
if ($participation->getHousehold() === $this->household
|
|
&& $participation->getEndDate() === null || $participation->getEndDate() > $membership->getStartDate()
|
|
&& $participation->getStartDate() <= $membership->getStartDate()
|
|
) {
|
|
$participation->setEndDate($membership->getStartDate());
|
|
}
|
|
}
|
|
} else {
|
|
// if a members is moved to the same household than the one he belongs to,
|
|
// we should make it leave the household
|
|
if ($person->getCurrentHousehold($date) === $this->household) {
|
|
$this->leaveMovement($date, $person);
|
|
}
|
|
|
|
// if there are multiple belongings not sharing household, close the others
|
|
foreach ($person->getHouseholdParticipationsNotShareHousehold() as $participation) {
|
|
if ($participation === $membership) {
|
|
continue;
|
|
}
|
|
|
|
if ($participation->getHousehold() === $this->household
|
|
&& ($participation->getEndDate() === null || $participation->getEndDate() > $membership->getStartDate())
|
|
&& $participation->getStartDate() <= $membership->getStartDate()
|
|
) {
|
|
$participation->setEndDate($membership->getStartDate());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$this->membershipsAffected[] = $membership;
|
|
$this->persistables[] = $membership;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getHousehold(): ?Household
|
|
{
|
|
return $this->household;
|
|
}
|
|
|
|
public function getPersistable(): array
|
|
{
|
|
return $this->persistables;
|
|
}
|
|
|
|
public function hasHousehold(): bool
|
|
{
|
|
return null !== $this->household;
|
|
}
|
|
|
|
public function leaveMovement(
|
|
DateTimeImmutable $date,
|
|
Person $person
|
|
): self {
|
|
$criteria = new Criteria();
|
|
$expr = Criteria::expr();
|
|
|
|
$criteria->where(
|
|
$expr->andX(
|
|
$expr->lt('startDate', $date),
|
|
$expr->isNull('endDate')
|
|
)
|
|
);
|
|
|
|
$participations = $person->getHouseholdParticipations()
|
|
->matching($criteria);
|
|
|
|
foreach ($participations as $participation) {
|
|
$this->events[] = $event = new PersonAddressMoveEvent($person);
|
|
$event->setPreviousMembership($participation);
|
|
$participation->setEndDate($date);
|
|
$this->membershipsAffected[] = $participation;
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function postMove(): void
|
|
{
|
|
foreach ($this->events as $event) {
|
|
$this->eventDispatcher->dispatch($event);
|
|
}
|
|
}
|
|
|
|
public function validate(): ConstraintViolationListInterface
|
|
{
|
|
if ($this->hasHousehold()) {
|
|
$list = $this->validator
|
|
->validate($this->getHousehold(), null, [self::VALIDATION_GROUP_AFFECTED, self::VALIDATION_GROUP_COMPOSITION]);
|
|
} else {
|
|
$list = new ConstraintViolationList();
|
|
}
|
|
|
|
foreach ($this->membershipsAffected as $m) {
|
|
if (in_array(spl_object_hash($m), $this->oldMembershipsHashes, true)) {
|
|
$list->addAll($this->validator->validate($m, null, [self::VALIDATION_GROUP_AFFECTED]));
|
|
} else {
|
|
$list->addAll($this->validator->validate($m, null, [self::VALIDATION_GROUP_CREATED,
|
|
self::VALIDATION_GROUP_AFFECTED, ]));
|
|
}
|
|
}
|
|
|
|
return $list;
|
|
}
|
|
}
|