src/Validator/Rules/OverlappingFieldsCanBeMerged.php
private function collectConflictsBetweenFragments(
        ValidationContext $context,
        array &$conflicts,
        $areMutuallyExclusive,
        $fragmentName1,
        $fragmentName2
    ) {
        // No need to compare a fragment to itself.
        if ($fragmentName1 === $fragmentName2) {
            return;
        }

        // Memoize so two fragments are not compared for conflicts more than once.
        if ($this->comparedFragmentPairs->has(
            $fragmentName1,
            $fragmentName2,
            $areMutuallyExclusive
        )
        ) {
            return;
        }
        $this->comparedFragmentPairs->add(
            $fragmentName1,
            $fragmentName2,
            $areMutuallyExclusive
        );

        $fragment1 = $context->getFragment($fragmentName1);
        $fragment2 = $context->getFragment($fragmentName2);
        if (! $fragment1 || ! $fragment2) {
            return;
        }

        [$fieldMap1, $fragmentNames1] = $this->getReferencedFieldsAndFragmentNames(
            $context,
            $fragment1
        );
        [$fieldMap2, $fragmentNames2] = $this->getReferencedFieldsAndFragmentNames(
            $context,
            $fragment2
        );

        // (F) First, collect all conflicts between these two collections of fields
        // (not including any nested fragments).
        $this->collectConflictsBetween(
            $context,
            $conflicts,
            $areMutuallyExclusive,
            $fieldMap1,
            $fieldMap2
        );

        // (G) Then collect conflicts between the first fragment and any nested
        // fragments spread in the second fragment.
        $fragmentNames2Length = count($fragmentNames2);
        for ($j = 0; $j < $fragmentNames2Length; $j++) {
            $this->collectConflictsBetweenFragments(
                $context,
                $conflicts,
                $areMutuallyExclusive,
                $fragmentName1,
                $fragmentNames2[$j]
            );
        }

        // (G) Then collect conflicts between the second fragment and any nested
        // fragments spread in the first fragment.
        $fragmentNames1Length = count($fragmentNames1);
        for ($i = 0; $i < $fragmentNames1Length; $i++) {
            $this->collectConflictsBetweenFragments(
                $context,
                $conflicts,
                $areMutuallyExclusive,
                $fragmentNames1[$i],
                $fragmentName2
            );
        }
    }
private function collectConflictsBetweenFragments(
        ValidationContext $context,
        array &$conflicts,
        $areMutuallyExclusive,
        $fragmentName1,
        $fragmentName2
    ) {
        // No need to compare a fragment to itself.
        if ($fragmentName1 === $fragmentName2) {
            return;
        }

        // Memoize so two fragments are not compared for conflicts more than once.
        if ($this->comparedFragmentPairs->has(
            $fragmentName1,
            $fragmentName2,
            $areMutuallyExclusive
        )
        ) {
            return;
        }
        $this->comparedFragmentPairs->add(
            $fragmentName1,
            $fragmentName2,
            $areMutuallyExclusive
        );

        $fragment1 = $context->getFragment($fragmentName1);
        $fragment2 = $context->getFragment($fragmentName2);
        if (! $fragment1 || ! $fragment2) {
            return;
        }

        [$fieldMap1, $fragmentNames1] = $this->getReferencedFieldsAndFragmentNames(
            $context,
            $fragment1
        );
        [$fieldMap2, $fragmentNames2] = $this->getReferencedFieldsAndFragmentNames(
            $context,
            $fragment2
        );

        // (F) First, collect all conflicts between these two collections of fields
        // (not including any nested fragments).
        $this->collectConflictsBetween(
            $context,
            $conflicts,
            $areMutuallyExclusive,
            $fieldMap1,
            $fieldMap2
        );

        // (G) Then collect conflicts between the first fragment and any nested
        // fragments spread in the second fragment.
        $fragmentNames2Length = count($fragmentNames2);
        for ($j = 0; $j < $fragmentNames2Length; $j++) {
            $this->collectConflictsBetweenFragments(
                $context,
                $conflicts,
                $areMutuallyExclusive,
                $fragmentName1,
                $fragmentNames2[$j]
            );
        }

        // (G) Then collect conflicts between the second fragment and any nested
        // fragments spread in the first fragment.
        $fragmentNames1Length = count($fragmentNames1);
        for ($i = 0; $i < $fragmentNames1Length; $i++) {
            $this->collectConflictsBetweenFragments(
                $context,
                $conflicts,
                $areMutuallyExclusive,
                $fragmentNames1[$i],
                $fragmentName2
            );
        }
    }
Collect all conflicts found between two fragments, including via spreading in
any nested fragments.

@param mixed[][] $conflicts
@param bool      $areMutuallyExclusive
@param string    $fragmentName1
@param string    $fragmentName2