Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

Passed
Pull Request — master (#801)
by Vincent
25:11
created

DocBlockTypeGuesser::getParser()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 2
eloc 3
c 1
b 1
f 0
nc 2
nop 0
dl 0
loc 7
rs 10
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\Type;
11
use phpDocumentor\Reflection\Types\AbstractList;
12
use phpDocumentor\Reflection\Types\Compound;
13
use phpDocumentor\Reflection\Types\ContextFactory;
14
use phpDocumentor\Reflection\Types\Mixed_;
15
use phpDocumentor\Reflection\Types\Null_;
16
use phpDocumentor\Reflection\Types\Nullable;
17
use phpDocumentor\Reflection\Types\Object_;
18
use ReflectionClass;
19
use ReflectionMethod;
20
use ReflectionProperty;
21
use Reflector;
22
use function sprintf;
23
24
class DocBlockTypeGuesser extends PhpTypeGuesser
25
{
26
    protected ?DocBlockFactory $factory;
27
28
    public function getName(): string
29
    {
30
        return 'Dock block';
31
    }
32
33
    public function supports(Reflector $reflector): bool
34
    {
35
        return $reflector instanceof ReflectionProperty || $reflector instanceof ReflectionMethod;
36
    }
37
38
    /**
39
     * @param ReflectionProperty|ReflectionMethod $reflector
40
     */
41
    public function guessType(ReflectionClass $reflectionClass, Reflector $reflector, array $filterGraphQLTypes = []): ?string
42
    {
43
        $contextFactory = new ContextFactory();
44
        $context = $contextFactory->createFromReflector($reflectionClass);
45
        try {
46
            $docBlock = $this->getParser()->create($reflector->getDocComment(), $context);
0 ignored issues
show
Bug introduced by
The method getDocComment() does not exist on Reflector. It seems like you code against a sub-type of said class. However, the method does not exist in ReflectionExtension or ReflectionZendExtension or ReflectionParameter. Are you sure you never get one of those? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

46
            $docBlock = $this->getParser()->create($reflector->/** @scrutinizer ignore-call */ getDocComment(), $context);
Loading history...
47
        } catch (Exception $e) {
48
            throw new TypeGuessingException(sprintf('Doc Block parsing failed with error: %s', $e->getMessage()));
49
        }
50
        $tagName = $reflector instanceof ReflectionProperty ? 'var' : 'return';
51
        $tags = $docBlock->getTagsByName($tagName);
52
        $tag = $tags[0] ?? null;
53
        if (!$tag || !$tag instanceof TagWithType) {
54
            throw new TypeGuessingException(sprintf('No @%s tag found in doc block or tag has no type', $tagName));
55
        }
56
        $type = $tag->getType();
57
        $isNullable = false;
58
        $isList = false;
59
        $isListNullable = false;
60
        $exceptionPrefix = sprintf('Tag @%s found', $tagName);
61
62
        if ($type instanceof Compound) {
63
            $type = $this->resolveCompound($type);
64
            if (!$type) {
65
                throw new TypeGuessingException(sprintf('%s, but composite types are only allowed with null. Ex: string|null.', $exceptionPrefix));
66
            }
67
            $isNullable = true;
68
        } elseif ($type instanceof Nullable) {
69
            $isNullable = true;
70
            $type = $type->getActualType();
71
        }
72
73
        if ($type instanceof AbstractList) {
74
            $isList = true;
75
            $isListNullable = $isNullable;
76
            $isNullable = false;
77
            $type = $type->getValueType();
78
            if ($type instanceof Compound) {
79
                $type = $this->resolveCompound($type);
80
                if (!$type) {
81
                    throw new TypeGuessingException(sprintf('%s, but composite types in array or iterable are only allowed with null. Ex: string|null.', $exceptionPrefix));
82
                }
83
                $isNullable = true;
84
            } elseif ($type instanceof Mixed_) {
85
                throw new TypeGuessingException(sprintf('%s, but the array values cannot be mixed type', $exceptionPrefix));
86
            }
87
        }
88
89
        if ($type instanceof Object_) {
90
            $className = $type->getFqsen();
91
            if (!$className) {
92
                throw new TypeGuessingException(sprintf('%s, but type "object" is too generic.', $exceptionPrefix, $className));
93
            }
94
            // Remove first '\' from returned class name
95
            $className = substr((string) $className, 1);
96
            $gqlType = $this->map->resolveType((string) $className, $filterGraphQLTypes);
97
            if (!$gqlType) {
98
                throw new TypeGuessingException(sprintf('%s, but target object "%s" is not a GraphQL Type class.', $exceptionPrefix, $className));
99
            }
100
        } else {
101
            $gqlType = $this->resolveTypeFromPhpType((string) $type);
102
            if (!$gqlType) {
103
                throw new TypeGuessingException(sprintf('%s, but unable to resolve type "%s" to a GraphQL scalar.', $exceptionPrefix, (string) $type));
104
            }
105
        }
106
107
        return $isList ? sprintf('[%s%s]%s', $gqlType, $isNullable ? '' : '!', $isListNullable ? '' : '!') : sprintf('%s%s', $gqlType, $isNullable ? '' : '!');
108
    }
109
110
    protected function resolveCompound(Compound $compound): ?Type
111
    {
112
        $typeNull = new Null_();
113
        if ($compound->getIterator()->count() > 2 || !$compound->contains($typeNull)) {
114
            return null;
115
        }
116
        $type = current(array_filter(iterator_to_array($compound->getIterator(), false), fn (Type $type) => (string) $type !== (string) $typeNull));
117
118
        return $type;
119
    }
120
121
    private function getParser(): DocBlockFactory
122
    {
123
        if (!isset($this->factory)) {
124
            $this->factory = DocBlockFactory::createInstance();
125
        }
126
127
        return $this->factory;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->factory could return the type null which is incompatible with the type-hinted return phpDocumentor\Reflection\DocBlockFactory. Consider adding an additional type-check to rule them out.
Loading history...
128
    }
129
}
130