private function resolveSynchronizationSequence()
{
$unresolved = $this->dbSchema->getAllReferences();
$sequence = [];
$triedRemovingSelfReferences = false;
while (count($unresolved) > 0) {
$resolvedInThisStep = [];
// 1st step - move all entities with resolved dependencies to $sequence
foreach ($unresolved as $entity => $deps) {
if (count($deps) === 0) {
unset($unresolved[$entity]);
$sequence[] = $entity;
$resolvedInThisStep[] = $entity;
}
}
// 2nd step - update unresolved dependencies of remaining entities
foreach ($resolvedInThisStep as $resolvedEntity) {
foreach ($unresolved as $unresolvedEntity => $deps) {
$unresolved[$unresolvedEntity] = array_diff($deps, [$resolvedEntity]);
}
}
// Nothing changed - circular dependency
if (count($resolvedInThisStep) === 0) {
if (!$triedRemovingSelfReferences) {
// At first try to remove all self-references as they have to run in 2-pass sync anyway
$triedRemovingSelfReferences = true;
foreach ($unresolved as $unresolvedEntity => $deps) {
$unresolved[$unresolvedEntity] = array_diff($deps, [$unresolvedEntity]);
}
} else {
// Simply eliminate dependencies one by one until it is resolvable
reset($unresolved);
$firstEntity = key($unresolved);
array_pop($unresolved[$firstEntity]);
}
}
}
return $sequence;
}