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; } }