Traitement par lots avec Doctrine : toIterable(), flush() et clear()
Le traitement par lots avec Doctrine parcourt des milliers d'entités sans saturer la mémoire : on les lit une à une, et tous les N, on écrit puis on vide.
$numero = 0; foreach ($io->progressIterate($query->toIterable(), $total) as $reservation) { $this->entityManager->remove($reservation); if (0 === ++$numero % self::PAR_LOT) { $this->entityManager->flush(); // écrire le lot… $this->entityManager->clear(); // … puis oublier les entités chargées } } $this->entityManager->flush(); // le dernier lot, incomplet $this->entityManager->clear();
L'EntityManager garde en mémoire chaque entité qu'il charge ou doit écrire : avec getResult(), toute la sélection arrive d'un coup, et le processus grossit avec le registre. toIterable() hydrate les résultats un à un ; flush() envoie les changements du lot, clear() détache tout ce que Doctrine suivait. Les deux pièges ne lèvent aucune erreur. Un clear() sans flush() juste avant efface aussi les remove() et persist() en attente : rien n'est écrit. Et sans flush() après la boucle, le dernier lot incomplet est perdu ; avec exactement 20 réservations pour des lots de 20, on ne le voit pas, avec 25, si.
Les exercices font écrire le grand ménage du registre, une commande qui purge par lots les réservations terminées, avec une barre de progression, un mode --dry-run et le détail avec -v ; puis retrouver pourquoi, après un passage de Pipin, elle annonce avoir tout purgé en laissant des dizaines de vieilles réservations au registre.
2 exercices font travailler cette notion, en écrivant du code dans le navigateur.
Dans les parcours
- Le grand ménage Symfony pour les devs PHP · chapitre 11 : Les ordres du patron
- 🐉 Boss : les ordres mal compris Symfony pour les devs PHP · chapitre 11 : Les ordres du patron