diff --git a/src/Entity/Base/AbstractStructuralDBElement.php b/src/Entity/Base/AbstractStructuralDBElement.php index cbe2c7be..921826b0 100644 --- a/src/Entity/Base/AbstractStructuralDBElement.php +++ b/src/Entity/Base/AbstractStructuralDBElement.php @@ -282,6 +282,12 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement */ public function getSubelements(): iterable { + //If the parent is equal to this object, we would get an endless loop, so just return an empty array + //This is just a workaround, as validator should prevent this behaviour, before it gets written to the database + if ($this->parent === $this) { + return new ArrayCollection(); + } + return $this->children ?? new ArrayCollection(); } diff --git a/src/Repository/AbstractPartsContainingRepository.php b/src/Repository/AbstractPartsContainingRepository.php index eab2c26c..1bf4c31c 100644 --- a/src/Repository/AbstractPartsContainingRepository.php +++ b/src/Repository/AbstractPartsContainingRepository.php @@ -27,6 +27,8 @@ use InvalidArgumentException; abstract class AbstractPartsContainingRepository extends StructuralDBElementRepository implements PartsContainingRepositoryInterface { + private const RECURSION_LIMIT = 50; + /** * Returns all parts associated with this element. * @@ -55,8 +57,17 @@ abstract class AbstractPartsContainingRepository extends StructuralDBElementRepo { $count = $this->getPartsCount($element); + //If the element is its own parent, we have a loop in the tree, so we stop here. + if ($element->getParent() === $element) { + return 0; + } + + $n = 0; foreach ($element->getChildren() as $child) { $count += $this->getPartsCountRecursive($child); + if ($n++ > self::RECURSION_LIMIT) { + throw new \RuntimeException('Recursion limit reached!'); + } } return $count; diff --git a/tests/Entity/Base/AbstractStructuralDBElementTest.php b/tests/Entity/Base/AbstractStructuralDBElementTest.php index 4b124053..9a4104e5 100644 --- a/tests/Entity/Base/AbstractStructuralDBElementTest.php +++ b/tests/Entity/Base/AbstractStructuralDBElementTest.php @@ -144,4 +144,15 @@ class AbstractStructuralDBElementTest extends TestCase $this->assertSame([$this->root, $this->child1], $this->child1->getPathArray()); $this->assertSame([$this->root], $this->root->getPathArray()); } + + public function testGetSubelements(): void + { + $this->assertSame([$this->child1, $this->child2, $this->child3], $this->root->getSubelements()->toArray()); + $this->assertSame([$this->child1_1, $this->child1_2], $this->child1->getSubelements()->toArray()); + $this->assertSame([], $this->child1_1->getSubelements()->toArray()); + + //If a element is set as its own parent, it should not be returned as a subelement + $this->child1->setParent($this->child1); + $this->assertSame([], $this->child1->getSubelements()->toArray()); + } } diff --git a/translations/validators.de.xlf b/translations/validators.de.xlf index abdd0886..47ee7322 100644 --- a/translations/validators.de.xlf +++ b/translations/validators.de.xlf @@ -173,7 +173,7 @@ validator.noneofitschild.self - Ein Element kann nicht sein eigenenes übergeordnetes Element sein. + Ein Element kann nicht sein eigenenes übergeordnetes Element sein! diff --git a/translations/validators.en.xlf b/translations/validators.en.xlf index e639fa67..51549395 100644 --- a/translations/validators.en.xlf +++ b/translations/validators.en.xlf @@ -164,7 +164,7 @@ user.invalid_username - The username must contain only letters, numbers, underscores, dots, pluses or minuses. + The username must contain only letters, numbers, underscores, dots, pluses or minuses! @@ -173,7 +173,7 @@ validator.noneofitschild.self - An element can not be its own parent. + An element can not be its own parent! @@ -182,7 +182,7 @@ validator.noneofitschild.children - You can not assign children element as parent (This would cause loops). + You can not assign children element as parent (This would cause loops)!