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 ($membership->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 (null === $participation->getEndDate() || $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 && null === $participation->getEndDate() || $participation->getEndDate() > $membership->getStartDate() && $participation->getStartDate() <= $membership->getStartDate() ) { $participation->setEndDate($membership->getStartDate()); } } } else { // if there are multiple belongings not sharing household, close the others foreach ($person->getHouseholdParticipations() as $participation) { if ($participation === $membership) { continue; } if ($participation->getHousehold() === $this->household && (null === $participation->getEndDate() || $participation->getEndDate() > $membership->getStartDate()) && $participation->getStartDate() <= $membership->getStartDate() ) { if ($participation->getShareHousehold()) { // if a members is moved to the same household than the one he belongs to, // we should make it leave the household $this->leaveMovement($date, $person); } else { $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; } /** * Makes a person leave the household. * * Makes a person leave the household **associated with this editor**. * * @return $this */ public function leaveMovement( \DateTimeImmutable $date, Person $person, ): self { $criteria = new Criteria(); $expr = Criteria::expr(); $criteria->where( $expr->andX( $expr->lte('startDate', $date), $expr->isNull('endDate'), $expr->eq('shareHousehold', true) ) ); $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; } }