Skip to content

Commit d0d9da0

Browse files
committed
Fix order of sorting for cyclic dependencies
where multiple dependencies are assumed to always go after the cyclic one
1 parent bf6c619 commit d0d9da0

File tree

2 files changed

+62
-11
lines changed

2 files changed

+62
-11
lines changed

src/Sorter/TopologicalSorter.php

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -132,15 +132,7 @@ private function visit(Vertex $definition)
132132
$definition->state = Vertex::IN_PROGRESS;
133133

134134
foreach ($definition->dependencyList as $dependency) {
135-
if (! isset($this->nodeList[$dependency])) {
136-
throw new RuntimeException(sprintf(
137-
'Fixture "%s" has a dependency of fixture "%s", but it not listed to be loaded.',
138-
get_class($definition->value),
139-
$dependency,
140-
));
141-
}
142-
143-
$childDefinition = $this->nodeList[$dependency];
135+
$childDefinition = $this->getDefinition($dependency, $definition);
144136

145137
// allow self referencing classes
146138
if ($definition === $childDefinition) {
@@ -167,6 +159,16 @@ private function visit(Vertex $definition)
167159
);
168160
}
169161

162+
// first do the rest of the unvisited children of the "in_progress" child before we continue
163+
// with the current one, to be sure that there are no other dependencies that need
164+
// to be cleared before this ($definition) node
165+
foreach ($childDefinition->dependencyList as $childDependency) {
166+
$nestedChildDefinition = $this->getDefinition($childDependency, $childDefinition);
167+
if ($nestedChildDefinition->state === Vertex::NOT_VISITED) {
168+
$this->visit($nestedChildDefinition);
169+
}
170+
}
171+
170172
break;
171173
case Vertex::NOT_VISITED:
172174
$this->visit($childDefinition);
@@ -177,4 +179,17 @@ private function visit(Vertex $definition)
177179

178180
$this->sortedNodeList[] = $definition->value;
179181
}
182+
183+
public function getDefinition(string $dependency, Vertex $definition): Vertex
184+
{
185+
if (! isset($this->nodeList[$dependency])) {
186+
throw new RuntimeException(sprintf(
187+
'Fixture "%s" has a dependency of fixture "%s", but it not listed to be loaded.',
188+
get_class($definition->value),
189+
$dependency,
190+
));
191+
}
192+
193+
return $this->nodeList[$dependency];
194+
}
180195
}

tests/Common/DataFixtures/Sorter/TopologicalSorterTest.php

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,17 +83,53 @@ public function testSortCyclicDependency(): void
8383
$node1 = new ClassMetadata('1');
8484
$node2 = new ClassMetadata('2');
8585
$node3 = new ClassMetadata('3');
86+
$node4 = new ClassMetadata('4');
87+
$node5 = new ClassMetadata('5');
8688

8789
$sorter->addNode('1', $node1);
8890
$sorter->addNode('2', $node2);
8991
$sorter->addNode('3', $node3);
92+
$sorter->addNode('4', $node4);
93+
$sorter->addNode('5', $node5);
9094

9195
$sorter->addDependency('1', '2');
96+
$sorter->addDependency('1', '4');
9297
$sorter->addDependency('2', '3');
93-
$sorter->addDependency('3', '1');
98+
$sorter->addDependency('5', '1');
99+
$sorter->addDependency('3', '4');
100+
101+
$sortedList = $sorter->sort();
102+
$correctList = [$node4, $node3, $node2, $node1, $node5];
103+
104+
self::assertSame($correctList, $sortedList);
105+
106+
$sorter->sort();
107+
}
108+
109+
public function testSortCyclicDependencyWhenNodesAreAddedInAnotherOrder(): void
110+
{
111+
$sorter = new TopologicalSorter();
112+
113+
$node1 = new ClassMetadata('1');
114+
$node2 = new ClassMetadata('2');
115+
$node3 = new ClassMetadata('3');
116+
$node4 = new ClassMetadata('4');
117+
$node5 = new ClassMetadata('5');
118+
119+
$sorter->addNode('5', $node5);
120+
$sorter->addNode('4', $node4);
121+
$sorter->addNode('3', $node3);
122+
$sorter->addNode('2', $node2);
123+
$sorter->addNode('1', $node1);
124+
125+
$sorter->addDependency('1', '2');
126+
$sorter->addDependency('1', '4');
127+
$sorter->addDependency('2', '3');
128+
$sorter->addDependency('5', '1');
129+
$sorter->addDependency('3', '4');
94130

95131
$sortedList = $sorter->sort();
96-
$correctList = [$node3, $node2, $node1];
132+
$correctList = [$node4, $node3, $node2, $node1, $node5];
97133

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

0 commit comments

Comments
 (0)