public static function traverseJoins(string $alias, QueryBuilder $queryBuilder, ManagerRegistry $managerRegistry): \Generator
    {
        $rootAliasMap = self::mapRootAliases($queryBuilder->getRootAliases(), $queryBuilder->getRootEntities());

        $joinParts = $queryBuilder->getDQLPart('join');
        $rootAlias = self::findRootAlias($alias, $queryBuilder);

        $joinAliasMap = self::mapJoinAliases($joinParts[$rootAlias]);

        $aliasMap = array_merge($rootAliasMap, $joinAliasMap);

        $apexEntityClass = null;
        $associationStack = [];
        $aliasStack = [];
        $currentAlias = $alias;

        while (null === $apexEntityClass) {
            if (!isset($aliasMap[$currentAlias])) {
                throw new \LogicException(sprintf('Unknown alias "%s".', $currentAlias));
            }

            if (\is_string($aliasMap[$currentAlias])) {
                $aliasStack[] = $currentAlias;
                $apexEntityClass = $aliasMap[$currentAlias];
            } else {
                [$parentAlias, $association] = $aliasMap[$currentAlias];

                $associationStack[] = $association;
                $aliasStack[] = $currentAlias;
                $currentAlias = $parentAlias;
            }
        }

        $entityClass = $apexEntityClass;

        while (null !== ($alias = array_pop($aliasStack))) {
            $metadata = $managerRegistry
                ->getManagerForClass($entityClass)
                ->getClassMetadata($entityClass);

            $association = array_pop($associationStack);

            yield $alias => [
                $metadata,
                $association,
            ];

            if (null !== $association) {
                $entityClass = $metadata->getAssociationTargetClass($association);
            }
        }
    }