uniquement les archives (is_archived = true) ; * - sinon $includeArchived = true -> actifs + archives (echappatoire) ; * - sinon (defaut) -> uniquement les actifs (is_archived = false). * $archivedOnly a la priorite sur $includeArchived. * - Tri par defaut : companyName ASC (RG-2.17). * - $search : recherche fuzzy insensible a la casse sur companyName + les * contacts lies (firstName / lastName / email) via sous-requete (D1, * refonte-contact §4.1). Metacaracteres LIKE echappes. Ignore si null/vide. * - $categoryCodes : restreint aux fournisseurs possedant au moins une * categorie dont le code est dans la liste (OR). Liste vide = pas de filtre. * - $siteIds : restreint aux fournisseurs ayant au moins une adresse rattachee * a l'un des sites donnes (OR — RG-2.06). Liste vide = pas de filtre. * * Filtrage centralise ICI (et non dans le provider/controller) pour que la * liste paginee (SupplierProvider) et l'export (SupplierExportController) * partagent strictement la meme logique de selection. * * Contrat = SELECTION uniquement (filtres + tri). Aucun fetch-join to-many : * l'hydratation des collections affichees est deleguee a * {@see self::hydrateListCollections()} pour ne pas imposer le cout d'un * produit cartesien aux chemins non pagines (cf. M1/ERP-100). * * @param list $categoryCodes * @param list $siteIds */ public function createListQueryBuilder( bool $includeArchived = false, ?string $search = null, array $categoryCodes = [], array $siteIds = [], bool $archivedOnly = false, ): QueryBuilder; /** * Hydrate en lot les collections affichees par le repertoire (categories, * adresses et leurs sites) sur un jeu de fournisseurs DEJA charges, via * l'identity map Doctrine (memes instances). A appeler apres une selection * bornee (page courante ou jeu d'export) pour eviter le N+1 a la * serialisation, sans imposer de fetch-join au QueryBuilder de selection * (anti N+1, § 2.12). * * Charge les categories et les adresses/sites en DEUX requetes distinctes * (et non un triple fetch-join) pour ne pas multiplier categories x adresses * x sites en un seul produit cartesien. * * @param list $suppliers */ public function hydrateListCollections(array $suppliers): void; /** * Hydrate en lot la collection `contacts` sur un jeu de fournisseurs DEJA * charges (memes instances via l'identity map). Reservee a l'export XLSX * (§ 4.6) qui a besoin du contact principal : la LISTE paginee n'embarque * pas les contacts (§ 2.12), d'ou une methode dediee plutot qu'une passe * supplementaire dans {@see self::hydrateListCollections()} — on n'impose pas * le cout du chargement des contacts au chemin liste. * * @param list $suppliers */ public function hydrateContacts(array $suppliers): void; }