• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

overblog / GraphQLBundle / 21698909275

29 Jan 2026 07:39AM UTC coverage: 98.546%. Remained the same
21698909275

push

github

web-flow
Test on PHP 8.5 (#1237)

* Test on PHP 8.5

* fix remove dummy attribute

4541 of 4608 relevant lines covered (98.55%)

76.57 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.16
/src/Config/Parser/MetadataParser/TypeGuesser/DocBlockTypeGuesser.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Overblog\GraphQLBundle\Config\Parser\MetadataParser\TypeGuesser;
6

7
use Exception;
8
use phpDocumentor\Reflection\DocBlock\Tags\TagWithType;
9
use phpDocumentor\Reflection\DocBlockFactory;
10
use phpDocumentor\Reflection\DocBlockFactoryInterface;
11
use phpDocumentor\Reflection\Type;
12
use phpDocumentor\Reflection\Types\AbstractList;
13
use phpDocumentor\Reflection\Types\Compound;
14
use phpDocumentor\Reflection\Types\ContextFactory;
15
use phpDocumentor\Reflection\Types\Mixed_;
16
use phpDocumentor\Reflection\Types\Null_;
17
use phpDocumentor\Reflection\Types\Nullable;
18
use phpDocumentor\Reflection\Types\Object_;
19
use ReflectionClass;
20
use ReflectionMethod;
21
use ReflectionProperty;
22
use Reflector;
23

24
use function sprintf;
25

26
final class DocBlockTypeGuesser extends PhpTypeGuesser
27
{
28
    protected ?DocBlockFactoryInterface $factory;
29

30
    public function getName(): string
31
    {
32
        return 'Dock block';
101✔
33
    }
34

35
    public function supports(Reflector $reflector): bool
36
    {
37
        return $reflector instanceof ReflectionProperty || $reflector instanceof ReflectionMethod;
101✔
38
    }
39

40
    /**
41
     * @param ReflectionProperty|ReflectionMethod $reflector
42
     */
43
    public function guessType(ReflectionClass $reflectionClass, Reflector $reflector, array $filterGraphQLTypes = []): ?string
44
    {
45
        $contextFactory = new ContextFactory();
195✔
46
        $context = $contextFactory->createFromReflector($reflectionClass);
195✔
47
        $docBlockComment = $reflector->getDocComment();
195✔
48
        if (!$docBlockComment) {
195✔
49
            throw new TypeGuessingException(sprintf('Doc Block not found'));
5✔
50
        }
51

52
        try {
53
            $docBlock = $this->getParser()->create($docBlockComment, $context);
190✔
54
        } catch (Exception $e) {
×
55
            throw new TypeGuessingException(sprintf('Doc Block parsing failed with error: %s', $e->getMessage()));
×
56
        }
57
        $tagName = $reflector instanceof ReflectionProperty ? 'var' : 'return';
190✔
58
        $tags = $docBlock->getTagsByName($tagName);
190✔
59
        $tag = $tags[0] ?? null;
190✔
60
        if (!$tag || !$tag instanceof TagWithType) {
190✔
61
            throw new TypeGuessingException(sprintf('No @%s tag found in doc block or tag has no type', $tagName));
106✔
62
        }
63
        $type = $tag->getType();
182✔
64
        $isNullable = false;
182✔
65
        $isList = false;
182✔
66
        $isListNullable = false;
182✔
67
        $exceptionPrefix = sprintf('Tag @%s found', $tagName);
182✔
68

69
        if ($type instanceof Compound) {
182✔
70
            $type = $this->resolveCompound($type);
18✔
71
            if (!$type) {
18✔
72
                throw new TypeGuessingException(sprintf('%s, but composite types are only allowed with null. Ex: string|null.', $exceptionPrefix));
4✔
73
            }
74
            $isNullable = true;
14✔
75
        } elseif ($type instanceof Nullable) {
164✔
76
            $isNullable = true;
4✔
77
            $type = $type->getActualType();
4✔
78
        }
79

80
        if ($type instanceof AbstractList) {
178✔
81
            $isList = true;
132✔
82
            $isListNullable = $isNullable;
132✔
83
            $isNullable = false;
132✔
84
            $type = $type->getValueType();
132✔
85
            if ($type instanceof Compound) {
132✔
86
                $type = $this->resolveCompound($type);
8✔
87
                if (!$type) {
8✔
88
                    throw new TypeGuessingException(sprintf('%s, but composite types in array or iterable are only allowed with null. Ex: string|null.', $exceptionPrefix));
4✔
89
                }
90
                $isNullable = true;
4✔
91
            } elseif ($type instanceof Mixed_) {
124✔
92
                throw new TypeGuessingException(sprintf('%s, but the array values cannot be mixed type', $exceptionPrefix));
8✔
93
            }
94
        }
95

96
        if ($type instanceof Object_) {
166✔
97
            $className = $type->getFqsen();
12✔
98
            if (!$className) {
12✔
99
                throw new TypeGuessingException(sprintf('%s, but type "object" is too generic.', $exceptionPrefix));
4✔
100
            }
101
            // Remove first '\' from returned class name
102
            $className = substr((string) $className, 1);
8✔
103
            $gqlType = $this->map->resolveType((string) $className, $filterGraphQLTypes);
8✔
104
            if (!$gqlType) {
8✔
105
                throw new TypeGuessingException(sprintf('%s, but target object "%s" is not a GraphQL Type class.', $exceptionPrefix, $className));
6✔
106
            }
107
        } else {
108
            $gqlType = $this->resolveTypeFromPhpType((string) $type);
154✔
109
            if (!$gqlType) {
154✔
110
                throw new TypeGuessingException(sprintf('%s, but unable to resolve type "%s" to a GraphQL scalar.', $exceptionPrefix, (string) $type));
2✔
111
            }
112
        }
113

114
        return $isList ? sprintf('[%s%s]%s', $gqlType, $isNullable ? '' : '!', $isListNullable ? '' : '!') : sprintf('%s%s', $gqlType, $isNullable ? '' : '!');
158✔
115
    }
116

117
    protected function resolveCompound(Compound $compound): ?Type
118
    {
119
        $typeNull = new Null_();
22✔
120
        if (2 !== $compound->getIterator()->count() || !$compound->contains($typeNull)) {
22✔
121
            return null;
8✔
122
        }
123
        foreach ($compound as $type) {
14✔
124
            if (!$type instanceof Null_) {
14✔
125
                return $type;
14✔
126
            }
127
        }
128

129
        return null;
×
130
    }
131

132
    private function getParser(): DocBlockFactoryInterface
133
    {
134
        if (!isset($this->factory)) {
190✔
135
            $this->factory = DocBlockFactory::createInstance();
190✔
136
        }
137

138
        return $this->factory;
190✔
139
    }
140
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc