refactor(commercial) : découpler l'hydratation des collections de la sélection clients (ERP-100) (#50)
Auto Tag Develop / tag (push) Successful in 7s
Auto Tag Develop / tag (push) Successful in 7s
## Contexte Issu de la review ERP-62 (#44). `DoctrineClientRepository::createListQueryBuilder()` portait 3 `leftJoin+addSelect` to-many imbriqués (`categories × addresses × addresses.sites`) **partagés** entre : - la **liste paginée** (`ClientProvider`) — bornée, OK ; - l'**export XLSX** et **`?pagination=false`** — `getResult()` sans pagination → hydratation du **produit cartésien sur tout le référentiel** (1 client à 5 cat × 4 adr × 3 sites = 60 lignes SQL, × N clients). Défaut d'altitude : un « QueryBuilder de liste » (contrat = filtres) imposait une stratégie d'hydratation à tout appelant. ## Changements - **`createListQueryBuilder()`** redevient **filtres + tri seuls** — conforme au contrat de l'interface. - Nouvelle méthode **`hydrateListCollections(array $clients)`** : recharge les collections en **2 requêtes `WHERE id IN(...)` séparées** (catégories d'un côté, adresses+sites de l'autre) via l'identity map Doctrine. Casse le triple cartésien en `cat + (addr × site)`. - **3 appelants** branchés sur cette stratégie unique : - liste paginée : `fetchJoinCollection: false` (COUNT simple) + hydratation de la page ; - `?pagination=false` : hydratation après `getResult()` ; - export XLSX : hydratation après `getResult()`. ## Tests - `make test` : **465 OK**. - Nouveau test `ClientExportControllerTest::testExportPopulatesCategoryAndSiteColumns` : garde-fou sur les valeurs Catégories/Sites de l'export (qu'un oubli d'hydratation rendrait silencieusement vides). - `php-cs-fixer` : 0 correction. ## Notes - Benchmark « 1000+ clients » non exécuté (pas de jeu de données à cette échelle en dev) ; le cartésien est supprimé structurellement. - `addr × site` reste un join imbriqué (inévitable pour agréger les sites par adresse), désormais non multiplié par les catégories. Closes ERP-100. --------- Co-authored-by: admin malio <malio@yuno.malio.fr> Co-authored-by: Matthieu <contact@malio.fr> Reviewed-on: #50 Co-authored-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr> Co-committed-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr>
This commit was merged in pull request #50.
This commit is contained in:
@@ -83,8 +83,13 @@ final class ClientProvider implements ProviderInterface
|
||||
// Echappatoire ?pagination=false : collection complete sans Paginator
|
||||
// (cf. convention ERP-72 — utile pour un <select> cote front).
|
||||
if (!$this->pagination->isEnabled($operation, $context)) {
|
||||
// @var list<Client> $result
|
||||
return $qb->getQuery()->getResult();
|
||||
/** @var list<Client> $clients */
|
||||
$clients = $qb->getQuery()->getResult();
|
||||
// Hydratation batchee des collections affichees (cf. ERP-100) : evite
|
||||
// le N+1 si la serialisation touche categories/sites, sans cartesien.
|
||||
$this->repository->hydrateListCollections($clients);
|
||||
|
||||
return $clients;
|
||||
}
|
||||
|
||||
$limit = $this->pagination->getLimit($operation, $context);
|
||||
@@ -93,9 +98,13 @@ final class ClientProvider implements ProviderInterface
|
||||
|
||||
$qb->setFirstResult($offset)->setMaxResults($limit);
|
||||
|
||||
// fetchJoinCollection: true pour un COUNT correct des que des JOINs
|
||||
// to-many seront ajoutes (sous-collections embarquees en detail).
|
||||
return new Paginator(new DoctrinePaginator($qb->getQuery(), fetchJoinCollection: true));
|
||||
// Le QB de selection ne porte plus de fetch-join to-many (ERP-100) : le
|
||||
// COUNT est simple, fetchJoinCollection inutile. On materialise la page
|
||||
// puis on hydrate ses collections en lot (memes entites managees).
|
||||
$paginator = new Paginator(new DoctrinePaginator($qb->getQuery(), fetchJoinCollection: false));
|
||||
$this->repository->hydrateListCollections(iterator_to_array($paginator));
|
||||
|
||||
return $paginator;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user