From 6e72bc2945ef8f4afdf2aa2cc5b274d264b6f196 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Thu, 5 Sep 2024 12:02:22 +0200 Subject: [PATCH] fix: getNodeForPath caching (#1545) * fix getNodeForPath caching * add test that cached parent nodes are used in Tree::getNodeForPath --- lib/DAV/Tree.php | 14 +++++++++++++- tests/Sabre/DAV/TreeTest.php | 17 +++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/lib/DAV/Tree.php b/lib/DAV/Tree.php index 65b4583ceb..1483e1bc51 100644 --- a/lib/DAV/Tree.php +++ b/lib/DAV/Tree.php @@ -62,9 +62,21 @@ public function getNodeForPath($path) return $this->rootNode; } - $parts = explode('/', $path); $node = $this->rootNode; + // look for any cached parent and collect the parts below the parent + $parts = []; + $remainingPath = $path; + do { + list($remainingPath, $baseName) = Uri\split($remainingPath); + array_unshift($parts, $baseName); + + if (isset($this->cache[$remainingPath])) { + $node = $this->cache[$remainingPath]; + break; + } + } while ('' !== $remainingPath); + while (count($parts)) { if (!($node instanceof ICollection)) { throw new Exception\NotFound('Could not find node at path: '.$path); diff --git a/tests/Sabre/DAV/TreeTest.php b/tests/Sabre/DAV/TreeTest.php index c7b29fc69e..87033e9f27 100644 --- a/tests/Sabre/DAV/TreeTest.php +++ b/tests/Sabre/DAV/TreeTest.php @@ -107,6 +107,23 @@ public function testGetSubTreeNode() $this->assertInstanceOf(INode::class, $tree->getNodeForPath('subtree/sub/1')); $this->assertInstanceOf(INode::class, $tree->getNodeForPath('subtree/2/3')); } + + public function testGetNodeCacheParent() + { + $tree = new TreeMock(); + + /** @var TreeDirectoryTester $root */ + $root = $tree->getNodeForPath(''); + $root->createDirectory('new'); + $parent = $tree->getNodeForPath('new'); + $parent->createDirectory('child'); + + // make it so we can't create the 'new' folder again + unset($root->newDirectories['new']); + + // we should still be able to query child items from the 'new' folder because it is cached in the tree + $this->assertInstanceOf(INode::class, $tree->getNodeForPath('new/child')); + } } class TreeMock extends Tree