(fournisseurs * ayant >= 1 categorie de ce code, repetable) et ?siteId= (fournisseurs * ayant >= 1 adresse rattachee a ce site, repetable) ; * - pagination obligatoire (regle ABSOLUE n°13) : Paginator ORM ; echappatoire * ?pagination=false pour alimenter un cote front). if (!$this->pagination->isEnabled($operation, $context)) { /** @var list $suppliers */ $suppliers = $qb->getQuery()->getResult(); // Hydratation batchee des collections affichees (§ 2.12) : evite le // N+1 si la serialisation touche categories/sites, sans cartesien. $this->repository->hydrateListCollections($suppliers); return $suppliers; } $limit = $this->pagination->getLimit($operation, $context); $page = max(1, $this->pagination->getPage($context)); $offset = ($page - 1) * $limit; $qb->setFirstResult($offset)->setMaxResults($limit); // Le QB de selection ne porte pas de fetch-join to-many (§ 2.12) : 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; } /** * @param array $uriVariables */ private function provideItem(array $uriVariables): ?Supplier { $id = $uriVariables['id'] ?? null; if (!is_int($id) && !(is_string($id) && ctype_digit($id))) { return null; } $supplier = $this->repository->findById((int) $id); if (null === $supplier) { return null; } // Soft-delete : jamais expose au M2 (HP-M3-1) — 404 via retour null. // Les archives restent visibles en detail (consultation + restauration). if (null !== $supplier->getDeletedAt()) { return null; } return $supplier; } /** * Lit un flag booleen issu des query params. Accepte true / "true" / "1". */ private function readBool(mixed $raw): bool { if (is_bool($raw)) { return $raw; } return is_string($raw) && in_array(strtolower($raw), ['true', '1'], true); } /** * Normalise un filtre en liste de chaines. Tolere un code unique (string) * ou une liste (?key[]=a&key[]=b). Trim + retrait des vides. * * @return list */ private function readStringList(mixed $raw): array { $values = is_array($raw) ? $raw : [$raw]; $out = []; foreach ($values as $value) { if (is_string($value) && '' !== trim($value)) { $out[] = trim($value); } } return $out; } /** * Normalise un filtre en liste d'identifiants entiers positifs. Tolere une * valeur unique ou une liste (?key[]=1&key[]=2). * * @return list */ private function readIntList(mixed $raw): array { $values = is_array($raw) ? $raw : [$raw]; $out = []; foreach ($values as $value) { if ((is_int($value) || (is_string($value) && ctype_digit($value))) && (int) $value > 0) { $out[] = (int) $value; } } return $out; } }