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 (#867)
by Vincent
23:12
created

DoctrineTypeGuesser::guessType()   C

Complexity

Conditions 13
Paths 11

Size

Total Lines 57
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 27
CRAP Score 13

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 13
eloc 35
c 1
b 0
f 0
nc 11
nop 3
dl 0
loc 57
ccs 27
cts 27
cp 1
crap 13
rs 6.6166

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Overblog\GraphQLBundle\Config\Parser\MetadataParser\TypeGuesser;
6
7
use Doctrine\ORM\Mapping\Annotation as MappingAnnotation;
8
use Doctrine\ORM\Mapping\Column;
9
use Doctrine\ORM\Mapping\JoinColumn;
10
use Doctrine\ORM\Mapping\ManyToMany;
11
use Doctrine\ORM\Mapping\ManyToOne;
12
use Doctrine\ORM\Mapping\OneToMany;
13
use Doctrine\ORM\Mapping\OneToOne;
14
use Overblog\GraphQLBundle\Config\Parser\AnnotationParser;
15
use Overblog\GraphQLBundle\Config\Parser\MetadataParser\ClassesTypesMap;
16
use ReflectionClass;
17
use ReflectionMethod;
18
use ReflectionProperty;
19
use Reflector;
20
21
class DoctrineTypeGuesser extends TypeGuesser
22
{
23
    protected array $doctrineMapping = [];
24
25
    public function __construct(ClassesTypesMap $map, array $doctrineMapping = [])
26
    {
27
        parent::__construct($map);
28 93
        $this->doctrineMapping = $doctrineMapping;
29
    }
30 93
31 93
    public function getName(): string
32 93
    {
33
        return 'Doctrine annotations ';
34 4
    }
35
36 4
    public function supports(Reflector $reflector): bool
37
    {
38
        return $reflector instanceof ReflectionProperty;
39 51
    }
40
41 51
    /**
42
     * @param ReflectionProperty $reflector
43
     */
44
    public function guessType(ReflectionClass $reflectionClass, Reflector $reflector, array $filterGraphQLTypes = []): ?string
45
    {
46
        if (!class_exists(Column::class)) {
47 52
            throw new TypeGuessingException(sprintf('You must install doctrine/orm package to use this type guesser.'));
48
        }
49 52
50 1
        if (!$reflector instanceof ReflectionProperty) {
51
            throw new TypeGuessingException('Doctrine type guesser only apply to properties.');
52
        }
53 52
54
        /** @var Column|null $columnAnnotation */
55 52
        $columnAnnotation = $this->getAnnotation($reflector, Column::class);
56 51
57 51
        if (null !== $columnAnnotation) {
58 51
            $type = $this->resolveTypeFromDoctrineType($columnAnnotation->type ?: 'string');
59 51
            $nullable = $columnAnnotation->nullable;
60
            if ($type) {
61 2
                return $nullable ? $type : sprintf('%s!', $type);
62
            } else {
63
                throw new TypeGuessingException(sprintf('Unable to auto-guess GraphQL type from Doctrine type "%s"', $columnAnnotation->type));
64
            }
65 52
        }
66
67
        $associationAnnotations = [
68
            OneToMany::class => true,
69
            OneToOne::class => false,
70
            ManyToMany::class => true,
71
            ManyToOne::class => false,
72 52
        ];
73
74 52
        foreach ($associationAnnotations as $associationClass => $isMultiple) {
75 52
            /** @var OneToMany|OneToOne|ManyToMany|ManyToOne|null $associationAnnotation */
76 51
            $associationAnnotation = $this->getAnnotation($reflector, $associationClass);
77 51
            if (null !== $associationAnnotation) {
78
                $target = $this->fullyQualifiedClassName($associationAnnotation->targetEntity, $reflectionClass->getNamespaceName());
0 ignored issues
show
Bug introduced by
It seems like $associationAnnotation->targetEntity can also be of type null; however, parameter $className of Overblog\GraphQLBundle\C...llyQualifiedClassName() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

78
                $target = $this->fullyQualifiedClassName(/** @scrutinizer ignore-type */ $associationAnnotation->targetEntity, $reflectionClass->getNamespaceName());
Loading history...
79 51
                $type = $this->map->resolveType($target, ['type']);
80 51
81 51
                if ($type) {
82 51
                    $isMultiple = $associationAnnotations[get_class($associationAnnotation)];
83
                    if ($isMultiple) {
84 51
                        return sprintf('[%s]!', $type);
85
                    } else {
86 51
                        $isNullable = false;
87 51
                        /** @var JoinColumn|null $joinColumn */
88 51
                        $joinColumn = $this->getAnnotation($reflector, JoinColumn::class);
89
                        if (null !== $joinColumn) {
90
                            $isNullable = $joinColumn->nullable;
91 51
                        }
92
93
                        return sprintf('%s%s', $type, $isNullable ? '' : '!');
94 2
                    }
95
                } else {
96
                    throw new TypeGuessingException(sprintf('Unable to auto-guess GraphQL type from Doctrine target class "%s" (check if the target class is a GraphQL type itself (with a @Metadata\Type metadata).', $target));
97
                }
98 1
            }
99
        }
100
        throw new TypeGuessingException(sprintf('No Doctrine ORM annotation found.'));
101 52
    }
102
103 52
    private function getAnnotation(Reflector $reflector, string $annotationClass): ?MappingAnnotation
104 52
    {
105
        $reader = AnnotationParser::getAnnotationReader();
106 52
        $annotations = [];
107 52
        switch (true) {
108 52
            case $reflector instanceof ReflectionClass: $annotations = $reader->getClassAnnotations($reflector); break;
109
            case $reflector instanceof ReflectionMethod: $annotations = $reader->getMethodAnnotations($reflector); break;
110 52
            case $reflector instanceof ReflectionProperty: $annotations = $reader->getPropertyAnnotations($reflector); break;
111 51
        }
112
        foreach ($annotations as $annotation) {
113 51
            if ($annotation instanceof $annotationClass) {
114
                /** @var MappingAnnotation $annotation */
115
                return $annotation;
116
            }
117 52
        }
118
119
        return null;
120 52
    }
121
122 52
    /**
123 52
     * Resolve a FQN from classname and namespace.
124 52
     *
125
     * @internal
126
     */
127
    public function fullyQualifiedClassName(string $className, string $namespace): string
128 52
    {
129 52
        if (false === strpos($className, '\\') && $namespace) {
130
            return $namespace.'\\'.$className;
131
        }
132 52
133
        return $className;
134
    }
135
136
    /**
137
     * Resolve a GraphQLType from a doctrine type.
138
     */
139
    private function resolveTypeFromDoctrineType(string $doctrineType): ?string
140 51
    {
141
        if (isset($this->doctrineMapping[$doctrineType])) {
142 51
            return $this->doctrineMapping[$doctrineType];
143 51
        }
144
145
        switch ($doctrineType) {
146
            case 'integer':
147
            case 'smallint':
148
            case 'bigint':
149
                return 'Int';
150
            case 'string':
151
            case 'text':
152 51
                return 'String';
153
            case 'bool':
154 51
            case 'boolean':
155 51
                return 'Boolean';
156
            case 'float':
157
            case 'decimal':
158
                return 'Float';
159 51
            default:
160 51
                return null;
161 51
        }
162 51
    }
163
}
164