mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-18 08:14:24 +00:00
Add functionality to find a caller by phone number
Added a new method in PersonRepository to allow querying people by phone number. Also, a new REST API endpoint "/public/api/1.0/ticket/find-caller" was introduced and it can find a caller by their phone number. Accompanied this feature addition with corresponding test cases.
This commit is contained in:
parent
66dc603c85
commit
78d1776733
@ -12,10 +12,12 @@ declare(strict_types=1);
|
||||
namespace Chill\PersonBundle\Repository;
|
||||
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Chill\PersonBundle\Entity\PersonPhone;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Doctrine\Persistence\ObjectRepository;
|
||||
use libphonenumber\PhoneNumber;
|
||||
|
||||
class PersonRepository implements ObjectRepository
|
||||
{
|
||||
@ -29,6 +31,8 @@ class PersonRepository implements ObjectRepository
|
||||
/**
|
||||
* @throws \Doctrine\ORM\NoResultException
|
||||
* @throws \Doctrine\ORM\NonUniqueResultException
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public function countByPhone(
|
||||
string $phonenumber,
|
||||
@ -71,6 +75,8 @@ class PersonRepository implements ObjectRepository
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*
|
||||
* @deprecated Use @see{self::findByPhoneNumber} or use a dedicated method in PersonACLAwareRepository
|
||||
*/
|
||||
public function findByPhone(
|
||||
string $phonenumber,
|
||||
@ -91,6 +97,25 @@ class PersonRepository implements ObjectRepository
|
||||
return $qb->getQuery()->getResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a person which is associated to the given phonenumber, without restrictions
|
||||
* on any.
|
||||
*
|
||||
* @return list<Person
|
||||
*/
|
||||
public function findByPhoneNumber(PhoneNumber $phoneNumber, int $firstResult = 0, int $maxResults = 50): array
|
||||
{
|
||||
$qb = $this->repository->createQueryBuilder('p');
|
||||
$qb->select('p');
|
||||
|
||||
$this->searchByPhoneNumbers($qb, $phoneNumber);
|
||||
|
||||
$qb->setFirstResult($firstResult)
|
||||
->setMaxResults($maxResults);
|
||||
|
||||
return $qb->getQuery()->getResult();
|
||||
}
|
||||
|
||||
public function findOneBy(array $criteria)
|
||||
{
|
||||
return $this->repository->findOneBy($criteria);
|
||||
@ -109,6 +134,20 @@ class PersonRepository implements ObjectRepository
|
||||
}
|
||||
}
|
||||
|
||||
private function searchByPhoneNumbers(QueryBuilder $qb, PhoneNumber $phoneNumber): void
|
||||
{
|
||||
$qb->setParameter('number', $phoneNumber, 'phone_number');
|
||||
|
||||
$orX = $qb->expr()->orX();
|
||||
$orX->add($qb->expr()->eq('p.mobilenumber', ':number'));
|
||||
$orX->add($qb->expr()->eq('p.phonenumber', ':number'));
|
||||
$orX->add(
|
||||
$qb->expr()->exists('SELECT 1 FROM '.PersonPhone::class.' k WHERE k.phonenumber = :number AND k.person = p')
|
||||
);
|
||||
|
||||
$qb->andWhere($orX);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
|
@ -0,0 +1,58 @@
|
||||
<?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\TicketBundle\Controller;
|
||||
|
||||
use Chill\MainBundle\Phonenumber\PhonenumberHelper;
|
||||
use Chill\PersonBundle\Repository\PersonRepository;
|
||||
use Chill\PersonBundle\Templating\Entity\PersonRenderInterface;
|
||||
use libphonenumber\NumberParseException;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
/**
|
||||
* Controller for a rest api to find a caller for a given phonenumber.
|
||||
*
|
||||
* TODO: currently, this rest api is not secured
|
||||
*/
|
||||
class FindCallerController
|
||||
{
|
||||
public function __construct(private PhonenumberHelper $phonenumberHelper, private PersonRepository $personRepository, private PersonRenderInterface $personRender) {}
|
||||
|
||||
#[Route('/public/api/1.0/ticket/find-caller', name: 'find-caller', methods: ['GET'])]
|
||||
public function findCaller(Request $request): Response
|
||||
{
|
||||
$caller = $request->query->get('caller', '');
|
||||
|
||||
if ('' === $caller) {
|
||||
throw new BadRequestHttpException('Missing "caller" query parameter');
|
||||
}
|
||||
|
||||
try {
|
||||
$phoneNumber = $this->phonenumberHelper->parse($caller);
|
||||
} catch (NumberParseException $e) {
|
||||
throw new BadRequestHttpException('Unable to parse number', $e);
|
||||
}
|
||||
|
||||
$persons = $this->personRepository->findByPhoneNumber($phoneNumber, 0, 2);
|
||||
|
||||
$asArray = match (count($persons)) {
|
||||
0 => ['found' => false, 'name' => null],
|
||||
1 => ['found' => true, 'name' => $this->personRender->renderString($persons[0], ['addAge' => false])],
|
||||
default => ['found' => true, 'name' => 'multiple'],
|
||||
};
|
||||
|
||||
return new JsonResponse($asArray);
|
||||
}
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
<?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\TicketBundle\Tests\Controller;
|
||||
|
||||
use Chill\MainBundle\Phonenumber\PhonenumberHelper;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Chill\PersonBundle\Repository\PersonRepository;
|
||||
use Chill\PersonBundle\Templating\Entity\PersonRenderInterface;
|
||||
use Chill\TicketBundle\Controller\FindCallerController;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Prophecy\Argument;
|
||||
use Prophecy\PhpUnit\ProphecyTrait;
|
||||
use Psr\Log\NullLogger;
|
||||
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @coversNothing
|
||||
*/
|
||||
class FindCallerControllerTest extends TestCase
|
||||
{
|
||||
use ProphecyTrait;
|
||||
|
||||
/**
|
||||
* @dataProvider provideFindCaller
|
||||
*/
|
||||
public function testFindCaller(string $caller, array $persons, array $expected): void
|
||||
{
|
||||
$controller = $this->buildController($persons);
|
||||
|
||||
$request = new Request(query: ['caller' => $caller]);
|
||||
|
||||
$response = $controller->findCaller($request);
|
||||
|
||||
$actual = json_decode($response->getContent(), true);
|
||||
|
||||
self::assertEqualsCanonicalizing($expected, $actual);
|
||||
}
|
||||
|
||||
public function testFindCallerWithoutCallerArgument(): void
|
||||
{
|
||||
self::expectException(BadRequestHttpException::class);
|
||||
|
||||
$controller = $this->buildController([]);
|
||||
|
||||
$request = new Request(query: []);
|
||||
|
||||
$controller->findCaller($request);
|
||||
}
|
||||
|
||||
public function testFindCallerWithEmptyCallerArgument(): void
|
||||
{
|
||||
self::expectException(BadRequestHttpException::class);
|
||||
|
||||
$controller = $this->buildController([]);
|
||||
|
||||
$request = new Request(query: ['caller' => '']);
|
||||
|
||||
$controller->findCaller($request);
|
||||
}
|
||||
|
||||
public function testFindCallerWithInvalidCaller(): void
|
||||
{
|
||||
self::expectException(BadRequestHttpException::class);
|
||||
|
||||
$controller = $this->buildController([]);
|
||||
|
||||
$request = new Request(query: ['caller' => 'abcde']);
|
||||
|
||||
$controller->findCaller($request);
|
||||
}
|
||||
|
||||
public static function provideFindCaller(): iterable
|
||||
{
|
||||
yield [
|
||||
'32486540600',
|
||||
[],
|
||||
['found' => false, 'name' => null],
|
||||
];
|
||||
|
||||
yield [
|
||||
'32486540600',
|
||||
[new Person()],
|
||||
['found' => true, 'name' => 'pppp'],
|
||||
]
|
||||
;
|
||||
yield [
|
||||
'32486540600',
|
||||
[new Person(), new Person()],
|
||||
['found' => true, 'name' => 'multiple'],
|
||||
];
|
||||
}
|
||||
|
||||
private function buildController(array $personsFound): FindCallerController
|
||||
{
|
||||
$phonenumberHelper =
|
||||
$subject = new PhonenumberHelper(
|
||||
new ArrayAdapter(),
|
||||
new ParameterBag([
|
||||
'chill_main.phone_helper' => [
|
||||
'default_carrier_code' => 'BE',
|
||||
],
|
||||
]),
|
||||
new NullLogger()
|
||||
);
|
||||
|
||||
$personRepository = $this->prophesize(PersonRepository::class);
|
||||
$personRepository->findByPhoneNumber(Argument::any(), Argument::type('int'), Argument::type('int'))->willReturn($personsFound);
|
||||
|
||||
$personRender = $this->prophesize(PersonRenderInterface::class);
|
||||
$personRender->renderString(Argument::type(Person::class), Argument::type('array'))->willReturn('pppp');
|
||||
|
||||
return new FindCallerController($phonenumberHelper, $personRepository->reveal(), $personRender->reveal());
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user