aa23189fe1
Aligne CarrierProvider/DoctrineCarrierRepository sur Client/Supplier/Provider : ?archivedOnly=true n'expose que les archives (prioritaire sur includeArchived), pour que le toggle « Voir les archives » du front (ERP-173/ERP-164) soit operant. Parametre optionnel en fin de signature : retro-compatible avec les appels existants.
107 lines
3.4 KiB
PHP
107 lines
3.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Module\Transport\Infrastructure\Doctrine;
|
|
|
|
use App\Module\Transport\Domain\Entity\Carrier;
|
|
use App\Module\Transport\Domain\Repository\CarrierRepositoryInterface;
|
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
|
use Doctrine\ORM\QueryBuilder;
|
|
use Doctrine\Persistence\ManagerRegistry;
|
|
|
|
/**
|
|
* @extends ServiceEntityRepository<Carrier>
|
|
*/
|
|
class DoctrineCarrierRepository extends ServiceEntityRepository implements CarrierRepositoryInterface
|
|
{
|
|
public function __construct(ManagerRegistry $registry)
|
|
{
|
|
parent::__construct($registry, Carrier::class);
|
|
}
|
|
|
|
public function findById(int $id): ?Carrier
|
|
{
|
|
return $this->find($id);
|
|
}
|
|
|
|
public function save(Carrier $carrier): void
|
|
{
|
|
$this->getEntityManager()->persist($carrier);
|
|
$this->getEntityManager()->flush();
|
|
}
|
|
|
|
public function createListQueryBuilder(
|
|
bool $includeArchived = false,
|
|
?string $search = null,
|
|
array $certificationTypes = [],
|
|
bool $archivedOnly = false,
|
|
): QueryBuilder {
|
|
// Fetch-join de la SEULE relation ManyToOne qualimatCarrier (sur, pas de
|
|
// cartesien) pour exposer statut/date de validite QUALIMAT en liste sans
|
|
// N+1 (§ 2.11). Aucune sous-collection (addresses/contacts/prices) jointe
|
|
// en liste : elles ne sont embarquees qu'au detail (carrier:item:read).
|
|
$qb = $this->createQueryBuilder('c')
|
|
->leftJoin('c.qualimatCarrier', 'q')->addSelect('q')
|
|
->andWhere('c.deletedAt IS NULL')
|
|
->orderBy('c.name', 'ASC')
|
|
;
|
|
|
|
// Pas de cloisonnement par site (§ 2.3) : referentiel global.
|
|
// Perimetre d'archivage : archivedOnly prioritaire sur includeArchived
|
|
// (jumeau de DoctrineProviderRepository — toggle « Voir les archives »).
|
|
if ($archivedOnly) {
|
|
$qb->andWhere('c.isArchived = true');
|
|
} elseif (!$includeArchived) {
|
|
$qb->andWhere('c.isArchived = false');
|
|
}
|
|
|
|
$this->applySearch($qb, $search);
|
|
$this->applyCertificationTypes($qb, $certificationTypes);
|
|
|
|
return $qb;
|
|
}
|
|
|
|
/**
|
|
* Recherche fuzzy insensible a la casse sur le nom du transporteur (§ 4.1).
|
|
* 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(c.name) LIKE :search')
|
|
->setParameter('search', $pattern)
|
|
;
|
|
}
|
|
|
|
/**
|
|
* Restreint aux transporteurs dont la certification figure dans la liste (OR).
|
|
* Alimente le filtre « Certification » de la liste (§ 4.1).
|
|
*
|
|
* @param list<string> $certificationTypes
|
|
*/
|
|
private function applyCertificationTypes(QueryBuilder $qb, array $certificationTypes): void
|
|
{
|
|
$codes = [];
|
|
foreach ($certificationTypes as $code) {
|
|
if (is_string($code) && '' !== trim($code)) {
|
|
$codes[] = trim($code);
|
|
}
|
|
}
|
|
|
|
if ([] === $codes) {
|
|
return;
|
|
}
|
|
|
|
$qb->andWhere('c.certificationType IN (:certificationTypes)')
|
|
->setParameter('certificationTypes', $codes)
|
|
;
|
|
}
|
|
}
|