<?php
namespace App\Entity;
use App\Entity\Club1895\Club1895Profile;
use App\Entity\Enum\PersonGender;
use App\Entity\Enum\ProfilingType;
use App\Entity\Traits\Identifiable;
use App\Repository\PersonRepository;
use DateInterval;
use DateTime;
use DateTimeImmutable;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use LogicException;
use Symfony\Component\Validator\Constraints\NotBlank;
#[ORM\Entity(repositoryClass: PersonRepository::class)]
class Person implements BenefactorPersonInterface, EmailableInterface
{
use Identifiable;
#[ORM\OneToOne(inversedBy: 'person', targetEntity: User::class, cascade: ['persist', 'remove'])]
private $user;
#[ORM\Column(type: 'string', length: 150, nullable: true)]
private $lastName;
#[ORM\Column(type: 'string', length: 150)]
#[NotBlank]
private $firstName;
#[ORM\Column(type: 'string', length: 10, nullable: true, enumType: PersonGender::class)]
private ?PersonGender $gender;
#[ORM\Column(type: 'string', length: 150, nullable: true)]
private $birthName;
#[ORM\Column(type: 'date_immutable', nullable: true)]
private $birthDate;
#[ORM\Column(type: 'string', length: 150, nullable: true)]
private $birthPlace;
#[ORM\Column(type: 'string', length: 100, nullable: true)]
private $birthCity;
#[ORM\Column(type: 'string', length: 100, nullable: true)]
private $birthCountry;
#[ORM\Column(type: 'string', length: 100, nullable: true)]
private $nationality;
#[ORM\Column(type: 'string', length: 150, nullable: true)]
private $profession;
#[ORM\Column(type: 'string', length: 150, nullable: true)]
private $school;
#[ORM\Embedded(PersonMeta::class, 'meta_')]
private $meta;
#[ORM\ManyToOne(targetEntity: Family::class, cascade: ['persist'], inversedBy: 'persons')]
#[ORM\JoinColumn(onDelete: 'SET NULL')]
private $family;
#[ORM\ManyToOne(targetEntity: ContactEmail::class, cascade: ['persist'], inversedBy: 'firstEmailPersons')]
#[ORM\JoinColumn(onDelete: 'SET NULL')]
private $firstEmail;
#[ORM\ManyToOne(targetEntity: ContactEmail::class, cascade: ['persist'], inversedBy: 'secondEmailPersons')]
#[ORM\JoinColumn(onDelete: 'SET NULL')]
private $secondEmail;
#[ORM\ManyToOne(targetEntity: ContactPhone::class, cascade: ['persist'], inversedBy: 'firstPhonePersons')]
#[ORM\JoinColumn(onDelete: 'SET NULL')]
private $firstPhone;
#[ORM\ManyToOne(targetEntity: ContactPhone::class, cascade: ['persist'], inversedBy: 'secondPhonePersons')]
#[ORM\JoinColumn(onDelete: 'SET NULL')]
private $secondPhone;
#[ORM\OneToMany(mappedBy: 'owner', targetEntity: ContactEmail::class, cascade: ['remove'])]
private $ownedEmails;
#[ORM\OneToMany(mappedBy: 'owner', targetEntity: ContactPhone::class, cascade: ['remove'])]
private $ownedPhones;
#[ORM\ManyToMany(targetEntity: self::class, inversedBy: 'tutors')]
#[ORM\JoinTable(name: 'tutors')]
#[ORM\JoinColumn('tutor_id', 'id')]
#[ORM\InverseJoinColumn('ward_id', 'id')]
private $wards;
#[ORM\ManyToMany(targetEntity: self::class, mappedBy: 'wards', cascade: ['persist'])]
private $tutors;
#[ORM\OneToMany(mappedBy: 'person', targetEntity: SectionPerson::class, cascade: ['persist', 'remove'])]
private $sectionPersons;
#[ORM\OneToMany(mappedBy: 'person', targetEntity: Coach::class, cascade: ['remove'])]
private $coaches;
#[ORM\OneToMany(mappedBy: 'signatory', targetEntity: Registration::class)]
private $signedRegistrations;
#[ORM\ManyToMany(targetEntity: Tag::class, mappedBy: 'persons')]
private $tags;
#[ORM\OneToMany(mappedBy: 'person', targetEntity: Registration::class, cascade: ['persist', 'remove'])]
private $registrations;
#[ORM\OneToMany(mappedBy: 'person', targetEntity: ProfilingPerson::class, cascade: ['persist', 'remove'])]
private $profilingPersons;
#[ORM\Column(type: 'boolean')]
private $isNew = true;
#[ORM\Column(type: 'integer', nullable: true)]
private $oldId;
#[ORM\OneToMany(mappedBy: 'owner', targetEntity: FilePerson::class, cascade: ['remove'])]
private $files;
#[ORM\Column(type: 'boolean')]
private $isCoach = false;
#[ORM\OneToMany(mappedBy: 'person', targetEntity: Debt::class)]
private $debts;
#[ORM\OneToMany(mappedBy: 'person', targetEntity: Donation::class)]
private Collection $donations;
#[ORM\Column(options: ['default' => false])]
private ?bool $benefactor = false;
#[ORM\OneToMany(mappedBy: 'relatedPerson', targetEntity: LegalPerson::class)]
private Collection $legalPersons;
#[ORM\OneToOne(mappedBy: 'person', cascade: ['persist', 'remove'])]
private ?Club1895Profile $club1895Profile = null;
#[ORM\Column(nullable: true)]
private ?bool $club1895Interested = null;
public function __construct()
{
$this->meta = new PersonMeta();
$this->wards = new ArrayCollection();
$this->tutors = new ArrayCollection();
$this->sectionPersons = new ArrayCollection();
$this->coaches = new ArrayCollection();
$this->signedRegistrations = new ArrayCollection();
$this->tags = new ArrayCollection();
$this->registrations = new ArrayCollection();
$this->profilingPersons = new ArrayCollection();
$this->files = new ArrayCollection();
$this->debts = new ArrayCollection();
$this->ownedEmails = new ArrayCollection();
$this->ownedPhones = new ArrayCollection();
$this->donations = new ArrayCollection();
$this->legalPersons = new ArrayCollection();
}
public function __toString(): string
{
return $this->getFullName(true);
}
public function getUser(): ?User
{
return $this->user;
}
public function setUser(?User $user): self
{
$this->user = $user;
return $this;
}
public function getLastName(): ?string
{
return $this->lastName ?? $this->getBirthName();
}
public function setLastName(?string $lastName): self
{
$this->lastName = $lastName;
return $this;
}
public function getFirstName(): ?string
{
return $this->firstName;
}
public function setFirstName(string $firstName): self
{
$this->firstName = $firstName;
return $this;
}
public function getGender(): ?PersonGender
{
return $this->gender;
}
public function setGender(?PersonGender $gender): self
{
$this->gender = $gender;
return $this;
}
public function getBirthDate(): ?DateTimeImmutable
{
return $this->birthDate;
}
public function getAge(): ?int
{
if (null === $this->getBirthDate()) {
return 18;
}
return $this->getBirthDate()?->diff(new DateTimeImmutable())->y;
}
public function setBirthDate(?DateTimeImmutable $birthDate): self
{
$this->birthDate = $birthDate;
return $this;
}
public function getBirthPlace(): ?string
{
return $this->birthPlace;
}
public function setBirthPlace(?string $birthPlace): self
{
$this->birthPlace = $birthPlace;
return $this;
}
public function getNationality(): ?string
{
return $this->nationality;
}
public function setNationality(?string $nationality): self
{
$this->nationality = $nationality;
return $this;
}
public function getProfession(): ?string
{
return $this->profession;
}
public function setProfession(?string $profession): self
{
$this->profession = $profession;
return $this;
}
public function getSchool(): ?string
{
return $this->school;
}
public function setSchool(?string $school): self
{
$this->school = $school;
return $this;
}
public function getFamily(): ?Family
{
return $this->family;
}
public function setFamily(?Family $family): self
{
$this->family = $family;
return $this;
}
public function getMeta(): ?PersonMeta
{
return $this->meta;
}
public function setMeta(PersonMeta $meta): self
{
$this->meta = $meta;
return $this;
}
public function getFirstEmail(): ?ContactEmail
{
return $this->firstEmail;
}
public function setFirstEmail(?ContactEmail $firstEmail): self
{
$this->firstEmail = $firstEmail;
if ($firstEmail && null === $firstEmail->getOwner()) {
$firstEmail->setOwner($this);
}
return $this;
}
public function getSecondEmail(): ?ContactEmail
{
return $this->secondEmail;
}
public function setSecondEmail(?ContactEmail $secondEmail): self
{
$this->secondEmail = $secondEmail;
if ($secondEmail && null === $secondEmail->getOwner()) {
$secondEmail->setOwner($this);
}
return $this;
}
public function getEmail(bool $ownedOnly = false): ?ContactEmail
{
if ($ownedOnly) {
if ($this->getFirstEmail()?->getOwner() === $this) {
return $this->getFirstEmail();
} elseif ($this->getSecondEmail()?->getOwner() === $this) {
return $this->getSecondEmail();
} else {
return null;
}
}
return $this->getFirstEmail() ?? $this->getSecondEmail();
}
/**
* @return Collection<int, ContactEmail>
*/
public function getEmails(): Collection
{
$emails = new ArrayCollection();
if ($this->getFirstEmail()) {
$emails->add($this->getFirstEmail());
}
if ($this->getSecondEmail()) {
$emails->add($this->getSecondEmail());
}
return $emails;
}
public function getValidEmail(): ?string
{
$contactEmail = $this->getEmail();
if ($contactEmail) {
return $contactEmail->getEmail();
}
foreach ($this->getTutors() as $tutor) {
if ($contactEmail = $tutor->getEmail()) {
return $contactEmail->getEmail();
}
}
return $this->getFamily()?->getResponsiblePerson()?->getEmail()?->getEmail();
}
public function getSimpleEmail(): ?string
{
return $this->getEmail()?->getEmail();
}
public function getFirstPhone(): ?ContactPhone
{
return $this->firstPhone;
}
public function setFirstPhone(?ContactPhone $firstPhone): self
{
$this->firstPhone = $firstPhone;
if ($firstPhone && null === $firstPhone->getOwner()) {
$firstPhone->setOwner($this);
}
return $this;
}
public function getSecondPhone(): ?ContactPhone
{
return $this->secondPhone;
}
public function setSecondPhone(?ContactPhone $secondPhone): self
{
$this->secondPhone = $secondPhone;
if ($secondPhone && null === $secondPhone->getOwner()) {
$secondPhone->setOwner($this);
}
return $this;
}
/**
* @return Collection<int, ContactPhone>
*/
public function getPhones(): Collection
{
$phones = new ArrayCollection();
if ($this->getFirstPhone()) {
$phones->add($this->getFirstPhone());
}
if ($this->getSecondPhone()) {
$phones->add($this->getSecondPhone());
}
return $phones;
}
/**
* @return Collection<int, ContactInterface>
*/
public function getContacts(): Collection
{
$contacts = new ArrayCollection();
foreach ($this->getEmails() as $email) {
$contacts->add($email);
}
foreach ($this->getPhones() as $phone) {
$contacts->add($phone);
}
return $contacts;
}
/**
* @return Collection<int, self>
*/
public function getWards(): Collection
{
return $this->wards;
}
public function addWard(self $ward): self
{
if (!$this->wards->contains($ward)) {
$this->wards[] = $ward;
}
return $this;
}
public function removeWard(self $ward): self
{
$this->wards->removeElement($ward);
return $this;
}
/**
* @param array|Person[] $wards
* @return Person
*/
public function setWards(array $wards): Person
{
$collection = new ArrayCollection();
foreach ($wards as $ward) {
if (!$collection->contains($ward)) {
$collection->add($ward);
}
}
$this->wards = $collection;
return $this;
}
/**
* @return Collection<int, self>
*/
public function getTutors(): Collection
{
return $this->tutors;
}
public function addTutor(self $tutor): self
{
if (!$this->tutors->contains($tutor)) {
$this->tutors[] = $tutor;
$tutor->addWard($this);
}
return $this;
}
public function removeTutor(self $tutor): self
{
if ($this->tutors->removeElement($tutor)) {
$tutor->removeWard($this);
}
return $this;
}
/**
* @param array|Person[] $tutors
* @return Person
*/
public function setTutors(array $tutors): Person
{
$collection = new ArrayCollection();
foreach ($tutors as $tutor) {
if (!$collection->contains($tutor)) {
$collection->add($tutor);
}
}
$this->tutors = $collection;
return $this;
}
public function getBirthCity(): ?string
{
return $this->birthCity;
}
public function setBirthCity(?string $birthCity): self
{
$this->birthCity = $birthCity;
return $this;
}
public function getBirthCountry(): ?string
{
return $this->birthCountry;
}
public function setBirthCountry(?string $birthCountry): self
{
$this->birthCountry = $birthCountry;
return $this;
}
/**
* @param Section|null $section
* @return Collection<int, SectionPerson>
*/
public function getSectionPersons(?Section $section = null): Collection
{
if ($section) {
return $this->sectionPersons->filter(
fn(SectionPerson $sectionPerson) => $sectionPerson->getSection() === $section
);
}
return $this->sectionPersons;
}
public function addSectionPerson(SectionPerson $sectionPerson): self
{
if (!$this->sectionPersons->contains($sectionPerson)) {
$this->sectionPersons[] = $sectionPerson;
$sectionPerson->setPerson($this);
}
return $this;
}
public function removeSectionPerson(SectionPerson $sectionPerson): self
{
if ($this->sectionPersons->removeElement($sectionPerson)) {
// set the owning side to null (unless already changed)
if ($sectionPerson->getPerson() === $this) {
$sectionPerson->setPerson(null);
}
}
return $this;
}
/**
* @return Collection<int, Coach>
*/
public function getCoaches(): Collection
{
return $this->coaches;
}
public function addCoach(Coach $coach): self
{
if (!$this->coaches->contains($coach)) {
$this->coaches[] = $coach;
$coach->setPerson($this);
}
return $this;
}
public function removeCoach(Coach $coach): self
{
if ($this->coaches->removeElement($coach)) {
// set the owning side to null (unless already changed)
if ($coach->getPerson() === $this) {
$coach->setPerson(null);
}
}
return $this;
}
/**
* @return Collection<int, Registration>
*/
public function getSignedRegistrations(): Collection
{
return $this->signedRegistrations;
}
public function addSignedRegistration(Registration $signedRegistration): self
{
if (!$this->signedRegistrations->contains($signedRegistration)) {
$this->signedRegistrations[] = $signedRegistration;
$signedRegistration->setSignatory($this);
}
return $this;
}
public function removeSignedRegistration(Registration $signedRegistration): self
{
if ($this->signedRegistrations->removeElement($signedRegistration)) {
// set the owning side to null (unless already changed)
if ($signedRegistration->getSignatory() === $this) {
$signedRegistration->setSignatory(null);
}
}
return $this;
}
/**
* @return Collection<int, Tag>
*/
public function getTags(): Collection
{
return $this->tags;
}
public function addTag(Tag $tag): self
{
if (!$this->tags->contains($tag)) {
$this->tags[] = $tag;
$tag->addPerson($this);
}
return $this;
}
public function removeTag(Tag $tag): self
{
if ($this->tags->removeElement($tag)) {
$tag->removePerson($this);
}
return $this;
}
/**
* @param array $tags
* @return Person
*/
public function setTags(array $tags): Person
{
$collection = new ArrayCollection();
foreach ($tags as $tag) {
$collection->add($tag);
}
$this->tags = $collection;
return $this;
}
/**
* @param Section|null $section
* @return Collection<int, Registration>
*/
public function getRegistrations(?Section $section = null): Collection
{
if (null === $section) {
return $this->registrations;
}
return $this->registrations->filter(fn(Registration $r) => $r->getSection() === $section);
}
public function getPreviousSeasonRegistrations()
{
}
public function addRegistration(Registration $registration): self
{
if (!$this->registrations->contains($registration)) {
$this->registrations[] = $registration;
$registration->setPerson($this);
}
return $this;
}
public function removeRegistration(Registration $registration): self
{
if ($this->registrations->removeElement($registration)) {
// set the owning side to null (unless already changed)
if ($registration->getPerson() === $this) {
$registration->setPerson(null);
}
}
return $this;
}
/**
* @param Section|null $section
* @return Collection<int, Registration>
*/
public function getActiveRegistrations(?Section $section = null): Collection
{
return $this->getRegistrations($section)->filter(fn(Registration $r) => $r->getSeason()->getIsActive());
}
/**
* @return Collection<int, ProfilingPerson>
*/
public function getProfilingPersons(): Collection
{
return $this->profilingPersons;
}
public function getSectionLevelPerson(Section $section, bool $activeSeason = true): ?ProfilingPerson
{
foreach ($this->getProfilingPersons() as $profilingPerson) {
if ($profilingPerson->getType() === ProfilingType::Level
&& $profilingPerson->getSeason()?->getSection() === $section) {
if ($activeSeason && $profilingPerson->getSeason()?->getIsActive()) {
return $profilingPerson;
}
if (!$activeSeason && $profilingPerson->getSeason()?->getNextSeason()?->getIsActive()) {
return $profilingPerson;
}
}
}
return null;
}
public function getSectionProfilingPerson(Section $section): ?ProfilingPerson
{
foreach ($this->getProfilingPersons() as $profilingPerson) {
if ($profilingPerson->getType() === ProfilingType::Profiling
&& $profilingPerson->getSeason()?->getIsActive()
&& $profilingPerson->getSeason()?->getSection() === $section) {
return $profilingPerson;
}
}
return null;
}
public function addProfilingPerson(ProfilingPerson $profilingPerson): self
{
if (!$this->profilingPersons->contains($profilingPerson)) {
$this->profilingPersons[] = $profilingPerson;
$profilingPerson->setPerson($this);
}
return $this;
}
public function removeProfilingPerson(ProfilingPerson $profilingPerson): self
{
if ($this->profilingPersons->removeElement($profilingPerson)) {
// set the owning side to null (unless already changed)
if ($profilingPerson->getPerson() === $this) {
$profilingPerson->setPerson(null);
}
}
return $this;
}
public function getBirthName(): ?string
{
return $this->birthName;
}
public function setBirthName(?string $birthName): self
{
$this->birthName = $birthName;
return $this;
}
public function getFullName(bool $capitalize = false): string
{
return sprintf(
'%s %s',
$this->getFirstName(),
$capitalize ? mb_strtoupper($this->getLastName()) : $this->getLastName()
);
}
/**
* @return bool
* @throws LogicException
*/
public function isMinor(): bool
{
if (null === $this->getBirthDate()) {
return false;
}
$date = (new DateTime())->sub(new DateInterval('P18Y'));
return $this->getBirthDate() > $date;
}
public function isIsNew(): ?bool
{
return $this->isNew;
}
public function setIsNew(bool $isNew): self
{
$this->isNew = $isNew;
return $this;
}
public function getOldId(): ?int
{
return $this->oldId;
}
public function setOldId(?int $oldId): self
{
$this->oldId = $oldId;
return $this;
}
/**
* @return Collection<int, FilePerson>
*/
public function getFiles(): Collection
{
return $this->files;
}
public function addFile(FilePerson $file): self
{
if (!$this->files->contains($file)) {
$this->files[] = $file;
$file->setOwner($this);
}
return $this;
}
public function removeFile(FilePerson $file): self
{
if ($this->files->removeElement($file)) {
// set the owning side to null (unless already changed)
if ($file->getOwner() === $this) {
$file->setOwner(null);
}
}
return $this;
}
public function isIsCoach(): ?bool
{
return $this->isCoach;
}
public function setIsCoach(bool $isCoach): self
{
$this->isCoach = $isCoach;
return $this;
}
/**
* @param Section|null $section
* @return Collection<int, Debt>
*/
public function getDebts(?Section $section = null): Collection
{
if ($section) {
return $this->debts->filter(fn(Debt $debt) => $debt->getSection()?->getId() === $section->getId());
}
return $this->debts;
}
public function addDebt(Debt $debt): self
{
if (!$this->debts->contains($debt)) {
$this->debts[] = $debt;
$debt->setPerson($this);
}
return $this;
}
public function removeDebt(Debt $debt): self
{
if ($this->debts->removeElement($debt)) {
// set the owning side to null (unless already changed)
if ($debt->getPerson() === $this) {
$debt->setPerson(null);
}
}
return $this;
}
/**
* @return Collection<int, ContactEmail>
*/
public function getOwnedEmails(): Collection
{
return $this->ownedEmails;
}
public function addOwnedEmail(ContactEmail $ownedEmail): self
{
if (!$this->ownedEmails->contains($ownedEmail)) {
$this->ownedEmails[] = $ownedEmail;
$ownedEmail->setOwner($this);
}
return $this;
}
public function removeOwnedEmail(ContactEmail $ownedEmail): self
{
if ($this->ownedEmails->removeElement($ownedEmail)) {
// set the owning side to null (unless already changed)
if ($ownedEmail->getOwner() === $this) {
$ownedEmail->setOwner(null);
}
}
return $this;
}
/**
* @return Collection<int, ContactPhone>
*/
public function getOwnedPhones(): Collection
{
return $this->ownedPhones;
}
public function addOwnedPhone(ContactPhone $ownedPhone): self
{
if (!$this->ownedPhones->contains($ownedPhone)) {
$this->ownedPhones[] = $ownedPhone;
$ownedPhone->setOwner($this);
}
return $this;
}
public function removeOwnedPhone(ContactPhone $ownedPhone): self
{
if ($this->ownedPhones->removeElement($ownedPhone)) {
// set the owning side to null (unless already changed)
if ($ownedPhone->getOwner() === $this) {
$ownedPhone->setOwner(null);
}
}
return $this;
}
/**
* @return Collection<int, Donation>
*/
public function getDonations(): Collection
{
return $this->donations;
}
public function addDonation(Donation $donation): self
{
if (!$this->donations->contains($donation)) {
$this->donations->add($donation);
$donation->setPerson($this);
}
return $this;
}
public function removeDonation(Donation $donation): self
{
if ($this->donations->removeElement($donation)) {
// set the owning side to null (unless already changed)
if ($donation->getPerson() === $this) {
$donation->setPerson(null);
}
}
return $this;
}
public function isBenefactor(): ?bool
{
return $this->benefactor;
}
public function setBenefactor(bool $benefactor): self
{
$this->benefactor = $benefactor;
return $this;
}
/**
* @return Collection<int, LegalPerson>
*/
public function getLegalPersons(): Collection
{
return $this->legalPersons;
}
public function addLegalPerson(LegalPerson $legalPerson): self
{
if (!$this->legalPersons->contains($legalPerson)) {
$this->legalPersons->add($legalPerson);
$legalPerson->setRelatedPerson($this);
}
return $this;
}
public function removeLegalPerson(LegalPerson $legalPerson): self
{
if ($this->legalPersons->removeElement($legalPerson)) {
// set the owning side to null (unless already changed)
if ($legalPerson->getRelatedPerson() === $this) {
$legalPerson->setRelatedPerson(null);
}
}
return $this;
}
public function getClub1895Profile(): ?Club1895Profile
{
return $this->club1895Profile;
}
public function setClub1895Profile(Club1895Profile $club1895Profile): self
{
// set the owning side of the relation if necessary
if ($club1895Profile->getPerson() !== $this) {
$club1895Profile->setPerson($this);
}
$this->club1895Profile = $club1895Profile;
return $this;
}
public function isClub1895Interested(): ?bool
{
return $this->club1895Interested;
}
public function setClub1895Interested(?bool $club1895Interested): self
{
$this->club1895Interested = $club1895Interested;
return $this;
}
}