Fixed infinite loop when an element gets assigned itself as parent

This fixes issue #230
This commit is contained in:
Jan Böhmer 2023-03-02 22:55:22 +01:00
parent d1b8a36b93
commit 7394a23a83
5 changed files with 32 additions and 4 deletions

View file

@ -282,6 +282,12 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement
*/ */
public function getSubelements(): iterable 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(); return $this->children ?? new ArrayCollection();
} }

View file

@ -27,6 +27,8 @@ use InvalidArgumentException;
abstract class AbstractPartsContainingRepository extends StructuralDBElementRepository implements PartsContainingRepositoryInterface abstract class AbstractPartsContainingRepository extends StructuralDBElementRepository implements PartsContainingRepositoryInterface
{ {
private const RECURSION_LIMIT = 50;
/** /**
* Returns all parts associated with this element. * Returns all parts associated with this element.
* *
@ -55,8 +57,17 @@ abstract class AbstractPartsContainingRepository extends StructuralDBElementRepo
{ {
$count = $this->getPartsCount($element); $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) { foreach ($element->getChildren() as $child) {
$count += $this->getPartsCountRecursive($child); $count += $this->getPartsCountRecursive($child);
if ($n++ > self::RECURSION_LIMIT) {
throw new \RuntimeException('Recursion limit reached!');
}
} }
return $count; return $count;

View file

@ -144,4 +144,15 @@ class AbstractStructuralDBElementTest extends TestCase
$this->assertSame([$this->root, $this->child1], $this->child1->getPathArray()); $this->assertSame([$this->root, $this->child1], $this->child1->getPathArray());
$this->assertSame([$this->root], $this->root->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());
}
} }

View file

@ -173,7 +173,7 @@
</notes> </notes>
<segment state="translated"> <segment state="translated">
<source>validator.noneofitschild.self</source> <source>validator.noneofitschild.self</source>
<target>Ein Element kann nicht sein eigenenes übergeordnetes Element sein.</target> <target>Ein Element kann nicht sein eigenenes übergeordnetes Element sein!</target>
</segment> </segment>
</unit> </unit>
<unit id="pr07aV4" name="validator.noneofitschild.children"> <unit id="pr07aV4" name="validator.noneofitschild.children">

View file

@ -164,7 +164,7 @@
</notes> </notes>
<segment state="translated"> <segment state="translated">
<source>user.invalid_username</source> <source>user.invalid_username</source>
<target>The username must contain only letters, numbers, underscores, dots, pluses or minuses.</target> <target>The username must contain only letters, numbers, underscores, dots, pluses or minuses!</target>
</segment> </segment>
</unit> </unit>
<unit id="lZvhKYu" name="validator.noneofitschild.self"> <unit id="lZvhKYu" name="validator.noneofitschild.self">
@ -173,7 +173,7 @@
</notes> </notes>
<segment state="translated"> <segment state="translated">
<source>validator.noneofitschild.self</source> <source>validator.noneofitschild.self</source>
<target>An element can not be its own parent.</target> <target>An element can not be its own parent!</target>
</segment> </segment>
</unit> </unit>
<unit id="pr07aV4" name="validator.noneofitschild.children"> <unit id="pr07aV4" name="validator.noneofitschild.children">
@ -182,7 +182,7 @@
</notes> </notes>
<segment state="translated"> <segment state="translated">
<source>validator.noneofitschild.children</source> <source>validator.noneofitschild.children</source>
<target>You can not assign children element as parent (This would cause loops).</target> <target>You can not assign children element as parent (This would cause loops)!</target>
</segment> </segment>
</unit> </unit>
<unit id="ayNr6QK" name="validator.select_valid_category"> <unit id="ayNr6QK" name="validator.select_valid_category">