diff --git a/src/Bundle/ChillPersonBundle/Entity/Person.php b/src/Bundle/ChillPersonBundle/Entity/Person.php index a25f84fbb..464be5f31 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Person.php +++ b/src/Bundle/ChillPersonBundle/Entity/Person.php @@ -22,15 +22,17 @@ namespace Chill\PersonBundle\Entity; * along with this program. If not, see . */ -use Doctrine\ORM\Mapping as ORM; -use Doctrine\Common\Collections\Collection; -use Doctrine\Common\Collections\ArrayCollection; -use Doctrine\Common\Collections\Criteria; +use ArrayIterator; use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Entity\Country; use Chill\PersonBundle\Entity\MaritalStatus; use Chill\MainBundle\Entity\HasCenterInterface; use Chill\MainBundle\Entity\Address; +use DateTime; +use Doctrine\ORM\Mapping as ORM; +use Doctrine\Common\Collections\Collection; +use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Criteria; use Symfony\Component\Validator\Context\ExecutionContextInterface; /** @@ -1008,32 +1010,28 @@ class Person implements HasCenterInterface /** * By default, the addresses are ordered by date, descending (the most * recent first) - * - * @return \Chill\MainBundle\Entity\Address[] */ - public function getAddresses() + public function getAddresses(): ArrayCollection { return $this->addresses; } - /** - * @param \DateTime|null $date - * @return null - */ - public function getLastAddress(\DateTime $date = null) + public function getLastAddress(DateTime $from = null) { - if ($date === null) { - $date = new \DateTime('now'); - } + $from ??= new DateTime('now'); - $addresses = $this->getAddresses(); + /** @var ArrayIterator $addressesIterator */ + $addressesIterator = $this->getAddresses() + ->filter(static fn (Address $address): bool => $address->getValidFrom() <= $from) + ->getIterator(); - if ($addresses == null) { + $addressesIterator->uasort( + static fn (Address $left, Address $right): int => $right->getValidFrom() <=> $left->getValidFrom() + ); - return null; - } - - return $addresses->first(); + return [] === ($addresses = iterator_to_array($addressesIterator)) ? + null : + current($addresses); } /** diff --git a/src/Bundle/ChillPersonBundle/Tests/Entity/PersonTest.php b/src/Bundle/ChillPersonBundle/Tests/Entity/PersonTest.php index 139c2200b..b1e6d6971 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Entity/PersonTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Entity/PersonTest.php @@ -24,6 +24,10 @@ namespace Chill\PersonBundle\Tests\Entity; use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\AccompanyingPeriod; +use Chill\MainBundle\Entity\Address; +use DateInterval; +use DateTime; +use Generator; /** * Unit tests for the person Entity @@ -151,4 +155,54 @@ class PersonTest extends \PHPUnit\Framework\TestCase $this->assertEquals($r['result'], Person::ERROR_ADDIND_PERIOD_AFTER_AN_OPEN_PERIOD); } + + public function dateProvider(): Generator + { + yield [(DateTime::createFromFormat('Y-m-d', '2021-01-05'))->settime(0, 0)]; + yield [(DateTime::createFromFormat('Y-m-d', '2021-02-05'))->settime(0, 0)]; + yield [(DateTime::createFromFormat('Y-m-d', '2021-03-05'))->settime(0, 0)]; + } + + /** + * @dataProvider dateProvider + */ + public function testGetLastAddress(DateTime $date) + { + $p = new Person($date); + + // Make sure that there is no last address. + $this::assertNull($p->getLastAddress()); + + // Take an arbitrary date before the $date in parameter. + $addressDate = clone $date; + + // 1. Smoke test: Test that the first address added is the last one. + $address1 = (new Address())->setValidFrom($addressDate->sub(new DateInterval('PT180M'))); + $p->addAddress($address1); + + $this::assertCount(1, $p->getAddresses()); + $this::assertSame($address1, $p->getLastAddress()); + + // 2. Add an older address, which should not be the last address. + $addressDate2 = clone $addressDate; + $address2 = (new Address())->setValidFrom($addressDate2->sub(new DateInterval('PT30M'))); + $p->addAddress($address2); + + $this::assertCount(2, $p->getAddresses()); + $this::assertSame($address1, $p->getLastAddress()); + + // 3. Add a newer address, which should be the last address. + $addressDate3 = clone $addressDate; + $address3 = (new Address())->setValidFrom($addressDate3->add(new DateInterval('PT30M'))); + $p->addAddress($address3); + + $this::assertCount(3, $p->getAddresses()); + $this::assertSame($address3, $p->getLastAddress()); + + // 4. Get the last address from a specific date. + $this::assertEquals($address1, $p->getLastAddress($addressDate)); + $this::assertEquals($address2, $p->getLastAddress($addressDate2)); + $this::assertEquals($address3, $p->getLastAddress($addressDate3)); + } + }