protected function findConflict(
        string $responseName,
        FieldContext $fieldA,
        FieldContext $fieldB,
        bool $parentFieldsAreMutuallyExclusive
    ): ?Conflict {
        $parentTypeA = $fieldA->getParentType();
        $parentTypeB = $fieldB->getParentType();

        // If it is known that two fields could not possibly apply at the same
        // time, due to the parent types, then it is safe to permit them to diverge
        // in aliased field or arguments used as they will not present any ambiguity
        // by differing.
        // It is known that two parent types could never overlap if they are
        // different Object types. Interface or Union types might overlap - if not
        // in the current state of the schema, then perhaps in some future version,
        // thus may not safely diverge.
        $areMutuallyExclusive = $parentFieldsAreMutuallyExclusive
            || ($parentTypeA !== $parentTypeB
                && $parentTypeA instanceof ObjectType
                && $parentTypeB instanceof ObjectType);

        $nodeA = $fieldA->getNode();
        $nodeB = $fieldB->getNode();

        $definitionA = $fieldA->getDefinition();
        $definitionB = $fieldB->getDefinition();

        if (!$areMutuallyExclusive) {
            // Two aliases must refer to the same field.
            $nameA = $nodeA->getNameValue();
            $nameB = $nodeB->getNameValue();

            if ($nameA !== $nameB) {
                return new Conflict(
                    $responseName,
                    sprintf('%s and %s are different fields', $nameA, $nameB),
                    [$nodeA],
                    [$nodeB]
                );
            }

            // Two field calls must have the same arguments.
            if (!ValueHelper::compareArguments($nodeA->getArguments(), $nodeB->getArguments())) {
                return new Conflict(
                    $responseName,
                    'they have differing arguments',
                    [$nodeA],
                    [$nodeB]
                );
            }
        }

        // The return type for each field.
        $typeA = null !== $definitionA ? $definitionA->getType() : null;
        $typeB = null !== $definitionB ? $definitionB->getType() : null;

        if (null !== $typeA && null !== $typeB && TypeHelper::compareTypes($typeA, $typeB)) {
            return new Conflict(
                $responseName,
                sprintf('they return conflicting types %s and %s', (string)$typeA, (string)$typeB),
                [$nodeA],
                [$nodeB]
            );
        }

        // Collect and compare sub-fields. Use the same "visited fragment names" list
        // for both collections so fields in a fragment reference are never
        // compared to themselves.
        $selectionSetA = $nodeA->getSelectionSet();
        $selectionSetB = $nodeB->getSelectionSet();

        if (null !== $selectionSetA && null !== $selectionSetB) {
            $conflicts = $this->findConflictsBetweenSubSelectionSets(
                getNamedType($typeA),
                $selectionSetA,
                getNamedType($typeB),
                $selectionSetB,
                $areMutuallyExclusive
            );

            return $this->subfieldConflicts($conflicts, $responseName, $nodeA, $nodeB);
        }

        return null;
    }
protected function findConflict(
        string $responseName,
        FieldContext $fieldA,
        FieldContext $fieldB,
        bool $parentFieldsAreMutuallyExclusive
    ): ?Conflict {
        $parentTypeA = $fieldA->getParentType();
        $parentTypeB = $fieldB->getParentType();

        // If it is known that two fields could not possibly apply at the same
        // time, due to the parent types, then it is safe to permit them to diverge
        // in aliased field or arguments used as they will not present any ambiguity
        // by differing.
        // It is known that two parent types could never overlap if they are
        // different Object types. Interface or Union types might overlap - if not
        // in the current state of the schema, then perhaps in some future version,
        // thus may not safely diverge.
        $areMutuallyExclusive = $parentFieldsAreMutuallyExclusive
            || ($parentTypeA !== $parentTypeB
                && $parentTypeA instanceof ObjectType
                && $parentTypeB instanceof ObjectType);

        $nodeA = $fieldA->getNode();
        $nodeB = $fieldB->getNode();

        $definitionA = $fieldA->getDefinition();
        $definitionB = $fieldB->getDefinition();

        if (!$areMutuallyExclusive) {
            // Two aliases must refer to the same field.
            $nameA = $nodeA->getNameValue();
            $nameB = $nodeB->getNameValue();

            if ($nameA !== $nameB) {
                return new Conflict(
                    $responseName,
                    sprintf('%s and %s are different fields', $nameA, $nameB),
                    [$nodeA],
                    [$nodeB]
                );
            }

            // Two field calls must have the same arguments.
            if (!ValueHelper::compareArguments($nodeA->getArguments(), $nodeB->getArguments())) {
                return new Conflict(
                    $responseName,
                    'they have differing arguments',
                    [$nodeA],
                    [$nodeB]
                );
            }
        }

        // The return type for each field.
        $typeA = null !== $definitionA ? $definitionA->getType() : null;
        $typeB = null !== $definitionB ? $definitionB->getType() : null;

        if (null !== $typeA && null !== $typeB && TypeHelper::compareTypes($typeA, $typeB)) {
            return new Conflict(
                $responseName,
                sprintf('they return conflicting types %s and %s', (string)$typeA, (string)$typeB),
                [$nodeA],
                [$nodeB]
            );
        }

        // Collect and compare sub-fields. Use the same "visited fragment names" list
        // for both collections so fields in a fragment reference are never
        // compared to themselves.
        $selectionSetA = $nodeA->getSelectionSet();
        $selectionSetB = $nodeB->getSelectionSet();

        if (null !== $selectionSetA && null !== $selectionSetB) {
            $conflicts = $this->findConflictsBetweenSubSelectionSets(
                getNamedType($typeA),
                $selectionSetA,
                getNamedType($typeB),
                $selectionSetB,
                $areMutuallyExclusive
            );

            return $this->subfieldConflicts($conflicts, $responseName, $nodeA, $nodeB);
        }

        return null;
    }
protected function findConflict ( string $ responseName , FieldContext $ fieldA , FieldContext $ fieldB , bool $ parentFieldsAreMutuallyExclusive ) : ? Conflict { $ parentTypeA = $ fieldA -> getParentType ( ) ; $ parentTypeB = $ fieldB -> getParentType ( ) ; // If it is known that two fields could not possibly apply at the same // time, due to the parent types, then it is safe to permit them to diverge // in aliased field or arguments used as they will not present any ambiguity // by differing. // It is known that two parent types could never overlap if they are // different Object types. Interface or Union types might overlap - if not // in the current state of the schema, then perhaps in some future version, // thus may not safely diverge. $ areMutuallyExclusive = $ parentFieldsAreMutuallyExclusive || ( $ parentTypeA !== $ parentTypeB && $ parentTypeA instanceof ObjectType && $ parentTypeB instanceof ObjectType ) ; $ nodeA = $ fieldA -> getNode ( ) ; $ nodeB = $ fieldB -> getNode ( ) ; $ definitionA = $ fieldA -> getDefinition ( ) ; $ definitionB = $ fieldB -> getDefinition ( ) ; if ( ! $ areMutuallyExclusive ) { // Two aliases must refer to the same field. $ nameA = $ nodeA -> getNameValue ( ) ; $ nameB = $ nodeB -> getNameValue ( ) ; if ( $ nameA !== $ nameB ) { return new Conflict ( $ responseName , sprintf ( '%s and %s are different fields' , $ nameA , $ nameB ) , [ $ nodeA ] , [ $ nodeB ] ) ; } // Two field calls must have the same arguments. if ( ! ValueHelper :: compareArguments ( $ nodeA -> getArguments ( ) , $ nodeB -> getArguments ( ) ) ) { return new Conflict ( $ responseName , 'they have differing arguments' , [ $ nodeA ] , [ $ nodeB ] ) ; } } // The return type for each field. $ typeA = null !== $ definitionA ? $ definitionA -> getType ( ) : null ; $ typeB = null !== $ definitionB ? $ definitionB -> getType ( ) : null ; if ( null !== $ typeA && null !== $ typeB && TypeHelper :: compareTypes ( $ typeA , $ typeB ) ) { return new Conflict ( $ responseName , sprintf ( 'they return conflicting types %s and %s' , ( string ) $ typeA , ( string ) $ typeB ) , [ $ nodeA ] , [ $ nodeB ] ) ; } // Collect and compare sub-fields. Use the same "visited fragment names" list // for both collections so fields in a fragment reference are never // compared to themselves. $ selectionSetA = $ nodeA -> getSelectionSet ( ) ; $ selectionSetB = $ nodeB -> getSelectionSet ( ) ; if ( null !== $ selectionSetA && null !== $ selectionSetB ) { $ conflicts = $ this -> findConflictsBetweenSubSelectionSets ( getNamedType ( $ typeA ) , $ selectionSetA , getNamedType ( $ typeB ) , $ selectionSetB , $ areMutuallyExclusive ) ; return $ this -> subfieldConflicts ( $ conflicts , $ responseName , $ nodeA , $ nodeB ) ; } return null ; }
Determines if there is a conflict between two particular fields, including
comparing their sub-fields.

@param string       $responseName
@param FieldContext $fieldA
@param FieldContext $fieldB
@param bool         $parentFieldsAreMutuallyExclusive
@return Conflict|null
@throws ConversionException
@throws InvalidTypeException
@throws InvariantException
Determines if there is a conflict between two particular fields including comparing their sub - fields .