Completed
Push — master ( 4bb4eb...402013 )
by Arthur
03:35
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\Guess;
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\SchemaContainer;
8
use Arthem\GraphQLMapper\Mapping\Type;
9
use Doctrine\Common\Persistence\Mapping\ClassMetadataFactory;
10
use Doctrine\Common\Persistence\Mapping\MappingException;
11
use Doctrine\Common\Persistence\ObjectManager;
12
use Doctrine\DBAL\Types\Type as DoctrineType;
13
use Doctrine\ORM\Mapping\ClassMetadataInfo;
14
15
class DoctrineGuesser implements TypeGuesserInterface, FieldGuesserInterface
16
{
17
    /**
18
     * @var ClassMetadataFactory
19
     */
20
    private $metadataFactory;
21
22
    /**
23
     * @param ClassMetadataFactory $metadataFactory
0 ignored issues
show
Bug introduced by
There is no parameter named $metadataFactory. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
24
     */
25
    public function __construct(ObjectManager $objectManager)
26
    {
27
        $this->metadataFactory = $objectManager->getMetadataFactory();
28
    }
29
30
    /**
31
     * {@inheritdoc}
32
     */
33
    public function guessFieldType(FieldContext $fieldContext)
34
    {
35
        if (!$this->isFieldContainerSupported($fieldContext)) {
36
            return;
37
        }
38
39
        /** @var Type $fieldContainer */
40
        $fieldContainer = $fieldContext->getContainer();
41
        $model          = $fieldContainer->getModel();
42
43
        if (null === $metadata = $this->getMetadata($model)) {
44
            return;
45
        }
46
47
        $field = $fieldContext->getField();
48
49
        $property = $field->getProperty() ?: $field->getName();
50
51
        if ($metadata->hasAssociation($property)) {
52
            return $this->guessAssociation($metadata, $field, $fieldContext->getSchema());
53
        }
54
55
        switch ($metadata->getTypeOfField($property)) {
56
            case DoctrineType::TARRAY:
57
            case DoctrineType::JSON_ARRAY:
58
                return $this->wrapRequired($metadata, $property, '[String]', Guess::LOW_CONFIDENCE);
59
            case DoctrineType::BOOLEAN:
60
                return new TypeGuess('Boolean', Guess::HIGH_CONFIDENCE);
61
            case DoctrineType::DATETIME:
62
            case DoctrineType::DATETIMETZ:
63
            case 'vardatetime':
64
            case DoctrineType::DATE:
65
            case DoctrineType::TIME:
66
                return $this->wrapRequired($metadata, $property, 'String', Guess::MEDIUM_CONFIDENCE);
67
            case DoctrineType::DECIMAL:
68
            case DoctrineType::FLOAT:
69
                return $this->wrapRequired($metadata, $property, 'Number', Guess::MEDIUM_CONFIDENCE);
70
            case DoctrineType::INTEGER:
71
            case DoctrineType::BIGINT:
72
            case DoctrineType::SMALLINT:
73
                return $this->wrapRequired($metadata, $property, 'Int', Guess::MEDIUM_CONFIDENCE);
74
            case DoctrineType::STRING:
75
                return $this->wrapRequired($metadata, $property, 'String', Guess::MEDIUM_CONFIDENCE);
76
            case DoctrineType::TEXT:
77
                return $this->wrapRequired($metadata, $property, 'String', Guess::MEDIUM_CONFIDENCE);
78
            default:
79
                return $this->wrapRequired($metadata, $property, 'String', Guess::LOW_CONFIDENCE);
80
        }
81
    }
82
83
    /**
84
     * {@inheritdoc}
85
     */
86 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...
87
    {
88
        if (!$this->isFieldContainerSupported($fieldContext)) {
89
            return;
90
        }
91
92
        /** @var Type $type */
93
        $type = $fieldContext->getContainer();
94
95
        return new ResolveConfigGuess([
96
            'handler' => 'doctrine',
97
            'entity'  => $type->getModel(),
98
        ]);
99
    }
100
101
    /**
102
     * {@inheritdoc}
103
     */
104 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...
105
    {
106
        if (!$this->isFieldContainerSupported($containerContext)) {
107
            return;
108
        }
109
110
        /** @var Type $type */
111
        $type = $containerContext->getContainer();
112
113
        return new ResolveConfigGuess([
114
            'handler' => 'doctrine',
115
            'entity'  => $type->getModel(),
116
        ]);
117
    }
118
119
    /**
120
     * @param ClassMetadataInfo $metadata
121
     * @param string            $property
122
     * @param string            $type
123
     * @param int               $confidence
124
     * @return TypeGuess
125
     */
126
    private function wrapRequired(ClassMetadataInfo $metadata, $property, $type, $confidence)
127
    {
128
        if (!$metadata->isNullable($property)) {
129
            $type .= '!';
130
        }
131
132
        return new TypeGuess($type, $confidence);
133
    }
134
135
    /**
136
     * @param ClassMetadataInfo $metadata
137
     * @param Field             $field
138
     * @param SchemaContainer   $schemaContainer
139
     * @return TypeGuess
140
     * @throws MappingException
141
     */
142
    private function guessAssociation(ClassMetadataInfo $metadata, Field $field, SchemaContainer $schemaContainer)
143
    {
144
        $property = $field->getProperty() ?: $field->getName();
145
        $multiple = $metadata->isCollectionValuedAssociation($property);
146
        $mapping  = $metadata->getAssociationMapping($property);
147
148
        foreach ($schemaContainer->getTypes() as $type) {
149
            $containerContext = new ContainerContext($type, $schemaContainer);
150
151
            if (!$this->isFieldContainerSupported($containerContext)) {
152
                continue;
153
            }
154
155
            if ($type->getModel() === $mapping['targetEntity']) {
156
                $typeName = $type->getName();
157
                if ($multiple) {
158
                    $typeName = sprintf('[%s]', $typeName);
159
                }
160
161
                return new TypeGuess($typeName, Guess::HIGH_CONFIDENCE);
162
            }
163
        }
164
    }
165
166
    /**
167
     * @param ContainerContext $containerContext
168
     * @return bool
169
     */
170
    private function isFieldContainerSupported(ContainerContext $containerContext)
171
    {
172
        $fieldContainer = $containerContext->getContainer();
173
        if (!$fieldContainer instanceof Type) {
174
            return false;
175
        }
176
177
        return !empty($fieldContainer->getModel());
178
    }
179
180
    /**
181
     * @param string $class
182
     * @return ClassMetadataInfo
183
     */
184
    protected function getMetadata($class)
185
    {
186
        try {
187
            return $this->metadataFactory->getMetadataFor($class);
188
        } 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...
189
            // not an entity or mapped super class
190
        }
191
    }
192
}
193