Skip to content

Commit

Permalink
Fix order of sorting for cyclic dependencies
Browse files Browse the repository at this point in the history
where multiple dependencies are assumed to always
go after the cyclic one
  • Loading branch information
esserj committed Jun 20, 2024
1 parent bf6c619 commit 7c7546a
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 11 deletions.
32 changes: 23 additions & 9 deletions src/Sorter/TopologicalSorter.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,15 +132,7 @@ private function visit(Vertex $definition)
$definition->state = Vertex::IN_PROGRESS;

foreach ($definition->dependencyList as $dependency) {
if (! isset($this->nodeList[$dependency])) {
throw new RuntimeException(sprintf(
'Fixture "%s" has a dependency of fixture "%s", but it not listed to be loaded.',
get_class($definition->value),
$dependency,
));
}

$childDefinition = $this->nodeList[$dependency];
$childDefinition = $this->getDefinition($dependency, $definition);

// allow self referencing classes
if ($definition === $childDefinition) {
Expand All @@ -166,6 +158,15 @@ private function visit(Vertex $definition)
),
);
}
// first do the rest of the unvisited children of the "in_progress" child before we continue
// with the current one, to be sure that there are no other dependencies that need
// to be cleared before this ($definition) node
foreach ($childDefinition->dependencyList as $childDependency) {
$nestedChildDefinition = $this->getDefinition($childDependency, $childDefinition);
if ($nestedChildDefinition->state === Vertex::NOT_VISITED) {

Check failure on line 166 in src/Sorter/TopologicalSorter.php

View workflow job for this annotation

GitHub Actions / Coding Standards / Coding Standards (8.3)

Use early exit to reduce code nesting.
$this->visit($nestedChildDefinition);

Check warning on line 167 in src/Sorter/TopologicalSorter.php

View check run for this annotation

Codecov / codecov/patch

src/Sorter/TopologicalSorter.php#L164-L167

Added lines #L164 - L167 were not covered by tests
}
}

break;
case Vertex::NOT_VISITED:
Expand All @@ -177,4 +178,17 @@ private function visit(Vertex $definition)

$this->sortedNodeList[] = $definition->value;
}

public function getDefinition(string $dependency, Vertex $definition): Vertex
{
if (! isset($this->nodeList[$dependency])) {
throw new RuntimeException(sprintf(
'Fixture "%s" has a dependency of fixture "%s", but it not listed to be loaded.',
get_class($definition->value),
$dependency,
));
}

return $this->nodeList[$dependency];
}
}
40 changes: 38 additions & 2 deletions tests/Common/DataFixtures/Sorter/TopologicalSorterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,17 +83,53 @@ public function testSortCyclicDependency(): void
$node1 = new ClassMetadata('1');
$node2 = new ClassMetadata('2');
$node3 = new ClassMetadata('3');
$node4 = new ClassMetadata('4');
$node5 = new ClassMetadata('5');

$sorter->addNode('1', $node1);
$sorter->addNode('2', $node2);
$sorter->addNode('3', $node3);
$sorter->addNode('4', $node4);
$sorter->addNode('5', $node5);

$sorter->addDependency('1', '2');
$sorter->addDependency('1', '4');
$sorter->addDependency('2', '3');
$sorter->addDependency('3', '1');
$sorter->addDependency('5', '1');
$sorter->addDependency('3', '4');

$sortedList = $sorter->sort();
$correctList = [$node4, $node3, $node2, $node1, $node5];

self::assertSame($correctList, $sortedList);

$sorter->sort();
}

public function testSortCyclicDependencyWhenNodesAreAddedInAnotherOrder(): void
{
$sorter = new TopologicalSorter();

$node1 = new ClassMetadata('1');
$node2 = new ClassMetadata('2');
$node3 = new ClassMetadata('3');
$node4 = new ClassMetadata('4');
$node5 = new ClassMetadata('5');

$sorter->addNode('5', $node5);
$sorter->addNode('4', $node4);
$sorter->addNode('3', $node3);
$sorter->addNode('2', $node2);
$sorter->addNode('1', $node1);

$sorter->addDependency('1', '2');
$sorter->addDependency('1', '4');
$sorter->addDependency('2', '3');
$sorter->addDependency('5', '1');
$sorter->addDependency('3', '4');

$sortedList = $sorter->sort();
$correctList = [$node3, $node2, $node1];
$correctList = [$node4, $node3, $node2, $node1, $node5];

self::assertSame($correctList, $sortedList);

Expand Down

0 comments on commit 7c7546a

Please sign in to comment.