Completed
Pull Request — master (#1)
by Arthur
02:21
created

DoctrineGuesser::guessFieldType()   C

Complexity

Conditions 20
Paths 36

Size

Total Lines 49
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 49
rs 5.0913
cc 20
eloc 36
nc 36
nop 1

How to fix   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
namespace Arthem\GraphQLMapper\Mapping\Guesser;
3
4
use Arthem\GraphQLMapper\Mapping\Context\ContainerContext;
5
use Arthem\GraphQLMapper\Mapping\Context\FieldContext;
6
use Arthem\GraphQLMapper\Mapping\Field;
7
use Arthem\GraphQLMapper\Mapping\Guesser\Guess\Guess;
8
use Arthem\GraphQLMapper\Mapping\Guesser\Guess\TypeGuess;
9
use Arthem\GraphQLMapper\Mapping\SchemaContainer;
10
use Arthem\GraphQLMapper\Mapping\Type;
11
use Doctrine\Common\Persistence\Mapping\ClassMetadataFactory;
12
use Doctrine\Common\Persistence\Mapping\MappingException;
13
use Doctrine\Common\Persistence\ObjectManager;
14
use Doctrine\DBAL\Types\Type as DoctrineType;
15
use Doctrine\ORM\Mapping\ClassMetadataInfo;
16
17
class DoctrineGuesser implements TypeResolveGuesserInterface, FieldResolveGuesserInterface, FieldTypeGuesserInterface
18
{
19
    /**
20
     * @var ClassMetadataFactory
21
     */
22
    private $metadataFactory;
23
24
    /**
25
     * @param ObjectManager $objectManager
26
     */
27
    public function __construct(ObjectManager $objectManager)
28
    {
29
        $this->metadataFactory = $objectManager->getMetadataFactory();
30
    }
31
32
    /**
33
     * {@inheritdoc}
34
     */
35
    public function guessFieldType(FieldContext $fieldContext)
36
    {
37
        if (!$this->isFieldContainerSupported($fieldContext)) {
38
            return;
39
        }
40
41
        /** @var Type $fieldContainer */
42
        $fieldContainer = $fieldContext->getContainer();
43
        $model          = $fieldContainer->getModel();
44
45
        if (null === $metadata = $this->getMetadata($model)) {
46
            return;
47
        }
48
49
        $field = $fieldContext->getField();
50
51
        $property = $field->getProperty() ?: $field->getName();
52
53
        if ($metadata->hasAssociation($property)) {
54
            return $this->guessAssociation($metadata, $field, $fieldContext->getSchema());
55
        }
56
57
        switch ($metadata->getTypeOfField($property)) {
58
            case DoctrineType::TARRAY:
59
            case DoctrineType::JSON_ARRAY:
60
                return $this->wrapRequired($metadata, $property, '[String]', Guess::LOW_CONFIDENCE);
61
            case DoctrineType::BOOLEAN:
62
                return new TypeGuess('Boolean', Guess::HIGH_CONFIDENCE);
63
            case DoctrineType::DATETIME:
64
            case DoctrineType::DATETIMETZ:
65
            case 'vardatetime':
66
            case DoctrineType::DATE:
67
            case DoctrineType::TIME:
68
                return $this->wrapRequired($metadata, $property, 'String', Guess::MEDIUM_CONFIDENCE);
69
            case DoctrineType::DECIMAL:
70
            case DoctrineType::FLOAT:
71
                return $this->wrapRequired($metadata, $property, 'Number', Guess::MEDIUM_CONFIDENCE);
72
            case DoctrineType::INTEGER:
73
            case DoctrineType::BIGINT:
74
            case DoctrineType::SMALLINT:
75
                return $this->wrapRequired($metadata, $property, 'Int', Guess::MEDIUM_CONFIDENCE);
76
            case DoctrineType::STRING:
77
                return $this->wrapRequired($metadata, $property, 'String', Guess::MEDIUM_CONFIDENCE);
78
            case DoctrineType::TEXT:
79
                return $this->wrapRequired($metadata, $property, 'String', Guess::MEDIUM_CONFIDENCE);
80
            default:
81
                return $this->wrapRequired($metadata, $property, 'String', Guess::LOW_CONFIDENCE);
82
        }
83
    }
84
85
    /**
86
     * {@inheritdoc}
87
     */
88 View Code Duplication
    public function guessFieldResolveConfig(FieldContext $fieldContext)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
89
    {
90
        if (!$this->isFieldContainerSupported($fieldContext)) {
91
            return;
92
        }
93
94
        /** @var Type $type */
95
        $type = $fieldContext->getContainer();
96
97
        return new ResolveConfigGuess([
98
            'handler' => 'doctrine',
99
            'entity'  => $type->getModel(),
100
        ]);
101
    }
102
103
    /**
104
     * {@inheritdoc}
105
     */
106 View Code Duplication
    public function guessTypeResolveConfig(ContainerContext $containerContext)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
107
    {
108
        if (!$this->isFieldContainerSupported($containerContext)) {
109
            return;
110
        }
111
112
        /** @var Type $type */
113
        $type = $containerContext->getContainer();
114
115
        return new ResolveConfigGuess([
116
            'handler' => 'doctrine',
117
            'entity'  => $type->getModel(),
118
        ]);
119
    }
120
121
    /**
122
     * @param ClassMetadataInfo $metadata
123
     * @param string            $property
124
     * @param string            $type
125
     * @param int               $confidence
126
     * @return TypeGuess
127
     */
128
    private function wrapRequired(ClassMetadataInfo $metadata, $property, $type, $confidence)
129
    {
130
        if (!$metadata->isNullable($property)) {
131
            $type .= '!';
132
        }
133
134
        return new TypeGuess($type, $confidence);
135
    }
136
137
    /**
138
     * @param ClassMetadataInfo $metadata
139
     * @param Field             $field
140
     * @param SchemaContainer   $schemaContainer
141
     * @return TypeGuess
142
     * @throws MappingException
143
     */
144
    private function guessAssociation(ClassMetadataInfo $metadata, Field $field, SchemaContainer $schemaContainer)
145
    {
146
        $property = $field->getProperty() ?: $field->getName();
147
        $multiple = $metadata->isCollectionValuedAssociation($property);
148
        $mapping  = $metadata->getAssociationMapping($property);
149
150
        foreach ($schemaContainer->getTypes() as $type) {
151
            $containerContext = new ContainerContext($type, $schemaContainer);
152
153
            if (!$this->isFieldContainerSupported($containerContext)) {
154
                continue;
155
            }
156
157
            if ($type->getModel() === $mapping['targetEntity']) {
158
                $typeName = $type->getName();
159
                if ($multiple) {
160
                    $typeName = sprintf('[%s]', $typeName);
161
                }
162
163
                return new TypeGuess($typeName, Guess::HIGH_CONFIDENCE);
164
            }
165
        }
166
    }
167
168
    /**
169
     * @param ContainerContext $containerContext
170
     * @return bool
171
     */
172
    private function isFieldContainerSupported(ContainerContext $containerContext)
173
    {
174
        $fieldContainer = $containerContext->getContainer();
175
        if (!$fieldContainer instanceof Type) {
176
            return false;
177
        }
178
179
        return !empty($fieldContainer->getModel());
180
    }
181
182
    /**
183
     * @param string $class
184
     * @return ClassMetadataInfo
185
     */
186
    protected function getMetadata($class)
187
    {
188
        try {
189
            return $this->metadataFactory->getMetadataFor($class);
190
        } catch (MappingException $e) {
0 ignored issues
show
Bug introduced by
The class Doctrine\Common\Persiste...apping\MappingException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
191
            // not an entity or mapped super class
192
        }
193
    }
194
}
195