mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
1711 lines
48 KiB
PHP
1711 lines
48 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\Entity;
|
|
|
|
use Chill\BudgetBundle\Entity\Charge;
|
|
use Chill\BudgetBundle\Entity\Resource;
|
|
use Chill\CalendarBundle\Entity\Calendar;
|
|
use Chill\MainBundle\Doctrine\Model\TrackCreationInterface;
|
|
use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
|
|
use Chill\MainBundle\Entity\Address;
|
|
use Chill\MainBundle\Entity\Center;
|
|
use Chill\MainBundle\Entity\Civility;
|
|
use Chill\MainBundle\Entity\Country;
|
|
use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable;
|
|
use Chill\MainBundle\Entity\Gender;
|
|
use Chill\MainBundle\Entity\HasCenterInterface;
|
|
use Chill\MainBundle\Entity\Language;
|
|
use Chill\MainBundle\Entity\User;
|
|
use Chill\MainBundle\Entity\Workflow\EntityWorkflowSignatureStateEnum;
|
|
use Chill\MainBundle\Entity\Workflow\EntityWorkflowStepSignature;
|
|
use Chill\MainBundle\Validation\Constraint\PhonenumberConstraint;
|
|
use Chill\PersonBundle\Entity\Household\Household;
|
|
use Chill\PersonBundle\Entity\Household\HouseholdMember;
|
|
use Chill\PersonBundle\Entity\Household\PersonHouseholdAddress;
|
|
use Chill\PersonBundle\Entity\Person\PersonCenterCurrent;
|
|
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
|
|
use Chill\PersonBundle\Entity\Person\PersonCurrentAddress;
|
|
use Chill\PersonBundle\Entity\Person\PersonResource;
|
|
use Chill\PersonBundle\Validator\Constraints\Household\HouseholdMembershipSequential;
|
|
use Chill\PersonBundle\Validator\Constraints\Person\Birthdate;
|
|
use Chill\PersonBundle\Validator\Constraints\Person\PersonHasCenter;
|
|
use DateTime;
|
|
use Doctrine\Common\Collections\ArrayCollection;
|
|
use Doctrine\Common\Collections\Collection;
|
|
use Doctrine\Common\Collections\Criteria;
|
|
use Doctrine\Common\Collections\ReadableCollection;
|
|
use Doctrine\Common\Collections\Selectable;
|
|
use Doctrine\ORM\Mapping as ORM;
|
|
use libphonenumber\PhoneNumber;
|
|
use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
|
|
use Symfony\Component\Validator\Constraints as Assert;
|
|
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
|
|
|
/**
|
|
* Person Class.
|
|
*/
|
|
#[DiscriminatorMap(typeProperty: 'type', mapping: ['person' => Person::class])]
|
|
#[ORM\Entity]
|
|
#[ORM\Index(name: 'person_names', columns: ['firstName', 'lastName'])] // ,
|
|
#[ORM\Index(name: 'person_birthdate', columns: ['birthdate'])] // @ORM\HasLifecycleCallbacks
|
|
#[ORM\Table(name: 'chill_person_person')]
|
|
#[ORM\HasLifecycleCallbacks]
|
|
#[PersonHasCenter]
|
|
#[HouseholdMembershipSequential(groups: ['household_memberships'])]
|
|
class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateInterface, \Stringable
|
|
{
|
|
// have days in commun
|
|
final public const ERROR_ADDIND_PERIOD_AFTER_AN_OPEN_PERIOD = 2; // where there exist
|
|
|
|
final public const ERROR_PERIODS_ARE_COLLAPSING = 1; // when two different periods
|
|
|
|
/**
|
|
* Accept receiving email.
|
|
*/
|
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::BOOLEAN, options: ['default' => false])]
|
|
private ?bool $acceptEmail = false;
|
|
|
|
/**
|
|
* Accept short text message (aka SMS).
|
|
*/
|
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::BOOLEAN, options: ['default' => false])]
|
|
private ?bool $acceptSMS = false;
|
|
|
|
/**
|
|
* The person's accompanying periods (when the person was accompanied by the center).
|
|
*
|
|
* @var Collection<int, AccompanyingPeriodParticipation>
|
|
*/
|
|
#[ORM\OneToMany(targetEntity: AccompanyingPeriodParticipation::class, mappedBy: 'person', cascade: ['persist', 'remove', 'merge', 'detach'])]
|
|
#[ORM\OrderBy(['startDate' => Criteria::DESC])]
|
|
private Collection $accompanyingPeriodParticipations;
|
|
|
|
/**
|
|
* The accompanying period requested by the Person.
|
|
*
|
|
* @var Collection<int, AccompanyingPeriod>
|
|
*/
|
|
#[ORM\OneToMany(targetEntity: AccompanyingPeriod::class, mappedBy: 'requestorPerson')]
|
|
private Collection $accompanyingPeriodRequested;
|
|
|
|
/**
|
|
* Addresses.
|
|
*
|
|
* @var Collection<int, Address>
|
|
*/
|
|
#[ORM\ManyToMany(targetEntity: Address::class, cascade: ['persist', 'remove', 'merge', 'detach'])]
|
|
#[ORM\JoinTable(name: 'chill_person_persons_to_addresses')]
|
|
#[ORM\OrderBy(['validFrom' => Criteria::DESC])]
|
|
private Collection $addresses;
|
|
|
|
/**
|
|
* @var Collection<int, PersonAltName>
|
|
*/
|
|
#[ORM\OneToMany(targetEntity: PersonAltName::class, mappedBy: 'person', cascade: ['persist', 'remove', 'merge', 'detach'], orphanRemoval: true)]
|
|
private Collection $altNames;
|
|
|
|
/**
|
|
* The person's birthdate.
|
|
*/
|
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::DATE_MUTABLE, nullable: true)]
|
|
#[Birthdate]
|
|
private ?\DateTime $birthdate = null;
|
|
|
|
/**
|
|
* @var Collection<int, Charge>
|
|
*/
|
|
#[ORM\OneToMany(targetEntity: Charge::class, mappedBy: 'person')]
|
|
private Collection $budgetCharges;
|
|
|
|
/**
|
|
* @var Collection<int, \Chill\BudgetBundle\Entity\Resource>
|
|
*/
|
|
#[ORM\OneToMany(targetEntity: Resource::class, mappedBy: 'person')]
|
|
private Collection $budgetResources;
|
|
|
|
/**
|
|
* @var Collection<int, Calendar>
|
|
*/
|
|
#[ORM\ManyToMany(targetEntity: Calendar::class, mappedBy: 'persons')]
|
|
private Collection $calendars;
|
|
|
|
/**
|
|
* The person's center.
|
|
*
|
|
* @deprecated
|
|
*/
|
|
#[ORM\ManyToOne(targetEntity: Center::class)]
|
|
private ?Center $center = null;
|
|
|
|
#[ORM\OneToOne(mappedBy: 'person', targetEntity: PersonCenterCurrent::class)]
|
|
private ?PersonCenterCurrent $centerCurrent = null;
|
|
|
|
/**
|
|
* @var Collection<int, PersonCenterHistory>&Selectable
|
|
*/
|
|
#[ORM\OneToMany(mappedBy: 'person', targetEntity: PersonCenterHistory::class, cascade: ['persist', 'remove'])]
|
|
private Collection&Selectable $centerHistory;
|
|
|
|
/**
|
|
* Array where customfield's data are stored.
|
|
*/
|
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::JSON)]
|
|
private ?array $cFData = null;
|
|
|
|
/**
|
|
* The marital status of the person.
|
|
*/
|
|
#[ORM\ManyToOne(targetEntity: Civility::class)]
|
|
#[ORM\JoinColumn(nullable: true)]
|
|
private ?Civility $civility = null;
|
|
|
|
/**
|
|
* Contact information for contacting the person.
|
|
*/
|
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::TEXT, nullable: true)]
|
|
private ?string $contactInfo = '';
|
|
|
|
/**
|
|
* The person's country of birth.
|
|
*/
|
|
#[ORM\ManyToOne(targetEntity: Country::class)] // sf4 check: option inversedBy="birthsIn" return error mapping !!
|
|
#[ORM\JoinColumn(nullable: true)]
|
|
private ?Country $countryOfBirth = null;
|
|
|
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::DATETIME_MUTABLE, nullable: true, options: ['default' => null])]
|
|
private ?\DateTimeInterface $createdAt = null;
|
|
|
|
#[ORM\ManyToOne(targetEntity: User::class)]
|
|
#[ORM\JoinColumn(nullable: true)]
|
|
private ?User $createdBy = null;
|
|
|
|
/**
|
|
* Cache the computation of household.
|
|
*/
|
|
private array $currentHouseholdAt = [];
|
|
|
|
/**
|
|
* Cache for the computation of current household participation.
|
|
*/
|
|
private array $currentHouseholdParticipationAt = [];
|
|
|
|
/**
|
|
* The current person address.
|
|
*
|
|
* This is computed through database and is optimized on database side.
|
|
*/
|
|
#[ORM\OneToOne(targetEntity: PersonCurrentAddress::class, mappedBy: 'person')]
|
|
private ?PersonCurrentAddress $currentPersonAddress = null;
|
|
|
|
/**
|
|
* The person's deathdate.
|
|
*/
|
|
#[Assert\GreaterThanOrEqual(propertyPath: 'birthdate')]
|
|
#[Assert\LessThanOrEqual('today')]
|
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::DATE_IMMUTABLE, nullable: true)]
|
|
private ?\DateTimeImmutable $deathdate = null;
|
|
|
|
/**
|
|
* The person's email.
|
|
*/
|
|
#[Assert\Email]
|
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::TEXT, nullable: true)]
|
|
private ?string $email = '';
|
|
|
|
/**
|
|
* The person's first name.
|
|
*/
|
|
#[Assert\NotBlank(message: 'The firstname cannot be empty')]
|
|
#[Assert\Length(max: 255)]
|
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING, length: 255)]
|
|
private string $firstName = '';
|
|
|
|
/**
|
|
* fullname canonical. Read-only field, which is calculated by
|
|
* the database.
|
|
*/
|
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::TEXT, nullable: true)]
|
|
private ?string $fullnameCanonical = '';
|
|
|
|
/**
|
|
* NEW column : The person's gender.
|
|
*/
|
|
#[Assert\NotNull(message: 'The gender must be set')]
|
|
#[ORM\ManyToOne(targetEntity: Gender::class)]
|
|
private ?Gender $gender = null;
|
|
|
|
/**
|
|
* Comment on gender.
|
|
*/
|
|
#[ORM\Embedded(class: CommentEmbeddable::class, columnPrefix: 'genderComment_')]
|
|
private CommentEmbeddable $genderComment;
|
|
|
|
/**
|
|
* Read-only field, computed by the database.
|
|
*
|
|
* @var Collection<int, PersonHouseholdAddress>
|
|
*/
|
|
#[ORM\OneToMany(targetEntity: PersonHouseholdAddress::class, mappedBy: 'person')]
|
|
private Collection $householdAddresses;
|
|
|
|
/**
|
|
* @var Collection<int, HouseholdMember>
|
|
*/
|
|
#[ORM\OneToMany(targetEntity: HouseholdMember::class, mappedBy: 'person')]
|
|
private Collection $householdParticipations;
|
|
|
|
/**
|
|
* The person's id.
|
|
*/
|
|
#[ORM\Id]
|
|
#[ORM\Column(name: 'id', type: \Doctrine\DBAL\Types\Types::INTEGER)]
|
|
#[ORM\GeneratedValue(strategy: 'AUTO')]
|
|
private ?int $id = null;
|
|
|
|
/**
|
|
* The person's last name.
|
|
*/
|
|
#[Assert\NotBlank(message: 'The lastname cannot be empty')]
|
|
#[Assert\Length(max: 255)]
|
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING, length: 255)]
|
|
private string $lastName = '';
|
|
|
|
/**
|
|
* The marital status of the person.
|
|
*/
|
|
#[ORM\ManyToOne(targetEntity: MaritalStatus::class)]
|
|
#[ORM\JoinColumn(nullable: true)]
|
|
private ?MaritalStatus $maritalStatus = null;
|
|
|
|
/**
|
|
* Comment on marital status.
|
|
*/
|
|
#[ORM\Embedded(class: CommentEmbeddable::class, columnPrefix: 'maritalStatusComment_')]
|
|
private CommentEmbeddable $maritalStatusComment;
|
|
|
|
/**
|
|
* The date of the last marital status change of the person.
|
|
*/
|
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::DATE_MUTABLE, nullable: true)]
|
|
private ?\DateTime $maritalStatusDate = null;
|
|
|
|
/**
|
|
* A remark over the person.
|
|
*/
|
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::TEXT)]
|
|
private string $memo = '';
|
|
|
|
/**
|
|
* The person's mobile phone number.
|
|
*/
|
|
#[ORM\Column(type: 'phone_number', nullable: true)]
|
|
#[PhonenumberConstraint(type: 'mobile')]
|
|
private ?PhoneNumber $mobilenumber = null;
|
|
|
|
/**
|
|
* The person's nationality.
|
|
*/
|
|
#[ORM\ManyToOne(targetEntity: Country::class)] // sf4 check: option inversedBy="nationals" return error mapping !!
|
|
#[ORM\JoinColumn(nullable: true)]
|
|
private ?Country $nationality = null;
|
|
|
|
/**
|
|
* Number of children.
|
|
*/
|
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::INTEGER, nullable: true)]
|
|
private ?int $numberOfChildren = null;
|
|
|
|
/**
|
|
* @var Collection<int, PersonPhone>
|
|
*/
|
|
#[Assert\Valid(traverse: true)]
|
|
#[ORM\OneToMany(targetEntity: PersonPhone::class, mappedBy: 'person', cascade: ['persist', 'remove', 'merge', 'detach'], orphanRemoval: true)]
|
|
private Collection $otherPhoneNumbers;
|
|
|
|
/**
|
|
* @var Collection<int, AccompanyingPeriod>
|
|
*/
|
|
#[ORM\OneToMany(targetEntity: AccompanyingPeriod::class, mappedBy: 'personLocation')]
|
|
private Collection $periodLocatedOn;
|
|
|
|
/**
|
|
* The person's phonenumber.
|
|
*/
|
|
#[ORM\Column(type: 'phone_number', nullable: true)]
|
|
#[PhonenumberConstraint(type: 'landline')]
|
|
private ?PhoneNumber $phonenumber = null;
|
|
|
|
/**
|
|
* The person's place of birth.
|
|
*/
|
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING, length: 255, name: 'place_of_birth')]
|
|
private string $placeOfBirth = '';
|
|
|
|
/**
|
|
* @deprecated
|
|
*/
|
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::BOOLEAN)]
|
|
private bool $proxyAccompanyingPeriodOpenState = false; // TO-DELETE ?
|
|
/**
|
|
* @var Collection<int, PersonResource>
|
|
*/
|
|
#[ORM\OneToMany(targetEntity: PersonResource::class, mappedBy: 'personOwner')]
|
|
private Collection $resources;
|
|
|
|
/**
|
|
* The person's spoken languages.
|
|
*
|
|
* @var Collection<int, Language>
|
|
*/
|
|
#[ORM\ManyToMany(targetEntity: Language::class)]
|
|
#[ORM\JoinTable(name: 'persons_spoken_languages', joinColumns: [new ORM\JoinColumn(name: 'person_id', referencedColumnName: 'id')], inverseJoinColumns: [new ORM\JoinColumn(name: 'language_id', referencedColumnName: 'id')])]
|
|
private Collection $spokenLanguages;
|
|
|
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::DATETIME_MUTABLE, nullable: true, options: ['default' => null])]
|
|
private ?\DateTimeInterface $updatedAt = null;
|
|
|
|
#[ORM\ManyToOne(targetEntity: User::class)]
|
|
private ?User $updatedBy = null;
|
|
|
|
/**
|
|
* @var Collection<int, EntityWorkflowStepSignature>
|
|
*/
|
|
#[ORM\OneToMany(targetEntity: EntityWorkflowStepSignature::class, mappedBy: 'personSigner', orphanRemoval: true)]
|
|
private Collection $signatures;
|
|
|
|
/**
|
|
* Person constructor.
|
|
*/
|
|
public function __construct()
|
|
{
|
|
$this->calendars = new ArrayCollection();
|
|
$this->accompanyingPeriodParticipations = new ArrayCollection();
|
|
$this->spokenLanguages = new ArrayCollection();
|
|
$this->addresses = new ArrayCollection();
|
|
$this->altNames = new ArrayCollection();
|
|
$this->otherPhoneNumbers = new ArrayCollection();
|
|
$this->householdParticipations = new ArrayCollection();
|
|
$this->householdAddresses = new ArrayCollection();
|
|
$this->genderComment = new CommentEmbeddable();
|
|
$this->maritalStatusComment = new CommentEmbeddable();
|
|
$this->periodLocatedOn = new ArrayCollection();
|
|
$this->accompanyingPeriodRequested = new ArrayCollection();
|
|
$this->budgetResources = new ArrayCollection();
|
|
$this->budgetCharges = new ArrayCollection();
|
|
$this->resources = new ArrayCollection();
|
|
$this->centerHistory = new ArrayCollection();
|
|
$this->signatures = new ArrayCollection();
|
|
}
|
|
|
|
public function __toString(): string
|
|
{
|
|
return $this->getLabel();
|
|
}
|
|
|
|
/**
|
|
* Add AccompanyingPeriodParticipation.
|
|
*
|
|
* @uses AccompanyingPeriod::addPerson
|
|
*/
|
|
public function addAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod): self
|
|
{
|
|
$participation = new AccompanyingPeriodParticipation($accompanyingPeriod, $this);
|
|
$this->accompanyingPeriodParticipations->add($participation);
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function addAddress(Address $address): self
|
|
{
|
|
$this->addresses[] = $address;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function addAltName(PersonAltName $altName): self
|
|
{
|
|
if (false === $this->altNames->contains($altName)) {
|
|
$this->altNames->add($altName);
|
|
$altName->setPerson($this);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function addBudgetCharge(Charge $budgetCharge): self
|
|
{
|
|
$this->budgetCharges[] = $budgetCharge;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function addBudgetResource(Resource $budgetResource): self
|
|
{
|
|
$this->budgetResources[] = $budgetResource;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function addHouseholdParticipation(HouseholdMember $member): self
|
|
{
|
|
$this->householdParticipations[] = $member;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @return $this
|
|
*/
|
|
public function addOtherPhoneNumber(PersonPhone $otherPhoneNumber)
|
|
{
|
|
if (false === $this->otherPhoneNumbers->contains($otherPhoneNumber)) {
|
|
$otherPhoneNumber->setPerson($this);
|
|
$this->otherPhoneNumbers->add($otherPhoneNumber);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function addSignature(EntityWorkflowStepSignature $signature): self
|
|
{
|
|
if (!$this->signatures->contains($signature)) {
|
|
$this->signatures->add($signature);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function removeSignature(EntityWorkflowStepSignature $signature): self
|
|
{
|
|
$this->signatures->removeElement($signature);
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @return ReadableCollection<int, EntityWorkflowStepSignature>
|
|
*/
|
|
public function getSignatures(): ReadableCollection
|
|
{
|
|
return $this->signatures;
|
|
}
|
|
|
|
public function getSignaturesPending(): ReadableCollection
|
|
{
|
|
return $this->signatures->filter(fn (EntityWorkflowStepSignature $signature) => EntityWorkflowSignatureStateEnum::PENDING === $signature->getState());
|
|
}
|
|
|
|
/**
|
|
* Function used for validation that check if the accompanying periods of
|
|
* the person are not collapsing (i.e. have not shared days) or having
|
|
* a period after an open period.
|
|
*
|
|
* @return true|array True if the accompanying periods are not collapsing,
|
|
* an array with data for displaying the error
|
|
*/
|
|
public function checkAccompanyingPeriodsAreNotCollapsing(): array|bool
|
|
{
|
|
$periods = $this->getAccompanyingPeriodsOrdered();
|
|
$periodsNbr = \count($periods);
|
|
$i = 0;
|
|
|
|
while ($periodsNbr - 1 > $i) {
|
|
$periodI = $periods[$i];
|
|
$periodAfterI = $periods[$i + 1];
|
|
|
|
if ($periodI->isOpen()) {
|
|
return [
|
|
'result' => self::ERROR_ADDIND_PERIOD_AFTER_AN_OPEN_PERIOD,
|
|
'dateOpening' => $periodAfterI->getOpeningDate(),
|
|
'dateClosing' => $periodAfterI->getClosingDate(),
|
|
'date' => $periodI->getOpeningDate(),
|
|
];
|
|
}
|
|
|
|
if ($periodI->getClosingDate() >= $periodAfterI->getOpeningDate()) {
|
|
return [
|
|
'result' => self::ERROR_PERIODS_ARE_COLLAPSING,
|
|
'dateOpening' => $periodI->getOpeningDate(),
|
|
|
|
'dateClosing' => $periodI->getClosingDate(),
|
|
'date' => $periodAfterI->getOpeningDate(),
|
|
];
|
|
}
|
|
++$i;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Set the Person file as closed at the given date.
|
|
*
|
|
* For update a closing date, you should update AccompanyingPeriod instance
|
|
* directly.
|
|
*
|
|
* To check if the Person and its accompanying period are consistent, use validation.
|
|
*
|
|
* @throws \Exception if two lines of the accompanying period are open
|
|
*/
|
|
public function close(?AccompanyingPeriod $accompanyingPeriod = null): void
|
|
{
|
|
$this->proxyAccompanyingPeriodOpenState = false;
|
|
}
|
|
|
|
public function countResources(): int
|
|
{
|
|
return $this->resources->count();
|
|
}
|
|
|
|
/**
|
|
* This public function is the same but return only true or false.
|
|
*/
|
|
public function containsAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod): bool
|
|
{
|
|
return ($this->participationsContainAccompanyingPeriod($accompanyingPeriod)) ? false : true;
|
|
}
|
|
|
|
/**
|
|
* Handy method to get the AccompanyingPeriodParticipation
|
|
* matching a given AccompanyingPeriod.
|
|
*
|
|
* Used in template, to find the participation when iterating on a list
|
|
* of period.
|
|
*/
|
|
public function findParticipationForPeriod(AccompanyingPeriod $period): ?AccompanyingPeriodParticipation
|
|
{
|
|
$closeCandidates = [];
|
|
|
|
foreach ($this->getAccompanyingPeriodParticipations() as $participation) {
|
|
if ($participation->getAccompanyingPeriod() === $period) {
|
|
if ($participation->isOpen()) {
|
|
return $participation;
|
|
}
|
|
$closeCandidates[] = $participation;
|
|
}
|
|
}
|
|
|
|
if (0 < \count($closeCandidates)) {
|
|
return $closeCandidates[0];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public function getAcceptEmail(): ?bool
|
|
{
|
|
return $this->acceptEmail;
|
|
}
|
|
|
|
public function getAcceptSMS(): ?bool
|
|
{
|
|
return $this->acceptSMS;
|
|
}
|
|
|
|
/**
|
|
* Return a list of all accompanying period where the person is involved:.
|
|
*
|
|
* * as requestor;
|
|
* * as participant, only for opened participation;
|
|
*
|
|
* @param bool $asParticipantOpen add participation which are still opened
|
|
* @param bool $asRequestor add accompanying period where the person is requestor
|
|
*
|
|
* @return AccompanyingPeriod[]|Collection
|
|
*/
|
|
public function getAccompanyingPeriodInvolved(
|
|
bool $asParticipantOpen = true,
|
|
bool $asRequestor = true,
|
|
): Collection {
|
|
$result = new ArrayCollection();
|
|
|
|
if ($asParticipantOpen) {
|
|
foreach ($this->getAccompanyingPeriodParticipations()
|
|
->map(fn (AccompanyingPeriodParticipation $app) => $app->getAccompanyingPeriod()) as $period
|
|
) {
|
|
if (!$result->contains($period)) {
|
|
$result->add($period);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($asRequestor) {
|
|
foreach ($this->accompanyingPeriodRequested as $period) {
|
|
if (!$result->contains($period)) {
|
|
$result->add($period);
|
|
}
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
public function countAccompanyingPeriodInvolved(
|
|
bool $asParticipantOpen = true,
|
|
bool $asRequestor = true,
|
|
): int {
|
|
// TODO should be optimized to avoid loading accompanying period ?
|
|
return $this->getAccompanyingPeriodInvolved($asParticipantOpen, $asRequestor)
|
|
->filter(fn (AccompanyingPeriod $p) => AccompanyingPeriod::STEP_DRAFT !== $p->getStep())
|
|
->count();
|
|
}
|
|
|
|
/**
|
|
* Get AccompanyingPeriodParticipations Collection.
|
|
*
|
|
* @return AccompanyingPeriodParticipation[]|Collection
|
|
*/
|
|
public function getAccompanyingPeriodParticipations(): Collection
|
|
{
|
|
return $this->accompanyingPeriodParticipations;
|
|
}
|
|
|
|
/**
|
|
* @return AccompanyingPeriod[]|Collection
|
|
*/
|
|
public function getAccompanyingPeriodRequested(): Collection
|
|
{
|
|
return $this->accompanyingPeriodRequested;
|
|
}
|
|
|
|
/**
|
|
* Get AccompanyingPeriods array.
|
|
*/
|
|
public function getAccompanyingPeriods(): array
|
|
{
|
|
$accompanyingPeriods = [];
|
|
|
|
foreach ($this->accompanyingPeriodParticipations as $participation) {
|
|
/* @var AccompanyingPeriodParticipation $participation */
|
|
$accompanyingPeriods[] = $participation->getAccompanyingPeriod();
|
|
}
|
|
|
|
return $accompanyingPeriods;
|
|
}
|
|
|
|
/**
|
|
* Get the accompanying periods of a give person with the chronological order.
|
|
*/
|
|
public function getAccompanyingPeriodsOrdered(): array
|
|
{
|
|
$periods = $this->getAccompanyingPeriods();
|
|
|
|
// order by date :
|
|
usort($periods, static function ($a, $b) {
|
|
$dateA = $a->getOpeningDate();
|
|
$dateB = $b->getOpeningDate();
|
|
|
|
if ($dateA === $dateB) {
|
|
$dateEA = $a->getClosingDate();
|
|
$dateEB = $b->getClosingDate();
|
|
|
|
if ($dateEA === $dateEB) {
|
|
return 0;
|
|
}
|
|
|
|
if ($dateEA < $dateEB) {
|
|
return -1;
|
|
}
|
|
|
|
return +1;
|
|
}
|
|
|
|
if ($dateA < $dateB) {
|
|
return -1;
|
|
}
|
|
|
|
return 1;
|
|
});
|
|
|
|
return $periods;
|
|
}
|
|
|
|
/**
|
|
* get the address associated with the person at the given date.
|
|
*
|
|
* If the `$at` parameter is now, use the method `getCurrentPersonAddress`, which is optimized
|
|
* on database side.
|
|
*
|
|
* @deprecated since chill2.0, address is linked to the household. Use @see{Person::getCurrentHouseholdAddress}
|
|
*
|
|
* @throws \Exception
|
|
*/
|
|
public function getAddressAt(?\DateTimeInterface $at = null): ?Address
|
|
{
|
|
$at ??= new \DateTime('now');
|
|
|
|
if ($at instanceof \DateTimeImmutable) {
|
|
$at = \DateTime::createFromImmutable($at);
|
|
}
|
|
|
|
/** @var \ArrayIterator $addressesIterator */
|
|
$addressesIterator = $this->getAddresses()
|
|
->filter(static fn (Address $address): bool => $address->getValidFrom() <= $at)
|
|
->getIterator();
|
|
|
|
$addressesIterator->uasort(
|
|
static fn (Address $left, Address $right): int => $right->getValidFrom() <=> $left->getValidFrom()
|
|
);
|
|
|
|
return [] === ($addresses = iterator_to_array($addressesIterator)) ?
|
|
null :
|
|
current($addresses);
|
|
}
|
|
|
|
/**
|
|
* By default, the addresses are ordered by date, descending (the most
|
|
* recent first).
|
|
*/
|
|
public function getAddresses(): Collection
|
|
{
|
|
return $this->addresses;
|
|
}
|
|
|
|
/**
|
|
* Return the age of a person, calculated at the date 'now'.
|
|
*
|
|
* If the person has a deathdate, calculate the age at the deathdate.
|
|
*
|
|
* @param string $at a valid string to create a DateTime
|
|
*/
|
|
public function getAge(string $at = 'now'): ?int
|
|
{
|
|
if ($this->birthdate instanceof \DateTimeInterface) {
|
|
if ($this->deathdate instanceof \DateTimeInterface) {
|
|
return (int) date_diff($this->birthdate, $this->deathdate)->format('%y');
|
|
}
|
|
|
|
return (int) date_diff($this->birthdate, date_create($at))->format('%y');
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public function getAltNames(): Collection
|
|
{
|
|
return $this->altNames;
|
|
}
|
|
|
|
public function getBirthdate(): ?\DateTime
|
|
{
|
|
return $this->birthdate;
|
|
}
|
|
|
|
/**
|
|
* @return Collection|Charge[]
|
|
*/
|
|
public function getBudgetCharges(): Collection
|
|
{
|
|
return $this->budgetCharges;
|
|
}
|
|
|
|
/**
|
|
* @return Collection|\Chill\BudgetBundle\Entity\Resource[]
|
|
*/
|
|
public function getBudgetResources(): Collection
|
|
{
|
|
return $this->budgetResources;
|
|
}
|
|
|
|
/**
|
|
* @return Collection<int, Calendar>
|
|
*/
|
|
public function getCalendars(): Collection
|
|
{
|
|
return $this->calendars;
|
|
}
|
|
|
|
public function getCenter(): ?Center
|
|
{
|
|
if (null !== $this->centerCurrent) {
|
|
return $this->centerCurrent->getCenter();
|
|
}
|
|
|
|
if (null === $currentCenterHistory = $this->getCurrentCenterHistory()) {
|
|
return null;
|
|
}
|
|
|
|
return $currentCenterHistory->getCenter();
|
|
}
|
|
|
|
public function getCenterCurrent(): ?PersonCenterCurrent
|
|
{
|
|
if (null !== $this->centerCurrent) {
|
|
return $this->centerCurrent;
|
|
}
|
|
|
|
if (null === $currentCenterHistory = $this->getCurrentCenterHistory()) {
|
|
return null;
|
|
}
|
|
|
|
return new PersonCenterCurrent($currentCenterHistory);
|
|
}
|
|
|
|
public function getCenterHistory(): Collection
|
|
{
|
|
return $this->centerHistory;
|
|
}
|
|
|
|
public function getCFData(): ?array
|
|
{
|
|
if (null === $this->cFData) {
|
|
$this->cFData = [];
|
|
}
|
|
|
|
return $this->cFData;
|
|
}
|
|
|
|
public function getCivility(): ?Civility
|
|
{
|
|
return $this->civility;
|
|
}
|
|
|
|
public function getcontactInfo(): ?string
|
|
{
|
|
return $this->contactInfo;
|
|
}
|
|
|
|
public function getCountryOfBirth(): ?Country
|
|
{
|
|
return $this->countryOfBirth;
|
|
}
|
|
|
|
public function getCreatedAt(): ?\DateTimeInterface
|
|
{
|
|
return $this->createdAt;
|
|
}
|
|
|
|
public function getCreatedBy(): ?User
|
|
{
|
|
return $this->createdBy;
|
|
}
|
|
|
|
/**
|
|
* Returns the opened accompanying period.
|
|
*
|
|
* @deprecated since 1.1 use `getOpenedAccompanyingPeriod instead
|
|
*/
|
|
public function getCurrentAccompanyingPeriod(): ?AccompanyingPeriod
|
|
{
|
|
return $this->getOpenedAccompanyingPeriod();
|
|
}
|
|
|
|
/**
|
|
* Get current accompanyingPeriods array.
|
|
*
|
|
* @return AccompanyingPeriod[]|array
|
|
*/
|
|
public function getCurrentAccompanyingPeriods(): array
|
|
{
|
|
$currentAccompanyingPeriods = [];
|
|
$currentDate = new \DateTime();
|
|
|
|
foreach ($this->accompanyingPeriodParticipations as $participation) {
|
|
$endDate = $participation->getEndDate();
|
|
|
|
if (null === $endDate || $endDate > $currentDate) {
|
|
$currentAccompanyingPeriods[] = $participation->getAccompanyingPeriod();
|
|
}
|
|
}
|
|
|
|
return $currentAccompanyingPeriods;
|
|
}
|
|
|
|
public function getCurrentHousehold(?\DateTimeImmutable $at = null): ?Household
|
|
{
|
|
$participation = $this->getCurrentHouseholdParticipationShareHousehold($at);
|
|
|
|
return $participation instanceof HouseholdMember ?
|
|
$participation->getHousehold()
|
|
: null;
|
|
}
|
|
|
|
/**
|
|
* Get the household address at the given date.
|
|
*
|
|
* if the given date is 'now', use instead @see{getCurrentPersonAddress}, which is optimized on
|
|
* database side.
|
|
*/
|
|
public function getCurrentHouseholdAddress(?\DateTimeImmutable $at = null): ?Address
|
|
{
|
|
if (
|
|
null === $at
|
|
|| $at->format('Ymd') === (new \DateTime('today'))->format('Ymd')
|
|
) {
|
|
return $this->currentPersonAddress instanceof PersonCurrentAddress
|
|
? $this->currentPersonAddress->getAddress() : null;
|
|
}
|
|
|
|
// if not now, compute the date from history
|
|
$criteria = new Criteria();
|
|
$expr = Criteria::expr();
|
|
|
|
$criteria->where(
|
|
$expr->lte('validFrom', $at)
|
|
)
|
|
->andWhere(
|
|
$expr->orX(
|
|
$expr->isNull('validTo'),
|
|
$expr->gte('validTo', $at)
|
|
)
|
|
);
|
|
|
|
$addrs = $this->getHouseholdAddresses()
|
|
->matching($criteria);
|
|
|
|
if ($addrs->count() > 0) {
|
|
return $addrs->first()->getAddress();
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public function getCurrentHouseholdParticipationShareHousehold(?\DateTimeImmutable $at = null): ?HouseholdMember
|
|
{
|
|
$criteria = new Criteria();
|
|
$expr = Criteria::expr();
|
|
$date = $at ?? new \DateTimeImmutable('today');
|
|
$datef = $date->format('Y-m-d');
|
|
|
|
if (
|
|
null !== ($this->currentHouseholdParticipationAt[$datef] ?? null)) {
|
|
return $this->currentHouseholdParticipationAt[$datef];
|
|
}
|
|
|
|
$criteria
|
|
->where(
|
|
$expr->andX(
|
|
$expr->lte('startDate', $date),
|
|
$expr->orX(
|
|
$expr->isNull('endDate'),
|
|
$expr->gt('endDate', $date)
|
|
),
|
|
$expr->eq('shareHousehold', true)
|
|
)
|
|
);
|
|
|
|
$participations = $this->getHouseholdParticipations()
|
|
->matching($criteria);
|
|
|
|
return $participations->count() > 0 ?
|
|
$this->currentHouseholdParticipationAt[$datef] = $participations->first()
|
|
: null;
|
|
}
|
|
|
|
/**
|
|
* Get the current person address.
|
|
*/
|
|
public function getCurrentPersonAddress(): ?Address
|
|
{
|
|
if (null === $this->currentPersonAddress) {
|
|
return null;
|
|
}
|
|
|
|
return $this->currentPersonAddress->getAddress();
|
|
}
|
|
|
|
public function getDeathdate(): ?\DateTimeInterface
|
|
{
|
|
return $this->deathdate;
|
|
}
|
|
|
|
public function getEmail(): ?string
|
|
{
|
|
return $this->email;
|
|
}
|
|
|
|
public function getFirstName(): string
|
|
{
|
|
return $this->firstName;
|
|
}
|
|
|
|
public function getFullnameCanonical(): string
|
|
{
|
|
return $this->fullnameCanonical;
|
|
}
|
|
|
|
public function getGender(): ?Gender
|
|
{
|
|
return $this->gender;
|
|
}
|
|
|
|
public function getGenderComment(): ?CommentEmbeddable
|
|
{
|
|
return $this->genderComment;
|
|
}
|
|
|
|
public function getHouseholdAddresses(): Collection
|
|
{
|
|
return $this->householdAddresses;
|
|
}
|
|
|
|
/**
|
|
* @return Collection|HouseholdMember[]
|
|
*/
|
|
public function getHouseholdParticipations(): Collection
|
|
{
|
|
return $this->householdParticipations;
|
|
}
|
|
|
|
/**
|
|
* Get participation where the person does not share the household.
|
|
*
|
|
* Order by startDate, desc
|
|
*
|
|
* @return HouseholdMember[]
|
|
*/
|
|
public function getHouseholdParticipationsNotShareHousehold(): Collection
|
|
{
|
|
$criteria = new Criteria();
|
|
$expr = Criteria::expr();
|
|
|
|
$criteria
|
|
->where(
|
|
$expr->eq('shareHousehold', false)
|
|
)
|
|
->orderBy(['startDate' => \Doctrine\Common\Collections\Order::Descending]);
|
|
|
|
return $this->getHouseholdParticipations()
|
|
->matching($criteria);
|
|
}
|
|
|
|
/**
|
|
* Get participation where the person does share the household.
|
|
*
|
|
* Order by startDate, desc
|
|
*
|
|
* @return Collection|HouseholdMember[]
|
|
*/
|
|
public function getHouseholdParticipationsShareHousehold(): Collection
|
|
{
|
|
$criteria = new Criteria();
|
|
$expr = Criteria::expr();
|
|
|
|
$criteria
|
|
->where(
|
|
$expr->eq('shareHousehold', true)
|
|
)
|
|
->orderBy(['startDate' => \Doctrine\Common\Collections\Order::Descending, 'id' => \Doctrine\Common\Collections\Order::Descending]);
|
|
|
|
return $this->getHouseholdParticipations()
|
|
->matching($criteria);
|
|
}
|
|
|
|
public function getId(): ?int
|
|
{
|
|
return $this->id;
|
|
}
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
public function getLabel()
|
|
{
|
|
return $this->getFirstName().' '.$this->getLastName();
|
|
}
|
|
|
|
/**
|
|
* @deprecated Use @see{Person::getCurrentPersonAddress} or @see{Person::getCurrentHouseholdAddress} instead
|
|
*
|
|
* @return false|mixed|null
|
|
*
|
|
* @throws \Exception
|
|
*/
|
|
public function getLastAddress(?\DateTime $from = null)
|
|
{
|
|
return $this->getCurrentHouseholdAddress(
|
|
null !== $from ? \DateTimeImmutable::createFromMutable($from) : null
|
|
);
|
|
}
|
|
|
|
public function getLastName(): string
|
|
{
|
|
return $this->lastName;
|
|
}
|
|
|
|
public function getMaritalStatus(): ?MaritalStatus
|
|
{
|
|
return $this->maritalStatus;
|
|
}
|
|
|
|
public function getMaritalStatusComment(): CommentEmbeddable
|
|
{
|
|
return $this->maritalStatusComment;
|
|
}
|
|
|
|
public function getMaritalStatusDate(): ?\DateTimeInterface
|
|
{
|
|
return $this->maritalStatusDate;
|
|
}
|
|
|
|
public function getMemo(): ?string
|
|
{
|
|
return $this->memo;
|
|
}
|
|
|
|
public function getMobilenumber(): ?PhoneNumber
|
|
{
|
|
return $this->mobilenumber;
|
|
}
|
|
|
|
public function getNationality(): ?Country
|
|
{
|
|
return $this->nationality;
|
|
}
|
|
|
|
public function getNumberOfChildren(): ?int
|
|
{
|
|
return $this->numberOfChildren;
|
|
}
|
|
|
|
/**
|
|
* Return the opened accompanying period.
|
|
*/
|
|
public function getOpenedAccompanyingPeriod(): ?AccompanyingPeriod
|
|
{
|
|
if (false === $this->isOpen()) {
|
|
return null;
|
|
}
|
|
|
|
foreach ($this->accompanyingPeriodParticipations as $participation) {
|
|
/** @var AccompanyingPeriodParticipation $participation */
|
|
if ($participation->getAccompanyingPeriod()->isOpen()) {
|
|
return $participation->getAccompanyingPeriod();
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Return a collection of participation, where the participation
|
|
* is still opened or in draft state.
|
|
*
|
|
* @return AccompanyingPeriodParticipation[]|Collection
|
|
*/
|
|
public function getOpenedParticipations(): Collection
|
|
{
|
|
// create a criteria for filtering easily
|
|
$criteria = Criteria::create();
|
|
$criteria
|
|
->andWhere(Criteria::expr()->eq('endDate', null))
|
|
->orWhere(Criteria::expr()->gt('endDate', new \DateTime('now')));
|
|
|
|
return $this->getAccompanyingPeriodParticipations()
|
|
->matching($criteria)
|
|
->filter(static fn (AccompanyingPeriodParticipation $app) => AccompanyingPeriod::STEP_CLOSED !== $app->getAccompanyingPeriod()->getStep());
|
|
}
|
|
|
|
public function getOtherPhoneNumbers(): Collection
|
|
{
|
|
return $this->otherPhoneNumbers;
|
|
}
|
|
|
|
public function getPhonenumber(): ?PhoneNumber
|
|
{
|
|
return $this->phonenumber;
|
|
}
|
|
|
|
public function getPlaceOfBirth(): ?string
|
|
{
|
|
return $this->placeOfBirth;
|
|
}
|
|
|
|
/**
|
|
* @return PersonResource[]|Collection
|
|
*/
|
|
public function getResources(): array|Collection
|
|
{
|
|
return $this->resources;
|
|
}
|
|
|
|
/**
|
|
* Get spokenLanguages.
|
|
*
|
|
* @return Collection<Language>
|
|
*/
|
|
public function getSpokenLanguages()
|
|
{
|
|
return $this->spokenLanguages;
|
|
}
|
|
|
|
public function getUpdatedAt(): ?\DateTimeInterface
|
|
{
|
|
return $this->updatedAt;
|
|
}
|
|
|
|
public function getUpdatedBy(): ?User
|
|
{
|
|
return $this->updatedBy;
|
|
}
|
|
|
|
public function hasCurrentHouseholdAddress(?\DateTimeImmutable $at = null): bool
|
|
{
|
|
return null !== $this->getCurrentHouseholdAddress($at);
|
|
}
|
|
|
|
/**
|
|
* Return true if the person has two addresses with the
|
|
* same validFrom date (in format 'Y-m-d').
|
|
*/
|
|
public function hasTwoAdressWithSameValidFromDate()
|
|
{
|
|
$validYMDDates = [];
|
|
|
|
foreach ($this->addresses as $ad) {
|
|
$validDate = $ad->getValidFrom()->format('Y-m-d');
|
|
|
|
if (\in_array($validDate, $validYMDDates, true)) {
|
|
return true;
|
|
}
|
|
$validYMDDates[] = $validDate;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Validation callback that checks if the accompanying periods are valid.
|
|
*
|
|
* This method add violation errors.
|
|
*/
|
|
#[Assert\Callback(groups: ['accompanying_period_consistent'])]
|
|
public function isAccompanyingPeriodValid(ExecutionContextInterface $context)
|
|
{
|
|
$r = $this->checkAccompanyingPeriodsAreNotCollapsing();
|
|
|
|
if (true !== $r) {
|
|
if (self::ERROR_PERIODS_ARE_COLLAPSING === $r['result']) {
|
|
$context->buildViolation('Two accompanying periods have days in commun')
|
|
->atPath('accompanyingPeriods')
|
|
->addViolation();
|
|
}
|
|
|
|
if (self::ERROR_ADDIND_PERIOD_AFTER_AN_OPEN_PERIOD === $r['result']) {
|
|
$context->buildViolation('A period is opened and a period is added after it')
|
|
->atPath('accompanyingPeriods')
|
|
->addViolation();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Validation callback that checks if the addresses are valid (do not have
|
|
* two addresses with the same validFrom date).
|
|
*
|
|
* This method add violation errors.
|
|
*/
|
|
#[Assert\Callback(groups: ['addresses_consistent'])]
|
|
public function isAddressesValid(ExecutionContextInterface $context)
|
|
{
|
|
if ($this->hasTwoAdressWithSameValidFromDate()) {
|
|
$context
|
|
->buildViolation('Two addresses has the same validFrom date')
|
|
->atPath('addresses')
|
|
->addViolation();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if the person is opened.
|
|
*/
|
|
public function isOpen(): bool
|
|
{
|
|
foreach ($this->getAccompanyingPeriods() as $period) {
|
|
if ($period->isOpen()) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public function isSharingHousehold(?\DateTimeImmutable $at = null): bool
|
|
{
|
|
return null !== $this->getCurrentHousehold($at);
|
|
}
|
|
|
|
/**
|
|
* set the Person file as open at the given date.
|
|
*
|
|
* For updating a opening's date, you should update AccompanyingPeriod instance
|
|
* directly.
|
|
*
|
|
* For closing a file, @see this::close
|
|
*
|
|
* To check if the Person and its accompanying period is consistent, use validation.
|
|
*/
|
|
public function open(AccompanyingPeriod $accompanyingPeriod): void
|
|
{
|
|
$this->proxyAccompanyingPeriodOpenState = true;
|
|
$this->addAccompanyingPeriod($accompanyingPeriod);
|
|
}
|
|
|
|
/**
|
|
* Remove AccompanyingPeriod.
|
|
*/
|
|
public function removeAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod): void
|
|
{
|
|
$participation = $this->participationsContainAccompanyingPeriod($accompanyingPeriod);
|
|
|
|
if (!null === $participation) {
|
|
$participation->setEndDate(new \DateTime());
|
|
$this->accompanyingPeriodParticipations->removeElement($participation);
|
|
}
|
|
}
|
|
|
|
public function removeAddress(Address $address)
|
|
{
|
|
$this->addresses->removeElement($address);
|
|
}
|
|
|
|
public function removeAltName(PersonAltName $altName): self
|
|
{
|
|
if ($this->altNames->contains($altName)) {
|
|
$altName->setPerson(null);
|
|
$this->altNames->removeElement($altName);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function removeBudgetCharge(Charge $budgetCharge): self
|
|
{
|
|
$this->budgetCharges->removeElement($budgetCharge);
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function removeBudgetResource(Resource $budgetResource): self
|
|
{
|
|
$this->budgetResources->removeElement($budgetResource);
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function removeOtherPhoneNumber(PersonPhone $otherPhoneNumber): self
|
|
{
|
|
if ($this->otherPhoneNumbers->contains($otherPhoneNumber)) {
|
|
$this->otherPhoneNumbers->removeElement($otherPhoneNumber);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setAcceptEmail(bool $acceptEmail): self
|
|
{
|
|
$this->acceptEmail = $acceptEmail;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setAcceptSMS(bool $acceptSMS): self
|
|
{
|
|
$this->acceptSMS = $acceptSMS;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setAltNames(Collection $altNames): self
|
|
{
|
|
$this->altNames = $altNames;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setBirthdate(?\DateTime $birthdate): self
|
|
{
|
|
$this->birthdate = $birthdate;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Associate the center with the person. The association start on 'now'.
|
|
*
|
|
* @return $this
|
|
*/
|
|
public function setCenter(?Center $center): self
|
|
{
|
|
$modification = new \DateTimeImmutable('now');
|
|
|
|
foreach ($this->centerHistory as $centerHistory) {
|
|
if (null === $centerHistory->getEndDate()) {
|
|
$centerHistory->setEndDate($modification);
|
|
}
|
|
}
|
|
|
|
if (null === $center) {
|
|
return $this;
|
|
}
|
|
|
|
$this->centerHistory[] = new PersonCenterHistory($this, $center, $modification);
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setCenterHistory(Collection&Selectable $centerHistory): Person
|
|
{
|
|
$this->centerHistory = $centerHistory;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function addCenterHistory(PersonCenterHistory $newCenterHistory): self
|
|
{
|
|
if (!$this->centerHistory->contains($newCenterHistory)) {
|
|
$this->centerHistory[] = $newCenterHistory;
|
|
$newCenterHistory->setPerson($this);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setCFData(?array $cFData): self
|
|
{
|
|
$this->cFData = $cFData;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setCivility(?Civility $civility = null): self
|
|
{
|
|
$this->civility = $civility;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setcontactInfo($contactInfo): self
|
|
{
|
|
if (null === $contactInfo) {
|
|
$contactInfo = '';
|
|
}
|
|
|
|
$this->contactInfo = $contactInfo;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setCountryOfBirth(?Country $countryOfBirth = null): self
|
|
{
|
|
$this->countryOfBirth = $countryOfBirth;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setCreatedAt(\DateTimeInterface $datetime): self
|
|
{
|
|
$this->createdAt = $datetime;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setCreatedBy(User $createdBy): self
|
|
{
|
|
$this->createdBy = $createdBy;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setDeathdate(?\DateTimeInterface $deathdate): self
|
|
{
|
|
$this->deathdate = $deathdate;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setEmail(?string $email): self
|
|
{
|
|
$this->email = trim((string) $email);
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setFirstName(?string $firstName): self
|
|
{
|
|
$this->firstName = (string) $firstName;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setFullnameCanonical(?string $fullnameCanonical): self
|
|
{
|
|
$this->fullnameCanonical = $fullnameCanonical;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setGender(?Gender $gender): self
|
|
{
|
|
$this->gender = $gender;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setGenderComment(CommentEmbeddable $genderComment): self
|
|
{
|
|
$this->genderComment = $genderComment;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setLastName(?string $lastName): self
|
|
{
|
|
$this->lastName = (string) $lastName;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setMaritalStatus(?MaritalStatus $maritalStatus = null): self
|
|
{
|
|
$this->maritalStatus = $maritalStatus;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setMaritalStatusComment(CommentEmbeddable $maritalStatusComment): self
|
|
{
|
|
$this->maritalStatusComment = $maritalStatusComment;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setMaritalStatusDate(?\DateTimeInterface $maritalStatusDate): self
|
|
{
|
|
$this->maritalStatusDate = $maritalStatusDate;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setMemo(?string $memo): self
|
|
{
|
|
if (null === $memo) {
|
|
$memo = '';
|
|
}
|
|
|
|
if ($this->memo !== $memo) {
|
|
$this->memo = $memo;
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setMobilenumber(?PhoneNumber $mobilenumber): self
|
|
{
|
|
$this->mobilenumber = $mobilenumber;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setNationality(?Country $nationality = null): self
|
|
{
|
|
$this->nationality = $nationality;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setNumberOfChildren(?int $numberOfChildren): self
|
|
{
|
|
$this->numberOfChildren = $numberOfChildren;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setOtherPhoneNumbers(Collection $otherPhoneNumbers): self
|
|
{
|
|
$this->otherPhoneNumbers = $otherPhoneNumbers;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setPhonenumber(?PhoneNumber $phonenumber): self
|
|
{
|
|
$this->phonenumber = $phonenumber;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setPlaceOfBirth(?string $placeOfBirth): self
|
|
{
|
|
if (null === $placeOfBirth) {
|
|
$placeOfBirth = '';
|
|
}
|
|
|
|
$this->placeOfBirth = $placeOfBirth;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param (Collection<int, Language>) $spokenLanguages
|
|
*/
|
|
public function setSpokenLanguages(Collection $spokenLanguages): self
|
|
{
|
|
$this->spokenLanguages = $spokenLanguages;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setUpdatedAt(\DateTimeInterface $datetime): self
|
|
{
|
|
$this->updatedAt = $datetime;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setUpdatedBy(User $user): self
|
|
{
|
|
$this->updatedBy = $user;
|
|
|
|
return $this;
|
|
}
|
|
|
|
private function getCurrentCenterHistory(): ?PersonCenterHistory
|
|
{
|
|
if (0 === $this->centerHistory->count()) {
|
|
return null;
|
|
}
|
|
|
|
$criteria = Criteria::create();
|
|
$now = new \DateTimeImmutable('now');
|
|
$criteria->where(Criteria::expr()->lte('startDate', $now))
|
|
->andWhere(Criteria::expr()->orX(
|
|
Criteria::expr()->isNull('endDate'),
|
|
Criteria::expr()->gt('endDate', $now)
|
|
));
|
|
|
|
$histories = $this->centerHistory->matching($criteria);
|
|
|
|
return match ($histories->count()) {
|
|
0 => null,
|
|
1 => $histories->first(),
|
|
default => throw new \UnexpectedValueException('It should not contains more than one center at a time'),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* This private function scan accompanyingPeriodParticipations Collection,
|
|
* searching for a given AccompanyingPeriod.
|
|
*/
|
|
private function participationsContainAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod): ?AccompanyingPeriodParticipation
|
|
{
|
|
foreach ($this->accompanyingPeriodParticipations as $participation) {
|
|
/** @var AccompanyingPeriodParticipation $participation */
|
|
if ($participation->getAccompanyingPeriod() === $accompanyingPeriod) {
|
|
return $participation;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|