Add phone number search function to PersonACLAwareRepository

A new function, findByPhone, has been added to the PersonACLAwareRepository. This function allows searching for people based on their phone numbers. Changes also reflect in the PersonACLAwareRepositoryInterface, and new test cases have been added to the PersonACLAwareRepositoryTest.
This commit is contained in:
Julien Fastré 2024-04-16 14:41:55 +02:00
parent 5832542978
commit 912fdd6349
Signed by: julienfastre
GPG Key ID: BDE2190974723FCB
3 changed files with 101 additions and 0 deletions

View File

@ -21,6 +21,8 @@ use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\NonUniqueResultException;
use Doctrine\ORM\Query;
use libphonenumber\PhoneNumber;
use libphonenumber\PhoneNumberFormat;
use Symfony\Component\Security\Core\Security;
final readonly class PersonACLAwareRepository implements PersonACLAwareRepositoryInterface
@ -298,4 +300,27 @@ final readonly class PersonACLAwareRepository implements PersonACLAwareRepositor
\array_map(static fn (Center $c) => $c->getId(), $authorizedCenters)
);
}
public function findByPhone(PhoneNumber $phoneNumber, int $start = 0, int $limit = 20): array
{
$authorizedCenters = $this->authorizationHelper
->getReachableCenters($this->security->getUser(), PersonVoter::SEE);
if ([] === $authorizedCenters) {
return [];
}
$util = \libphonenumber\PhoneNumberUtil::getInstance();
return $this->em->createQuery(
'SELECT p FROM '.Person::class.' p LEFT JOIN p.otherPhoneNumbers opn JOIN p.centerCurrent pcc '.
'WHERE (p.phonenumber LIKE :phone OR p.mobilenumber LIKE :phone OR opn.phonenumber LIKE :phone) '.
'AND pcc.center IN (:centers)'
)
->setMaxResults($limit)
->setFirstResult($start)
->setParameter('phone', $util->format($phoneNumber, PhoneNumberFormat::E164))
->setParameter('centers', $authorizedCenters)
->getResult();
}
}

View File

@ -13,6 +13,7 @@ namespace Chill\PersonBundle\Repository;
use Chill\MainBundle\Search\SearchApiQuery;
use Chill\PersonBundle\Entity\Person;
use libphonenumber\PhoneNumber;
interface PersonACLAwareRepositoryInterface
{
@ -60,4 +61,13 @@ interface PersonACLAwareRepositoryInterface
?string $phonenumber = null,
?string $city = null
): array;
/**
* @return list<Person>
*/
public function findByPhone(
PhoneNumber $phoneNumber,
int $start = 0,
int $limit = 20
): array;
}

View File

@ -11,14 +11,17 @@ declare(strict_types=1);
namespace Chill\PersonBundle\Tests\Repository;
use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Repository\CenterRepositoryInterface;
use Chill\MainBundle\Repository\CountryRepository;
use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Entity\PersonPhone;
use Chill\PersonBundle\Repository\PersonACLAwareRepository;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\Attributes\DataProvider;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
@ -98,4 +101,67 @@ final class PersonACLAwareRepositoryTest extends KernelTestCase
$this->assertStringContainsString('diallo', strtolower($person->getFirstName().' '.$person->getLastName()));
}
}
/**
* @dataProvider providePersonsWithPhoneNumbers
*/
public function testFindByPhonenumber(\libphonenumber\PhoneNumber $phoneNumber, ?int $expectedId): void
{
$user = new User();
$authorizationHelper = $this->prophesize(AuthorizationHelperInterface::class);
$authorizationHelper->getReachableCenters(Argument::exact($user), Argument::exact(PersonVoter::SEE))
->willReturn($this->centerRepository->findAll());
$security = $this->prophesize(Security::class);
$security->getUser()->willReturn($user);
$repository = new PersonACLAwareRepository(
$security->reveal(),
$this->entityManager,
$this->countryRepository,
$authorizationHelper->reveal()
);
$actual = $repository->findByPhone($phoneNumber, 0, 10);
if (null === $expectedId) {
self::assertCount(0, $actual);
} else {
$actualIds = array_map(fn (Person $person) => $person->getId(), $actual);
self::assertContains($expectedId, $actualIds);
}
}
public static function providePersonsWithPhoneNumbers(): iterable
{
self::bootKernel();
$em = self::getContainer()->get(EntityManagerInterface::class);
$center = $em->createQuery('SELECT c FROM '.Center::class.' c ')->setMaxResults(1)
->getSingleResult();
$util = \libphonenumber\PhoneNumberUtil::getInstance();
$mobile = $util->parse('+32486123456');
$fixed = $util->parse('+3281136917');
$anotherMobile = $util->parse('+32486123478');
$person = (new Person())->setFirstName('diallo')->setLastName('diallo')->setCenter($center);
$person->setMobilenumber($mobile)->setPhonenumber($fixed);
$otherPhone = new PersonPhone();
$otherPhone->setPerson($person);
$otherPhone->setPhonenumber($anotherMobile);
$otherPhone->setType('mobile');
$em->persist($person);
$em->persist($otherPhone);
$em->flush();
self::ensureKernelShutdown();
yield [$mobile, $person->getId()];
yield [$anotherMobile, $person->getId()];
yield [$fixed, $person->getId()];
yield [$util->parse('+331234567890'), null];
}
}