*/ class DoctrineQualimatCarrierRepository extends ServiceEntityRepository implements QualimatCarrierRepositoryInterface { public function __construct(ManagerRegistry $registry) { parent::__construct($registry, QualimatCarrier::class); } public function createSearchQueryBuilder(?string $search = null): QueryBuilder { // Saisie assistee (§ 4.7) : on ne propose QUE des transporteurs QUALIMAT // actifs (is_active = true), tries par nom. Le forcage de l'actif est une // regle serveur (pas un filtre client) — les lignes soft-deletees par la // synchro restent invisibles. $qb = $this->createQueryBuilder('q') ->andWhere('q.isActive = true') ->orderBy('q.name', 'ASC') ; $this->applySearch($qb, $search); return $qb; } /** * Recherche fuzzy insensible a la casse sur le nom (+ siret) du transporteur * QUALIMAT (§ 4.7 / RG-4.01). Metacaracteres LIKE (%, _, \) echappes pour * rester litteraux. */ private function applySearch(QueryBuilder $qb, ?string $search): void { if (null === $search || '' === trim($search)) { return; } $escaped = str_replace(['\\', '%', '_'], ['\\\\', '\%', '\_'], trim($search)); $pattern = '%'.mb_strtolower($escaped, 'UTF-8').'%'; $qb->andWhere('LOWER(q.name) LIKE :search OR LOWER(q.siret) LIKE :search') ->setParameter('search', $pattern) ; } }