Skip to content
Merged
1 change: 1 addition & 0 deletions config/packages/doctrine.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ doctrine:
POINT: App\Doctrine\Functions\PointFunction
MBRContains: App\Doctrine\Functions\MBRContains
ST_MakeEnvelope: App\Doctrine\Functions\STMakeEnvelope
REPLACE: App\Doctrine\Functions\ReplaceFunction
39 changes: 39 additions & 0 deletions src/Doctrine/Functions/ReplaceFunction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace App\Doctrine\Functions;

use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
use Doctrine\ORM\Query\TokenType;

/**
* ReplaceFunction ::= "REPLACE" "(" StringPrimary "," StringPrimary "," StringPrimary ")".
*/
class ReplaceFunction extends FunctionNode
{
public mixed $subject;
public mixed $search;
public mixed $replace;

public function parse(Parser $parser): void
{
$parser->match(TokenType::T_IDENTIFIER);
$parser->match(TokenType::T_OPEN_PARENTHESIS);
$this->subject = $parser->StringPrimary();
$parser->match(TokenType::T_COMMA);
$this->search = $parser->StringPrimary();
$parser->match(TokenType::T_COMMA);
$this->replace = $parser->StringPrimary();
$parser->match(TokenType::T_CLOSE_PARENTHESIS);
}

public function getSql(SqlWalker $sqlWalker): string
{
return 'REPLACE(' .
$this->subject->dispatch($sqlWalker) . ', ' .
$this->search->dispatch($sqlWalker) . ', ' .
$this->replace->dispatch($sqlWalker) .
')';
}
}
2 changes: 1 addition & 1 deletion src/Entity/Cim11.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
use Symfony\Component\Serializer\Annotation\Groups;

#[ORM\Entity(repositoryClass: Cim11Repository::class)]
#[ApiFilter(Cim11Filter::class, properties: ['search', 'ids', 'cim10_code'])]
#[ApiFilter(Cim11Filter::class, properties: ['search', 'ids', 'cim10Code'])]
#[ORM\Table(name: 'cim_11')]
#[ORM\Index(columns: ['code'])]
#[UniqueEntity(['code', 'whoId'])]
Expand Down
20 changes: 18 additions & 2 deletions src/Repository/InseeCommune1943Repository.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,34 @@
*/
class InseeCommune1943Repository extends ServiceEntityRepository
{
use SearchNormalizationTrait;

public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, InseeCommune1943::class);
}

public function searchByNameAndDate(string $search, DateTime $date): array
{
// Normalize hyphens to spaces at the SQL level for flexible matching
// MySQL collations are typically accent-insensitive by default (utf8mb4_unicode_ci)
return $this->createQueryBuilder('c')
->where('REPLACE(c.nomTypographie, \'-\', \' \') LIKE :search')
->andWhere('(c.dateDebut IS NULL OR c.dateDebut <= :date)')
->andWhere('(c.dateFin IS NULL OR c.dateFin >= :date)')
->setParameter('search', '%' . str_replace('-', ' ', $search) . '%')
->setParameter('date', $date)
->getQuery()
->getResult();
}

public function findByCodeAndDate(string $code, DateTime $date): array
{
return $this->createQueryBuilder('c')
->where('c.nomTypographie LIKE :search')
->where('c.codeCommune = :code')
->andWhere('(c.dateDebut IS NULL OR c.dateDebut <= :date)')
->andWhere('(c.dateFin IS NULL OR c.dateFin >= :date)')
->setParameter('search', "$search%")
->setParameter('code', $code)
->setParameter('date', $date)
->getQuery()
->getResult();
Expand Down
17 changes: 15 additions & 2 deletions src/Repository/InseeCommuneRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,29 @@
*/
class InseeCommuneRepository extends ServiceEntityRepository
{
use SearchNormalizationTrait;

public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, InseeCommune::class);
}

public function searchByName(string $search): array
{
// Normalize hyphens to spaces at the SQL level for flexible matching
// MySQL collations are typically accent-insensitive by default (utf8mb4_unicode_ci)
return $this->createQueryBuilder('c')
->where('REPLACE(c.nomEnClair, \'-\', \' \') LIKE :search')
->setParameter('search', '%' . str_replace('-', ' ', $search) . '%')
->getQuery()
->getResult();
}

public function findByCode(string $code): array
{
return $this->createQueryBuilder('c')
->where('c.nomEnClair LIKE :search')
->setParameter('search', "$search%")
->where('c.codeCommune = :code')
->setParameter('code', $code)
->getQuery()
->getResult();
}
Expand Down
22 changes: 19 additions & 3 deletions src/Repository/InseePays1943Repository.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
*/
class InseePays1943Repository extends ServiceEntityRepository
{
use SearchNormalizationTrait;

public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, InseePays1943::class);
Expand All @@ -25,15 +27,29 @@ public function __construct(ManagerRegistry $registry)
/**
* Note : might consider searching also the libelleOfficiel field.
*
* Search for countries matching a name that existed at a given date.
* Search for countries matching a name.
* Date constraints removed to allow searching for historical countries (e.g., Algeria before 1962).
*/
public function searchByNameAndDate(string $search, DateTime $date): array
{
// Normalize hyphens to spaces at the SQL level for flexible matching
// MySQL collations are typically accent-insensitive by default (utf8mb4_unicode_ci)
return $this->createQueryBuilder('p')
->where('p.libelleCog LIKE :search')
->where('REPLACE(p.libelleCog, \'-\', \' \') LIKE :search')
// Date constraints removed to allow historical country searches (e.g., Algeria before 1962)
->setParameter('search', '%' . str_replace('-', ' ', $search) . '%')
->getQuery()
Comment on lines 37 to 41
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed the normalization to replace hyphens with spaces instead of removing them. Fixed in commit 843de38.

->getResult();
}

public function findByCodeAndDate(string $code, DateTime $date): array
{
return $this->createQueryBuilder('p')
->where('p.codePays = :code')
// Keep date constraints for find by code
->andWhere('(p.dateDebut IS NULL OR p.dateDebut <= :date)')
->andWhere('(p.dateFin IS NULL OR p.dateFin >= :date)')
->setParameter('search', "%$search%")
->setParameter('code', $code)
->setParameter('date', $date)
->getQuery()
->getResult();
Expand Down
17 changes: 15 additions & 2 deletions src/Repository/InseePaysRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,29 @@
*/
class InseePaysRepository extends ServiceEntityRepository
{
use SearchNormalizationTrait;

public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, InseePays::class);
}

public function searchByName(string $search): array
{
// Normalize hyphens to spaces at the SQL level for flexible matching
// MySQL collations are typically accent-insensitive by default (utf8mb4_unicode_ci)
return $this->createQueryBuilder('p')
->where('REPLACE(p.libelleCog, \'-\', \' \') LIKE :search')
->setParameter('search', '%' . str_replace('-', ' ', $search) . '%')
->getQuery()
->getResult();
}

public function findByCode(string $code): array
{
return $this->createQueryBuilder('p')
->where('p.libelleCog LIKE :search')
->setParameter('search', "%$search%")
->where('p.codePays = :code')
->setParameter('code', $code)
->getQuery()
->getResult();
}
Expand Down
18 changes: 18 additions & 0 deletions src/Repository/SearchNormalizationTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace App\Repository;

trait SearchNormalizationTrait
{
/**
* Normalize search term by replacing hyphens with spaces.
*
* Note: Accent normalization is handled by MySQL's collation (utf8mb4_unicode_ci)
* which is accent-insensitive by default, so we don't need to remove accents here.
*/
private function normalizeSearchTerm(string $search): string
{
// Replace hyphens with spaces for flexible matching
return str_replace('-', ' ', $search);
}
}
22 changes: 17 additions & 5 deletions src/Service/BirthPlaceService.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,14 @@ public function searchBirthPlaces(string $search): array
/** @var InseePaysRepository $paysRepository */
$paysRepository = $this->em->getRepository(InseePays::class);

$communeResults = $communeRepository->searchByName($search);
$paysResults = $paysRepository->searchByName($search);
// Check if search is a 5-digit code
if (preg_match('/^\d{5}$/', $search)) {
$communeResults = $communeRepository->findByCode($search);
$paysResults = $paysRepository->findByCode($search);
} else {
$communeResults = $communeRepository->searchByName($search);
$paysResults = $paysRepository->searchByName($search);
}

return $this->mapResultsToDTO($communeResults, $paysResults);
}
Expand All @@ -42,7 +48,7 @@ public function getBirthPlaceByCode(string $code, ?string $dateOfBirth): ?BirthP
if ($dateOfBirth) {
try {
$dateOfBirth = new DateTime($dateOfBirth);
} catch (Exception $e) {
} catch (Exception) {
// If the date is invalid, we ignore it and proceed with the search
$dateOfBirth = null;
}
Expand Down Expand Up @@ -97,8 +103,14 @@ public function searchBirthPlacesByDate(string $search, DateTime $date): array
/** @var InseePays1943Repository $pays1943Repository */
$pays1943Repository = $this->em->getRepository(InseePays1943::class);

$communeResults = $commune1943Repository->searchByNameAndDate($search, $date);
$paysResults = $pays1943Repository->searchByNameAndDate($search, $date);
// Check if search is a 5-digit code
if (preg_match('/^\d{5}$/', $search)) {
$communeResults = $commune1943Repository->findByCodeAndDate($search, $date);
$paysResults = $pays1943Repository->findByCodeAndDate($search, $date);
} else {
$communeResults = $commune1943Repository->searchByNameAndDate($search, $date);
$paysResults = $pays1943Repository->searchByNameAndDate($search, $date);
}

return $this->mapResultsToDTO($communeResults, $paysResults);
}
Expand Down
11 changes: 10 additions & 1 deletion src/StateProvider/BirthPlacesProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@ private function provideItem(Operation $operation, array $uriVariables = [], arr
throw new RuntimeException('Missing "code" in URI variables');
}

return $this->birthPlaceService->getBirthPlaceByCode($uriVariables['code'], $context['filters']['filters'] ?? null);
$request = $this->requestStack->getCurrentRequest();
if (!$request) {
throw new LogicException('No current request available');
}

$dateOfBirth = $request->query->get('dateOfBirth');

$code = explode('.', $uriVariables['code'])[0];

return $this->birthPlaceService->getBirthPlaceByCode($code, $dateOfBirth);
}
}
Loading