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 914064c
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 11 deletions.
35 changes: 26 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 @@ -167,6 +159,18 @@ 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) {
continue;

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

View check run for this annotation

Codecov / codecov/patch

src/Sorter/TopologicalSorter.php#L165-L168

Added lines #L165 - L168 were not covered by tests
}

$this->visit($nestedChildDefinition);

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

View check run for this annotation

Codecov / codecov/patch

src/Sorter/TopologicalSorter.php#L171

Added line #L171 was not covered by tests
}

break;
case Vertex::NOT_VISITED:
$this->visit($childDefinition);
Expand All @@ -177,4 +181,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 914064c

Please sign in to comment.