diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodController.php index 6b6e4dda9..2b51e9191 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodController.php @@ -88,12 +88,12 @@ class AccompanyingPeriodController extends AbstractController $this->denyAccessUnlessGranted(PersonVoter::UPDATE, $person, 'You are not allowed to update this person'); - $accompanyingPeriod = new AccompanyingPeriod(new \DateTime()); - $accompanyingPeriod->setClosingDate(new \DateTime()); - - $person->addAccompanyingPeriod( - $accompanyingPeriod); - + $accompanyingPeriod = new AccompanyingPeriod(new \DateTimeImmutable('now')); + $accompanyingPeriod->setClosingDate(new \DateTimeImmutable('now')); + + $accompanyingPeriod->addPerson($person); + //or $person->addAccompanyingPeriod($accompanyingPeriod); + $form = $this->createForm( AccompanyingPeriodType::class, $accompanyingPeriod, [ @@ -153,8 +153,9 @@ class AccompanyingPeriodController extends AbstractController } /** @var Person $person */ - $person = $em->getRepository(Person::class)->find($person_id); + $person = $this->_getPerson($person_id); + // CHECK if (! $accompanyingPeriod->containsPerson($person)) { throw new Exception("Accompanying period " . $period_id . " does not contain person " . $person_id); } diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php index 29355b5b8..915500392 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php @@ -35,7 +35,7 @@ use Chill\MainBundle\Entity\User; /** * AccompanyingPeriod Class * - * @ORM\Entity(repositoryClass=AccompanyingPeriodRepository::class) + * @ORM\Entity(repositoryClass="Chill\PersonBundle\Repository\AccompanyingPeriodRepository") * @ORM\Table(name="chill_person_accompanying_period") */ class AccompanyingPeriod @@ -79,9 +79,10 @@ class AccompanyingPeriod * @var Collection * * @ORM\OneToMany(targetEntity=AccompanyingPeriodParticipation::class, - * mappedBy="accompanyingPeriod") + * mappedBy="accompanyingPeriod", + * cascade={"persist", "remove", "merge", "detach"}) */ - private $persons; + private $participations; /** * @var AccompanyingPeriod\ClosingMotive @@ -175,7 +176,7 @@ class AccompanyingPeriod */ public function __construct(\DateTime $dateOpening) { $this->setOpeningDate($dateOpening); - $this->persons = new ArrayCollection(); + $this->participations = new ArrayCollection(); $this->scopes = new ArrayCollection(); } @@ -280,37 +281,63 @@ class AccompanyingPeriod { return $this->remark; } - - public function getPersons(): Collection - { - return $this->persons; - } - public function containsPerson(Person $person): bool + /** + * Get Participations Collection + */ + public function getParticipations(): Collection { - foreach ($this->persons as $p) { - if ($p === $person) { return true; } - } - - return false; + return $this->participations; } /** - * For consistency, you should use Person::addAccompanyingPeriod instead. - * @see Person::addAccompanyingPeriod + * This private function scan Participations Collection, + * searching for a given Person + */ + private function participationsContainsPerson(Person $person): ?AccompanyingPeriodParticipation + { + foreach ($this->participations as $participation) { + /** @var AccompanyingPeriodParticipation $participation */ + if ($person === $participation->getPerson()) { + return $participation; + }} + + return null; + } + + /** + * This public function is the same but return only true or false + */ + public function containsPerson(Person $person): bool + { + return ($this->participationsContainsPerson($person) === null) ? false : true; + } + + /** + * Add Person */ public function addPerson(Person $person = null): self { - $this->persons[] = $person; + $participation = new AccompanyingPeriodParticipation($this, $person); + $this->participations[] = $participation; return $this; } + /** + * Remove Person + */ public function removePerson(Person $person): void { - $this->persons->removeElement($person); + $participation = $this->participationsContainsPerson($person); + + if (! null === $participation) { + $participation->setEndDate(new \DateTimeImmutable('now')); + $this->participations->removeElement($participation); + } } + public function getClosingMotive(): ?ClosingMotive { return $this->closingMotive; @@ -335,11 +362,12 @@ class AccompanyingPeriod return false; } - foreach ($this->getPersons() as $p) { - if ($p === $person) { - $periods = $p->getAccompanyingPeriodsOrdered(); - return end($periods) === $this; - } + $participation = $this->participationsContainsPerson($person); + if (!null === $participation) + { + $person = $participation->getPerson(); + $periods = $person->getAccompanyingPeriodsOrdered(); + return end($periods) === $this; } return false; diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriodParticipation.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriodParticipation.php index 4a2fe3b44..9a807b179 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriodParticipation.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriodParticipation.php @@ -44,22 +44,81 @@ class AccompanyingPeriodParticipation private $id; /** - * @ORM\ManyToOne(targetEntity=Person::class, - * inversedBy="accompanyingPeriods") + * @ORM\ManyToOne(targetEntity=Person::class, inversedBy="accompanyingPeriodParticipations") * @ORM\JoinColumn(name="person_id", referencedColumnName="id", nullable=false) */ private $person; /** - * @ORM\ManyToOne(targetEntity=AccompanyingPeriod::class, - * inversedBy="persons") + * @ORM\ManyToOne(targetEntity=AccompanyingPeriod::class, inversedBy="participations") * @ORM\JoinColumn(name="accompanyingperiod_id", referencedColumnName="id", nullable=false) */ private $accompanyingPeriod; + /** + * @ORM\Column(type="date", nullable=false) + */ + private $startDate; + + /** + * @ORM\Column(type="date", nullable=true) + */ + private $endDate = null; + + public function __construct(AccompanyingPeriod $accompanyingPeriod, Person $person) + { + $this->startDate = new \DateTimeImmutable('now'); + $this->accompanyingPeriod = $accompanyingPeriod; + $this->person = $person; + } public function getId(): ?int { return $this->id; } + + public function getPerson(): ?Person + { + return $this->person; + } + + public function setPerson(?Person $person): self + { + $this->person = $person; + + return $this; + } + + public function getAccompanyingPeriod(): ?AccompanyingPeriod + { + return $this->accompanyingPeriod; + } + + public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self + { + $this->accompanyingPeriod = $accompanyingPeriod; + + return $this; + } + + public function getStartDate(): ?\DateTimeInterface + { + return $this->startDate; + } + + /* + * public function setStartDate(\DateTimeInterface $startDate): self { $this->startDate = $startDate; return $this; } + */ + + public function getEndDate(): ?\DateTimeInterface + { + return $this->endDate; + } + + public function setEndDate(?\DateTimeInterface $endDate): self + { + $this->endDate = $endDate; + + return $this; + } } diff --git a/src/Bundle/ChillPersonBundle/Entity/Person.php b/src/Bundle/ChillPersonBundle/Entity/Person.php index bd89fbcea..e3a01a055 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Person.php +++ b/src/Bundle/ChillPersonBundle/Entity/Person.php @@ -209,7 +209,7 @@ class Person implements HasCenterInterface * mappedBy="person", * cascade={"persist", "remove", "merge", "detach"}) */ - private $accompanyingPeriods; + private $accompanyingPeriodParticipations; /** * A remark over the person @@ -262,7 +262,7 @@ class Person implements HasCenterInterface */ public function __construct(\DateTime $opening = null) { - $this->accompanyingPeriods = new ArrayCollection(); + $this->accompanyingPeriodParticipations = new ArrayCollection(); $this->spokenLanguages = new ArrayCollection(); $this->addresses = new ArrayCollection(); $this->altNames = new ArrayCollection(); @@ -273,16 +273,39 @@ class Person implements HasCenterInterface $this->open(new AccompanyingPeriod($opening)); } - + /** - * Add AccompanyingPeriod + * 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 ($accompanyingPeriod === $participation->getAccompanyingPeriod()) { + return $participation; + }} + + return null; + } + + /** + * This public function is the same but return only true or false + */ + public function containsAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod): bool + { + return ($this->participationsContainAccompanyingPeriod($accompanyingPeriod)) ? false : true; + } + + /** + * Add AccompanyingPeriodParticipation * * @uses AccompanyingPeriod::addPerson */ public function addAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod): self { - $accompanyingPeriod->addPerson($this); - $this->accompanyingPeriods->add($accompanyingPeriod); + $participation = new AccompanyingPeriodParticipation($accompanyingPeriod, $this); + $this->accompanyingPeriodParticipations->add($participation); return $this; } @@ -292,7 +315,12 @@ class Person implements HasCenterInterface */ public function removeAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod) : void { - $this->accompanyingPeriods->remove($accompanyingPeriod); + $participation = $this->participationsContainAccompanyingPeriod($accompanyingPeriod); + + if (! null === $participation) { + $participation->setEndDate(\DateTimeImmutable::class); + $this->accompanyingPeriodParticipations->removeElement($participation); + } } /** @@ -335,9 +363,10 @@ class Person implements HasCenterInterface return null; } - foreach ($this->accompanyingPeriods as $period) { - if ($period->isOpen()) { - return $period; + foreach ($this->accompanyingPeriodParticipations as $participation) { + /** @var AccompanyingPeriodParticipation $participation */ + if ($participation->getAccompanyingPeriod()->isOpen()) { + return $participation->getAccompanyingPeriod(); } } } @@ -353,19 +382,33 @@ class Person implements HasCenterInterface } /** - * Get AccompanyingPeriods Collection + * Get AccompanyingPeriods array */ - public function getAccompanyingPeriods() : Collection + public function getAccompanyingPeriods(): array { - return $this->accompanyingPeriods; + $accompanyingPeriods = []; + foreach ($this->accompanyingPeriodParticipations as $participation) + { + /** @var AccompanyingPeriodParticipation $participation */ + $accompanyingPeriods[] = $participation->getAccompanyingPeriod(); + } + return $accompanyingPeriods; + } + + /** + * Get AccompanyingPeriodParticipations Collection + */ + public function getAccompanyingPeriodParticipations(): Collection + { + return $this->accompanyingPeriodParticipations; } /** * Get the accompanying periods of a give person with the chronological order. */ - public function getAccompanyingPeriodsOrdered() : array + public function getAccompanyingPeriodsOrdered(): array { - $periods = $this->getAccompanyingPeriods()->toArray(); + $periods = $this->getAccompanyingPeriods(); //order by date : usort($periods, function($a, $b) { @@ -504,7 +547,7 @@ class Person implements HasCenterInterface * @param PersonAltName $altName * @return $this */ - public function removeAltName(PersonAltName $altName) + public function removeAltName(PersonAltName $altName) { if ($this->altNames->contains($altName)) { $altName->setPerson(null); diff --git a/src/Bundle/ChillPersonBundle/config/services/repository.yaml b/src/Bundle/ChillPersonBundle/config/services/repository.yaml index 50209b010..8cfaa8471 100644 --- a/src/Bundle/ChillPersonBundle/config/services/repository.yaml +++ b/src/Bundle/ChillPersonBundle/config/services/repository.yaml @@ -12,3 +12,9 @@ services: factory: ['@doctrine.orm.entity_manager', getRepository] arguments: - 'Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive' + + Chill\PersonBundle\Repository\AccompanyingPeriodRepository: + class: Chill\PersonBundle\Repository\AccompanyingPeriodRepository + tags: [ doctrine.repository_service ] + arguments: + - '@Doctrine\Persistence\ManagerRegistry' diff --git a/src/Bundle/ChillPersonBundle/config/validation.yaml b/src/Bundle/ChillPersonBundle/config/validation.yaml index 814db0ee4..ba6d6b84d 100644 --- a/src/Bundle/ChillPersonBundle/config/validation.yaml +++ b/src/Bundle/ChillPersonBundle/config/validation.yaml @@ -27,9 +27,9 @@ Chill\PersonBundle\Entity\Person: gender: - NotNull: groups: [general, creation] - accompanyingPeriods: - - Valid: - traverse: true + #accompanyingPeriods: + # - Valid: + # traverse: true email: - Email: groups: [general, creation] diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210331084527.php b/src/Bundle/ChillPersonBundle/migrations/Version20210331084527.php index c42da9874..9c379c4b0 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210331084527.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210331084527.php @@ -24,12 +24,16 @@ final class Version20210331084527 extends AbstractMigration $this->addSql('ALTER TABLE persons_accompanying_periods RENAME TO chill_person_accompanying_period_participation'); // 2 - // NOT NECCESSARY $this->addSql('CREATE SEQUENCE chill_person_accompanying_period_participation_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); + // SERIAL automatically create sequence with NEXTVAL() $this->addSql('ALTER TABLE chill_person_accompanying_period_participation ADD COLUMN id SERIAL NOT NULL PRIMARY KEY'); - // TO CHECK !! automatically complete missing values allowing not null clause - // but add strange "id serial (10) default nextval('chill_person_accompanying_period_participation_id_seq':: regclass )" in column definition + // drop NEXTVAL() in column definition + $this->addSql('ALTER TABLE chill_person_accompanying_period_participation ALTER id DROP DEFAULT'); // 3 + $this->addSql('ALTER TABLE chill_person_accompanying_period_participation ADD startDate DATE NOT NULL DEFAULT \'1970-01-01\''); + $this->addSql('ALTER TABLE chill_person_accompanying_period_participation ADD endDate DATE DEFAULT NULL'); + + // 4 $this->addSql('ALTER TABLE chill_person_accompanying_period_participation DROP CONSTRAINT fk_49a3871f217bbb47'); $this->addSql('ALTER TABLE chill_person_accompanying_period_participation DROP CONSTRAINT fk_49a3871f550b0c53'); $this->addSql('ALTER TABLE chill_person_accompanying_period_participation ADD CONSTRAINT FK_A59DF89F217BBB47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); @@ -40,7 +44,7 @@ final class Version20210331084527 extends AbstractMigration public function down(Schema $schema) : void { - // 3 + // 4 $this->addSql('ALTER TABLE chill_person_accompanying_period_participation DROP CONSTRAINT FK_A59DF89F217BBB47'); $this->addSql('ALTER TABLE chill_person_accompanying_period_participation DROP CONSTRAINT FK_A59DF89F550B0C53'); $this->addSql('ALTER TABLE chill_person_accompanying_period_participation ADD CONSTRAINT fk_49a3871f217bbb47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); @@ -48,6 +52,10 @@ final class Version20210331084527 extends AbstractMigration $this->addSql('ALTER INDEX idx_a59df89f550b0c53 RENAME TO idx_49a3871f550b0c53'); $this->addSql('ALTER INDEX idx_a59df89f217bbb47 RENAME TO idx_49a3871f217bbb47'); + // 3 + $this->addSql('ALTER TABLE chill_person_accompanying_period_participation DROP startDate'); + $this->addSql('ALTER TABLE chill_person_accompanying_period_participation DROP endDate'); + // 2 $this->addSql('DROP SEQUENCE chill_person_accompanying_period_participation_id_seq CASCADE'); $this->addSql('ALTER TABLE chill_person_accompanying_period_participation DROP id');