protected function collectFieldASTsAndDefs(
        ValidationContext $context,
        $parentType,
        SelectionSetNode $selectionSet,
        ?ArrayObject $visitedFragmentNames = null,
        ?ArrayObject $astAndDefs = null
    ) {
        $_visitedFragmentNames = $visitedFragmentNames ?: new ArrayObject();
        $_astAndDefs           = $astAndDefs ?: new ArrayObject();

        foreach ($selectionSet->selections as $selection) {
            switch ($selection->kind) {
                case NodeKind::FIELD:
                    /** @var FieldNode $selection */
                    $fieldName = $selection->name->value;
                    $fieldDef  = null;
                    if ($parentType && method_exists($parentType, 'getFields')) {
                        $tmp                  = $parentType->getFields();
                        $schemaMetaFieldDef   = Introspection::schemaMetaFieldDef();
                        $typeMetaFieldDef     = Introspection::typeMetaFieldDef();
                        $typeNameMetaFieldDef = Introspection::typeNameMetaFieldDef();

                        if ($fieldName === $schemaMetaFieldDef->name && $context->getSchema()->getQueryType() === $parentType) {
                            $fieldDef = $schemaMetaFieldDef;
                        } elseif ($fieldName === $typeMetaFieldDef->name && $context->getSchema()->getQueryType() === $parentType) {
                            $fieldDef = $typeMetaFieldDef;
                        } elseif ($fieldName === $typeNameMetaFieldDef->name) {
                            $fieldDef = $typeNameMetaFieldDef;
                        } elseif (isset($tmp[$fieldName])) {
                            $fieldDef = $tmp[$fieldName];
                        }
                    }
                    $responseName = $this->getFieldName($selection);
                    if (! isset($_astAndDefs[$responseName])) {
                        $_astAndDefs[$responseName] = new ArrayObject();
                    }
                    // create field context
                    $_astAndDefs[$responseName][] = [$selection, $fieldDef];
                    break;
                case NodeKind::INLINE_FRAGMENT:
                    /** @var InlineFragmentNode $selection */
                    $_astAndDefs = $this->collectFieldASTsAndDefs(
                        $context,
                        TypeInfo::typeFromAST($context->getSchema(), $selection->typeCondition),
                        $selection->selectionSet,
                        $_visitedFragmentNames,
                        $_astAndDefs
                    );
                    break;
                case NodeKind::FRAGMENT_SPREAD:
                    /** @var FragmentSpreadNode $selection */
                    $fragName = $selection->name->value;

                    if (empty($_visitedFragmentNames[$fragName])) {
                        $_visitedFragmentNames[$fragName] = true;
                        $fragment                         = $context->getFragment($fragName);

                        if ($fragment) {
                            $_astAndDefs = $this->collectFieldASTsAndDefs(
                                $context,
                                TypeInfo::typeFromAST($context->getSchema(), $fragment->typeCondition),
                                $fragment->selectionSet,
                                $_visitedFragmentNames,
                                $_astAndDefs
                            );
                        }
                    }
                    break;
            }
        }

        return $_astAndDefs;
    }
protected function collectFieldASTsAndDefs(
        ValidationContext $context,
        $parentType,
        SelectionSetNode $selectionSet,
        ?ArrayObject $visitedFragmentNames = null,
        ?ArrayObject $astAndDefs = null
    ) {
        $_visitedFragmentNames = $visitedFragmentNames ?: new ArrayObject();
        $_astAndDefs           = $astAndDefs ?: new ArrayObject();

        foreach ($selectionSet->selections as $selection) {
            switch ($selection->kind) {
                case NodeKind::FIELD:
                    
                    $fieldName = $selection->name->value;
                    $fieldDef  = null;
                    if ($parentType && method_exists($parentType, 'getFields')) {
                        $tmp                  = $parentType->getFields();
                        $schemaMetaFieldDef   = Introspection::schemaMetaFieldDef();
                        $typeMetaFieldDef     = Introspection::typeMetaFieldDef();
                        $typeNameMetaFieldDef = Introspection::typeNameMetaFieldDef();

                        if ($fieldName === $schemaMetaFieldDef->name && $context->getSchema()->getQueryType() === $parentType) {
                            $fieldDef = $schemaMetaFieldDef;
                        } elseif ($fieldName === $typeMetaFieldDef->name && $context->getSchema()->getQueryType() === $parentType) {
                            $fieldDef = $typeMetaFieldDef;
                        } elseif ($fieldName === $typeNameMetaFieldDef->name) {
                            $fieldDef = $typeNameMetaFieldDef;
                        } elseif (isset($tmp[$fieldName])) {
                            $fieldDef = $tmp[$fieldName];
                        }
                    }
                    $responseName = $this->getFieldName($selection);
                    if (! isset($_astAndDefs[$responseName])) {
                        $_astAndDefs[$responseName] = new ArrayObject();
                    }
                    
                    $_astAndDefs[$responseName][] = [$selection, $fieldDef];
                    break;
                case NodeKind::INLINE_FRAGMENT:
                    
                    $_astAndDefs = $this->collectFieldASTsAndDefs(
                        $context,
                        TypeInfo::typeFromAST($context->getSchema(), $selection->typeCondition),
                        $selection->selectionSet,
                        $_visitedFragmentNames,
                        $_astAndDefs
                    );
                    break;
                case NodeKind::FRAGMENT_SPREAD:
                    
                    $fragName = $selection->name->value;

                    if (empty($_visitedFragmentNames[$fragName])) {
                        $_visitedFragmentNames[$fragName] = true;
                        $fragment                         = $context->getFragment($fragName);

                        if ($fragment) {
                            $_astAndDefs = $this->collectFieldASTsAndDefs(
                                $context,
                                TypeInfo::typeFromAST($context->getSchema(), $fragment->typeCondition),
                                $fragment->selectionSet,
                                $_visitedFragmentNames,
                                $_astAndDefs
                            );
                        }
                    }
                    break;
            }
        }

        return $_astAndDefs;
    }
protected function collectFieldASTsAndDefs ( ValidationContext $ context , $ parentType , SelectionSetNode $ selectionSet , ? ArrayObject $ visitedFragmentNames = null , ? ArrayObject $ astAndDefs = null ) { $ _visitedFragmentNames = $ visitedFragmentNames ? : new ArrayObject ( ) ; $ _astAndDefs = $ astAndDefs ? : new ArrayObject ( ) ; foreach ( $ selectionSet -> selections as $ selection ) { switch ( $ selection -> kind ) { case NodeKind :: FIELD : /** @var FieldNode $selection */ $ fieldName = $ selection -> name -> value ; $ fieldDef = null ; if ( $ parentType && method_exists ( $ parentType , 'getFields' ) ) { $ tmp = $ parentType -> getFields ( ) ; $ schemaMetaFieldDef = Introspection :: schemaMetaFieldDef ( ) ; $ typeMetaFieldDef = Introspection :: typeMetaFieldDef ( ) ; $ typeNameMetaFieldDef = Introspection :: typeNameMetaFieldDef ( ) ; if ( $ fieldName === $ schemaMetaFieldDef -> name && $ context -> getSchema ( ) -> getQueryType ( ) === $ parentType ) { $ fieldDef = $ schemaMetaFieldDef ; } elseif ( $ fieldName === $ typeMetaFieldDef -> name && $ context -> getSchema ( ) -> getQueryType ( ) === $ parentType ) { $ fieldDef = $ typeMetaFieldDef ; } elseif ( $ fieldName === $ typeNameMetaFieldDef -> name ) { $ fieldDef = $ typeNameMetaFieldDef ; } elseif ( isset ( $ tmp [ $ fieldName ] ) ) { $ fieldDef = $ tmp [ $ fieldName ] ; } } $ responseName = $ this -> getFieldName ( $ selection ) ; if ( ! isset ( $ _astAndDefs [ $ responseName ] ) ) { $ _astAndDefs [ $ responseName ] = new ArrayObject ( ) ; } // create field context $ _astAndDefs [ $ responseName ] [ ] = [ $ selection , $ fieldDef ] ; break ; case NodeKind :: INLINE_FRAGMENT : /** @var InlineFragmentNode $selection */ $ _astAndDefs = $ this -> collectFieldASTsAndDefs ( $ context , TypeInfo :: typeFromAST ( $ context -> getSchema ( ) , $ selection -> typeCondition ) , $ selection -> selectionSet , $ _visitedFragmentNames , $ _astAndDefs ) ; break ; case NodeKind :: FRAGMENT_SPREAD : /** @var FragmentSpreadNode $selection */ $ fragName = $ selection -> name -> value ; if ( empty ( $ _visitedFragmentNames [ $ fragName ] ) ) { $ _visitedFragmentNames [ $ fragName ] = true ; $ fragment = $ context -> getFragment ( $ fragName ) ; if ( $ fragment ) { $ _astAndDefs = $ this -> collectFieldASTsAndDefs ( $ context , TypeInfo :: typeFromAST ( $ context -> getSchema ( ) , $ fragment -> typeCondition ) , $ fragment -> selectionSet , $ _visitedFragmentNames , $ _astAndDefs ) ; } } break ; } } return $ _astAndDefs ; }
Given a selectionSet, adds all of the fields in that selection to
the passed in map of fields, and returns it at the end.

Note: This is not the same as execution's collectFields because at static
time we do not know what object type will be used, so we unconditionally
spread in all fragments.

@see \GraphQL\Validator\Rules\OverlappingFieldsCanBeMerged

@param Type|null $parentType

@return ArrayObject
Given a selectionSet adds all of the fields in that selection to the passed in map of fields and returns it at the end .