From 110fa0fbbea7a123f364fb6923dfe4f919589598 Mon Sep 17 00:00:00 2001 From: Maksim Date: Thu, 27 Nov 2025 13:01:43 +0700 Subject: [PATCH] Optimze DQL cache usage in NestedTreeRepository --- CHANGELOG.md | 2 + .../Repository/NestedTreeRepository.php | 47 ++++++++++++------- 2 files changed, 31 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bee883f90..e18f0c84f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ a release. --- ## [Unreleased] +### Fixed +- Tree: Optimize DQL cache usage and prevent memory leaks by using parameterized queries in NestedTreeRepository ## [3.21.0] - 2025-09-22 ### Added diff --git a/src/Tree/Entity/Repository/NestedTreeRepository.php b/src/Tree/Entity/Repository/NestedTreeRepository.php index 375f42d6a..78aee242b 100644 --- a/src/Tree/Entity/Repository/NestedTreeRepository.php +++ b/src/Tree/Entity/Repository/NestedTreeRepository.php @@ -127,12 +127,15 @@ public function getPathQueryBuilder($node/* , array $options = [] */) // @phpsta ->orderBy('node.'.$config['left'], 'ASC') ; if ($options['includeNode']) { - $qb->where($qb->expr()->lte('node.'.$config['left'], $left)) - ->andWhere($qb->expr()->gte('node.'.$config['right'], $right)); + $qb->where($qb->expr()->lte('node.'.$config['left'], ':left')) + ->andWhere($qb->expr()->gte('node.'.$config['right'], ':right')); } else { - $qb->where($qb->expr()->lt('node.'.$config['left'], $left)) - ->andWhere($qb->expr()->gt('node.'.$config['right'], $right)); + $qb->where($qb->expr()->lt('node.'.$config['left'], ':left')) + ->andWhere($qb->expr()->gt('node.'.$config['right'], ':right')); } + $qb->setParameter('left', $left); + $qb->setParameter('right', $right); + if (isset($config['root'])) { $rootId = $wrapped->getPropertyValue($config['root']); $qb->andWhere($qb->expr()->eq('node.'.$config['root'], ':rid')); @@ -259,8 +262,10 @@ public function childrenQueryBuilder($node = null, $direct = false, $sortByField $left = $wrapped->getPropertyValue($config['left']); $right = $wrapped->getPropertyValue($config['right']); if ($left && $right) { - $qb->where($qb->expr()->lt('node.'.$config['right'], $right)); - $qb->andWhere($qb->expr()->gt('node.'.$config['left'], $left)); + $qb->where($qb->expr()->lt('node.'.$config['right'], ':right')); + $qb->andWhere($qb->expr()->gt('node.'.$config['left'], ':left')); + $qb->setParameter('left', $left); + $qb->setParameter('right', $right); } } if (isset($config['root'])) { @@ -470,11 +475,12 @@ public function getNextSiblingsQueryBuilder($node, $includeSelf = false) $qb->select('node') ->from($config['useObjectClass'], 'node') ->where($includeSelf ? - $qb->expr()->gte('node.'.$config['left'], $left) : - $qb->expr()->gt('node.'.$config['left'], $left) + $qb->expr()->gte('node.'.$config['left'], ':left') : + $qb->expr()->gt('node.'.$config['left'], ':left') ) ->orderBy("node.{$config['left']}", 'ASC') ; + $qb->setParameter('left', $left); if ($parent) { $wrappedParent = new EntityWrapper($parent, $this->getEntityManager()); $qb->andWhere($qb->expr()->eq('node.'.$config['parent'], ':pid')); @@ -550,11 +556,12 @@ public function getPrevSiblingsQueryBuilder($node, $includeSelf = false) $qb->select('node') ->from($config['useObjectClass'], 'node') ->where($includeSelf ? - $qb->expr()->lte('node.'.$config['left'], $left) : - $qb->expr()->lt('node.'.$config['left'], $left) + $qb->expr()->lte('node.'.$config['left'], ':left') : + $qb->expr()->lt('node.'.$config['left'], ':left') ) ->orderBy("node.{$config['left']}", 'ASC') ; + $qb->setParameter('left', $left); if ($parent) { $wrappedParent = new EntityWrapper($parent, $this->getEntityManager()); $qb->andWhere($qb->expr()->eq('node.'.$config['parent'], ':pid')); @@ -923,10 +930,10 @@ public function recoverFast(array $options = []): void $em = $this->getEntityManager(); $updateQb = $em->createQueryBuilder() - ->update($meta->getName(), 'node') - ->set('node.'.$config['left'], ':left') - ->set('node.'.$config['right'], ':right') - ->where('node.id = :id'); + ->update($meta->getName(), 'node') + ->set('node.'.$config['left'], ':left') + ->set('node.'.$config['right'], ':right') + ->where('node.id = :id'); if (isset($config['level'])) { $updateQb->set('node.'.$config['level'], ':level'); } @@ -1223,10 +1230,12 @@ private function verifyTree(array &$errors, ?object $root = null): void $qb->select($qb->expr()->count('node.'.$identifier)) ->from($config['useObjectClass'], 'node') ->where($qb->expr()->orX( - $qb->expr()->eq('node.'.$config['left'], $i), - $qb->expr()->eq('node.'.$config['right'], $i) + $qb->expr()->eq('node.'.$config['left'], ':left'), + $qb->expr()->eq('node.'.$config['right'], ':right') )) ; + $qb->setParameter('left', $i); + $qb->setParameter('right', $i); if (isset($config['root'])) { $qb->andWhere($qb->expr()->eq('node.'.$config['root'], ':rid')); $qb->setParameter('rid', $rootId); @@ -1337,9 +1346,11 @@ private function verifyTree(array &$errors, ?object $root = null): void $qb = $this->getQueryBuilder(); $qb->select($qb->expr()->count('node.'.$identifier)) ->from($config['useObjectClass'], 'node') - ->where($qb->expr()->lt('node.'.$config['left'], $left)) - ->andWhere($qb->expr()->gt('node.'.$config['right'], $right)) + ->where($qb->expr()->lt('node.'.$config['left'], ':left')) + ->andWhere($qb->expr()->gt('node.'.$config['right'], ':right')) ; + $qb->setParameter('left', $left); + $qb->setParameter('right', $right); if (isset($config['root'])) { $qb->andWhere($qb->expr()->eq('node.'.$config['root'], ':rid')); $qb->setParameter('rid', $rootId);